package com.liquidnet.service.kylin.service.impl;

import com.alibaba.fastjson.JSON;
import com.liquidnet.commons.lang.util.*;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.kylin.constant.KylinRedisConst;
import com.liquidnet.service.kylin.constant.KylinTableStatusConst;
import com.liquidnet.service.kylin.dto.vo.admin.OrderRefundAddress;
import com.liquidnet.service.kylin.dto.vo.admin.OrderRefundPoundage;
import com.liquidnet.service.kylin.dto.vo.admin.OrderRefundPoundageAll;
import com.liquidnet.service.kylin.dto.vo.express.KylinOrderExpressVo;
import com.liquidnet.service.kylin.dto.vo.middle.KylinTicketTimesVo;
import com.liquidnet.service.kylin.dto.vo.middle.KylinTicketVo;
import com.liquidnet.service.kylin.dto.vo.mongo.KylinOrderRefundEntitiesVo;
import com.liquidnet.service.kylin.dto.vo.mongo.KylinOrderTicketEntitiesVo;
import com.liquidnet.service.kylin.dto.vo.mongo.KylinOrderTicketVo;
import com.liquidnet.service.kylin.dto.vo.mongo.KylinPerformanceVo;
import com.liquidnet.service.kylin.dto.vo.returns.*;
import com.liquidnet.service.kylin.entity.*;
import com.liquidnet.service.kylin.utils.*;
import com.mongodb.BasicDBObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.bson.Document;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * <p>
 * 订单用户申请退款 服务实现类
 * </p>
 *
 * @author jiangxiulong
 * @since 2021-09-16
 */
@Service
@Slf4j
public class KylinOrderTicketsRefundServiceImpl {

    @Autowired
    private DataUtils dataUtils;
    @Autowired
    private OrderUtils orderUtils;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private QueueUtils queueUtils;
    @Autowired
    private KylinRefundsStatusServiceImpl refundsStatusService;

    @Value("${liquidnet.express.shunfeng.custid}")
    private String custid;
    @Value("${liquidnet.express.shunfeng.expressType}")
    private Integer expressType;
    @Value("${liquidnet.express.shunfeng.depositumInfo}")
    private String depositumInfo;
    @Value("${liquidnet.client.admin.platformUrl}")
    private String platformUrl;
    @Autowired
    private ShunfengSignUtils shunfengSignUtils;

    public ResponseDto<KylinOrderTicketPreVo> toOrderRefundDetails(String orderId) {
        try {
            // 订单 演出 订单退款数据
            KylinOrderTicketPreVo vo = KylinOrderTicketPreVo.getNew();
            String uid = CurrentUtil.getCurrentUid();
            KylinOrderTicketVo orderTicketVo = dataUtils.getOrderTicketVo(orderId);
            KylinPerformanceVo performanceVo = dataUtils.getPerformanceVo(orderTicketVo.getPerformanceId());
            List<KylinOrderRefundsVo> kylinOrderRefundsVoBaseList = dataUtils.getOrderRefundVoByOrderId(orderTicketVo.getOrderTicketsId());
            // 判断是否购买人
            if (!SuperAccountUtils.isSuperAccount(uid, orderTicketVo.getUserId())) {
                return ResponseDto.failure(ErrorMapping.get("20003"));
            }
//            if (uid.equals("809406") || uid.equals("773650")) {
//            } else {
//                if (!orderTicketVo.getUserId().equals(uid)) {
//                    return ResponseDto.failure(ErrorMapping.get("20003"));
//                }
//            }
            // 入场人 数据脱敏/退款
            List<KylinOrderTicketEntitiesVo> kylinOrderTicketEntitiesVoList = orderTicketVo.getEntitiesVoList();
            List<KylinOrderTicketEntitiesPreRefundVo> kylinOrderTicketEntitiesPreRefundVos = ObjectUtil.getKylinOrderTicketEntitiesPreRefundVoArrayList();
            for (KylinOrderTicketEntitiesVo item : kylinOrderTicketEntitiesVoList) {
                KylinOrderTicketEntitiesPreRefundVo refundVo = KylinOrderTicketEntitiesPreRefundVo.getNew();
                if (item.getEnterIdCode().length() == 18) {
                    item.setEnterIdCode(item.getEnterIdCode().substring(0, 3) + "*************" + item.getEnterIdCode().substring(16));
                }
//                if (item.getEnterMobile().length() == 11) {
//                    item.setEnterMobile(item.getEnterMobile().substring(0, 3) + "****" + item.getEnterMobile().substring(7));
//                }
                item.setPriceActual(orderTicketVo.getPriceActual().subtract(orderTicketVo.getPriceExpress()).divide(BigDecimal.valueOf(orderTicketVo.getNumber()), 2, BigDecimal.ROUND_HALF_UP));
                item.setPriceCanRefund(dataUtils.getCanRefundOrderEntitiesPrice(orderTicketVo, kylinOrderRefundsVoBaseList, item.getOrderTicketEntitiesId()));
                // 手续费处理 TODO 手续费计算改成 按照实付金额计算
                BigDecimal chargesRatio = getChargesRatio(orderTicketVo.getUseStart(), performanceVo.getIsRefundPoundage(dataUtils.getRefundPoundage(1, performanceVo.getPerformancesId()).size()), performanceVo.getPerformancesId());
                BigDecimal chargesPrice = item.getPriceActual().multiply(chargesRatio).setScale(2, BigDecimal.ROUND_HALF_UP);
                item.setPriceCanRefund(item.getPriceCanRefund().subtract(chargesPrice));
                item.setChargesRatio(chargesRatio);
                item.setChargesPrice(chargesPrice);

                BeanUtils.copyProperties(item, refundVo);
                kylinOrderTicketEntitiesPreRefundVos.add(refundVo);
            }
            // FieldName
            orderTicketVo.setFieldName(performanceVo.getFieldName());
            // 短OrderCode
            if (orderTicketVo.getOrderCode().length() > 20) {
                orderTicketVo.setOrderCode(orderTicketVo.getOrderCode().substring(orderTicketVo.getOrderCode().length() - 10));
            }
            // 手续费相关
            OrderRefundPoundageAll refundPoundageAll = dataUtils.getRefundPoundageAll(performanceVo.getIsRefundPoundage(dataUtils.getRefundPoundage(1, performanceVo.getPerformancesId()).size()), performanceVo.getPerformancesId());
            // 券
            ArrayList<KylinOrderCoupons> orderCoupon = dataUtils.getOrderCoupon(orderId);
            // 快递地址
            OrderRefundAddress refundAddress = dataUtils.getRefundAddress(orderTicketVo.getGetTicketType());
            // 快递状态
            Integer orderExpressStatus = dataUtils.getOrderExpressInfo(orderTicketVo.getOrderTicketsId());
            vo.setExpressStatus(orderExpressStatus);
            // 可退快递费
            // 快递费 判断是否是最后一张入场人票 减去已经退的快递费
            BigDecimal canRefundPriceExpress = BigDecimal.valueOf(0);
            // 正在和已经退的快递票金额 正在和已经退的票数量
            if (null != performanceVo.getIsRefundExpressNew() && performanceVo.getIsRefundExpressNew() == 1) {
                Integer refundNum = 0;
                BigDecimal priceExpressOld = BigDecimal.valueOf(0);
                for (KylinOrderRefundsVo refundVo : kylinOrderRefundsVoBaseList) {
                    int status = refundVo.getStatus();
                    if (status != KylinTableStatusConst.ORDER_REFUND_STATUS_CANCEL && status != KylinTableStatusConst.ORDER_REFUND_STATUS_REJECT) { //退款流程未完成和已完成的
                        refundNum++;
                        priceExpressOld = priceExpressOld.add(refundVo.getPriceExpress());
                    }
                }
                if (refundNum + 1 == orderTicketVo.getNumber()) {
                    canRefundPriceExpress = orderTicketVo.getPriceExpress().subtract(priceExpressOld);
                }
            }
            // 整理返回数据
            BeanUtils.copyProperties(orderTicketVo, vo);
            vo.setIsRefundPoundage(performanceVo.getIsRefundPoundage(dataUtils.getRefundPoundage(1, performanceVo.getPerformancesId()).size()));
            vo.setIsRefundVoucher(performanceVo.getIsRefundVoucher());
            vo.setIsBackPaperTicket(performanceVo.getIsBackPaperTicket());
            vo.setIsRefundExpressNew(performanceVo.getIsRefundExpressNew());
            vo.setRefundPoundageAll(refundPoundageAll);
            vo.setOrderCouponList(orderCoupon);
            vo.setRefundAddress(refundAddress);
            vo.setIsTrueName(performanceVo.getIsTrueName());
            vo.setIsRefundExpress(performanceVo.getIsRefundExpress());
            vo.setEntitiesPreRefundVos(kylinOrderTicketEntitiesPreRefundVos);
            vo.setCanRefundPriceExpress(canRefundPriceExpress);
            return ResponseDto.success(vo);
        } catch (Exception e) {
            log.error("toOrderRefundDetailsException", e);
            return ResponseDto.failure(ErrorMapping.get("20030"));
        }
    }

    public ResponseDto sendOrderRefund(String orderId, String orderTicketEntitiesId, String reason, String picList, String ticketNum, Integer sendExpressType, String expressNumber, String expressContacts, String expressPhone, String sendExpressAddress, String appointmentTime) {
        return sendOrderRefund(orderId, orderTicketEntitiesId, reason, picList, ticketNum,
                sendExpressType, expressNumber, expressContacts, expressPhone, sendExpressAddress, appointmentTime,
                false, false);
    }

    /**
     * 系统全额退（拼团散团/超时）：跳过票主登录态与退票窗口，免手续费并触发自动退款。
     */
    public ResponseDto systemFullRefund(String orderId, String orderTicketEntitiesId, String reason) {
        return sendOrderRefund(orderId, orderTicketEntitiesId, reason, "", "",
                0, "", "", "", "", "", true, true);
    }

    public ResponseDto sendOrderRefund(String orderId, String orderTicketEntitiesId, String reason, String picList, String ticketNum, Integer sendExpressType, String expressNumber, String expressContacts, String expressPhone, String sendExpressAddress, String appointmentTime, boolean skipCharges, boolean autoApproved) {
        boolean isLock = dataUtils.setRefundLock(orderTicketEntitiesId);
        if (!isLock) {
            return ResponseDto.failure("正在处理，请勿重复操作～");
        }

        KylinOrderTicketEntitiesVo orderTicketEntitiesVo = null;
        try {
            String uid = null;
            try {
                uid = CurrentUtil.getCurrentUid();
            } catch (Exception ignore) {
                // 系统退款可能无登录态
            }
            KylinOrderTicketVo orderTicketVo = dataUtils.getOrderTicketVo(orderId);
            List<KylinOrderRefundsVo> kylinOrderRefundsVoBaseList = dataUtils.getOrderRefundVoByOrderId(orderTicketVo.getOrderTicketsId());
            if (!autoApproved) {
                if (uid == null || !SuperAccountUtils.isSuperAccount(uid, orderTicketVo.getUserId())) {
                    return ResponseDto.failure(ErrorMapping.get("20003"));
                }
            } else if (uid == null) {
                uid = "system";
            }
//            if (uid.equals("809406") || uid.equals("773650")) {
//            } else {
//                if (!orderTicketVo.getUserId().equals(uid)) {
//                    return ResponseDto.failure(ErrorMapping.get("20003"));
//                }
//            }

            if (!orderTicketVo.getPayStatus().equals(1)) {
                return ResponseDto.failure("暂不支持退款");
            }

            KylinPerformanceVo performanceVo = dataUtils.getPerformanceVo(orderTicketVo.getPerformanceId());
            KylinTicketVo ticketVo = null;
            //获取购票数据
            for (int x = 0; x < performanceVo.getTicketTimeList().size(); x++) {
                KylinTicketTimesVo timeItem = performanceVo.getTicketTimeList().get(x);
                for (int y = 0; y < timeItem.getTicketList().size(); y++) {
                    KylinTicketVo ticketItem = timeItem.getTicketList().get(y);
                    if (ticketItem.getTicketsId().equals(orderTicketVo.getTicketId())) {
                        ticketVo = ticketItem;
                        break;
                    }
                }
            }

            if (!autoApproved) {
                if (null != performanceVo.getIsCanRefund() && performanceVo.getIsCanRefund() == 1) {
                    LocalDateTime refundOpenDate = DateUtil.Formatter.yyyyMMddHHmmss.parse(performanceVo.getRefundOpenTime());
                    LocalDateTime refundCloseDate = DateUtil.Formatter.yyyyMMddHHmmss.parse(performanceVo.getRefundCloseTime());
                    if (LocalDateTime.now().isAfter(refundOpenDate) && LocalDateTime.now().isBefore(refundCloseDate)
                            //&& ticketVo.getCounts() == 1
                    ) {

                    } else {
                        return ResponseDto.failure("暂不支持退款");
                    }
                } else {
                    return ResponseDto.failure("暂不支持退款");
                }
            }

            List<KylinOrderTicketEntitiesVo> entitiesVos = orderTicketVo.getEntitiesVoList();
            for (KylinOrderTicketEntitiesVo item : entitiesVos) {
                if (item.getOrderTicketEntitiesId().equals(orderTicketEntitiesId)) {
                    orderTicketEntitiesVo = item;
                }
            }
            if (null == orderTicketEntitiesVo) {
                return ResponseDto.failure("订单不存在");
            }

            BigDecimal refundSinglePrice = dataUtils.getCanRefundOrderEntitiesPrice(orderTicketVo, kylinOrderRefundsVoBaseList, orderTicketEntitiesId);
            if (refundSinglePrice.compareTo(BigDecimal.ZERO) <= 0) {
                return ResponseDto.failure("申请金额不得小于0");
            }

            BigDecimal singlePrice = orderTicketVo.getPriceActual().subtract(orderTicketVo.getPriceExpress()).divide(BigDecimal.valueOf(orderTicketVo.getNumber()), 2, BigDecimal.ROUND_HALF_UP);
            // 手续费处理 TODO 修改了手续费根据票单算
            BigDecimal priceCharges = BigDecimal.ZERO;
            if (!skipCharges) {
                BigDecimal chargesRatio = getChargesRatio(orderTicketVo.getUseStart(), performanceVo.getIsRefundPoundage(dataUtils.getRefundPoundage(1, performanceVo.getPerformancesId()).size()), performanceVo.getPerformancesId());
                priceCharges = singlePrice.multiply(chargesRatio).setScale(2, BigDecimal.ROUND_HALF_UP);
                refundSinglePrice = refundSinglePrice.subtract(priceCharges);
            }
            if (refundSinglePrice.compareTo(BigDecimal.ZERO) <= 0) {
                return ResponseDto.failure("申请金额不得小于0哦～");
            }

            // 快递费 判断是否是最后一张入场人票 减去已经退的快递费
            BigDecimal priceExpress = BigDecimal.valueOf(0);
            // 正在和已经退的快递票金额 正在和已经退的票数量
            if (null != performanceVo.getIsRefundExpressNew() && performanceVo.getIsRefundExpressNew() == 1) {
                Integer refundNum = 0;
                BigDecimal priceExpressOld = BigDecimal.valueOf(0);
                for (KylinOrderRefundsVo refundVo : kylinOrderRefundsVoBaseList) {
                    int status = refundVo.getStatus();
                    if (status != KylinTableStatusConst.ORDER_REFUND_STATUS_CANCEL && status != KylinTableStatusConst.ORDER_REFUND_STATUS_REJECT) { //退款流程未完成和已完成的
                        refundNum++;
                        priceExpressOld = priceExpressOld.add(refundVo.getPriceExpress());
                    }
                }
                if (refundNum + 1 == orderTicketVo.getNumber()) {
                    priceExpress = orderTicketVo.getPriceExpress().subtract(priceExpressOld);
                }
            }

            String username = "system";
            if (!autoApproved) {
                Map token = CurrentUtil.getTokenClaims();
                username = StringUtils.defaultString(((String) token.get("nickname")), "");
            }
            Integer expressTypeParam = sendExpressType == null ? 0 : sendExpressType;
            String orderRefundId = refundsStatusService.userOrderTicketRefunding(orderTicketVo, refundSinglePrice, priceExpress, priceCharges, orderTicketEntitiesId, reason, picList, ticketNum, uid, username, kylinOrderRefundsVoBaseList.size(), expressTypeParam);
            if (!orderRefundId.isEmpty()) {
                // 退款申请成功 异步去快递下单
                if (orderTicketVo.getGetTicketType().equals("express") && expressTypeParam > 0) {// 快递票
                    expressPlace(expressTypeParam, expressNumber, expressContacts, expressPhone, sendExpressAddress, appointmentTime, orderTicketVo, performanceVo, orderRefundId);
                }
                //电子票自动退款；系统退款一律触发自动审批
                if (autoApproved || orderTicketVo.getGetTicketType().equals("electronic")){
                    try {
                        MultiValueMap<String, String> params = new LinkedMultiValueMap();
                        params.add("orderRefundsId", orderRefundId);
                        MultiValueMap<String, String> headers = new LinkedMultiValueMap();
                        headers.add("Accept", "application/json;charset=UTF-8");
                        log.info("触发自动退款参数" + JsonUtils.toJson(params));
                        String post = HttpUtil.post(platformUrl + "/platform/refund/automaticRefund", params, headers);
                        log.info("触发自动退款返参数" + post);
                    }catch (Exception e){
                        log.error("触发自动退款接口失败orderRefundId={} Exception",orderRefundId,e);
                    }
                }
                HashMap<String, String> map = CollectionUtil.mapStringString();
                map.put("orderRefundsId", orderRefundId);
                return ResponseDto.success(map);
            } else {
                return ResponseDto.failure("申请失败");
            }
        } catch (Exception e) {
            log.error("sendOrderRefundException e:[{}]", e);
            return ResponseDto.failure("申请失败");
        } finally {
            // 执行完毕。释放锁
            dataUtils.delRefundLock(orderTicketEntitiesId);
        }
    }

    public ResponseDto<OrderRefundVo> orderRefundDetails(String orderId, String orderRefundId) {
        try {
            OrderRefundVo vo = OrderRefundVo.getNew();
            String uid = CurrentUtil.getCurrentUid();
            KylinOrderTicketVo orderTicketVo = dataUtils.getOrderTicketVo(orderId);
            KylinPerformanceVo performanceVo = dataUtils.getPerformanceVo(orderTicketVo.getPerformanceId());

            if (!SuperAccountUtils.isSuperAccount(uid, orderTicketVo.getUserId())) {
                return ResponseDto.failure(ErrorMapping.get("20003"));
            }
//            if (uid.equals("809406") || uid.equals("773650")) {
//            } else {
//                if (!orderTicketVo.getUserId().equals(uid)) {
//                    return ResponseDto.failure(ErrorMapping.get("20003"));
//                }
//            }
            orderTicketVo.setFieldName(performanceVo.getFieldName());
            if (orderTicketVo.getOrderCode().length() > 20) {
                orderTicketVo.setOrderCode(orderTicketVo.getOrderCode().substring(orderTicketVo.getOrderCode().length() - 10));
            }
            KylinOrderRefundsVo kylinOrderRefundsVoBase = dataUtils.getOrderRefundVo(orderRefundId);
            if (kylinOrderRefundsVoBase.getOrderRefundCode().length() > 20) {
                kylinOrderRefundsVoBase.setOrderRefundCode(kylinOrderRefundsVoBase.getOrderRefundCode().substring(kylinOrderRefundsVoBase.getOrderRefundCode().length() - 10));
            }
            vo.setKylinOrderRefundsVoBaseList(kylinOrderRefundsVoBase);
            vo.setOrderTicketVo(orderTicketVo);
            vo.setKylinOrderExpressVo(dataUtils.getOrderRefundExpressInfo(orderId));
            return ResponseDto.success(vo);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseDto.failure(ErrorMapping.get("20030"));
        }
    }

    // 返回手续费比例
    private BigDecimal getChargesRatio(String useStart, Integer isRefundPoundage, String performanceId) {
        ArrayList<OrderRefundPoundage> refundPoundage = dataUtils.getRefundPoundage(isRefundPoundage, performanceId);
        // 手续费比例
        BigDecimal chargesRatio = BigDecimal.valueOf(0);
        if (!CollectionUtils.isEmpty(refundPoundage)) {
            chargesRatio = BigDecimal.valueOf(1);
            // 票种演出开始时间
            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            // 当前时间
            LocalDateTime nowTime = LocalDateTime.now();
            //todo 阶梯退票 下面注释为原逻辑 这是判断是否支持退手续费和退多少
            for (OrderRefundPoundage item : refundPoundage) {
                LocalDateTime t = LocalDateTime.parse(item.getDay(), df);//当前阶段时间
                if(nowTime.isBefore(t)){
                    int isCanRefund = item.getIsCanRefund();
                    if (isCanRefund > 0) {
                        chargesRatio = item.getPresent();
                    } else {
                        chargesRatio = BigDecimal.valueOf(Long.parseLong("1"));
                    }
                    break;
                }
            }
//            LocalDateTime useStartD = LocalDateTime.parse(useStart, df);
            // 3、15天之前的时间 时间可变
//            int oneDay = refundPoundage.get(0).getDay();
//            int twoDay = refundPoundage.get(1).getDay();
//            LocalDateTime useStartD15Before = useStartD.minusDays(oneDay);
//            LocalDateTime useStartD3Before = useStartD.minusDays(twoDay);
//
//            if (useStartD15Before.isAfter(nowTime)) { // 15天以前的时间大于当前时间 距离演出开始日期>15天
//                int isCanRefund = refundPoundage.get(0).getIsCanRefund();
//                if (isCanRefund > 0) {
//                    chargesRatio = refundPoundage.get(0).getPresent();
//                } else {
//                    chargesRatio = BigDecimal.valueOf(Long.parseLong("-1"));
//                }
//            } else if (useStartD3Before.isAfter(nowTime)) { // 3天以前的时间大于当前时间 距离演出开始日期>3天-15天 含15天
//                int isCanRefund = refundPoundage.get(1).getIsCanRefund();
//                if (isCanRefund > 0) {
//                    chargesRatio = refundPoundage.get(1).getPresent();
//                } else {
//                    chargesRatio = BigDecimal.valueOf(Long.parseLong("-1"));
//                }
//            } else { // 三天以内 <=3
//                int isCanRefund = refundPoundage.get(2).getIsCanRefund();
//                if (isCanRefund > 0) {
//                    chargesRatio = refundPoundage.get(2).getPresent();
//                } else {
//                    chargesRatio = BigDecimal.valueOf(Long.parseLong("1"));
//                    // return ResponseDto.failure("当前日期不支持退票");
//                }
//            }
            return chargesRatio;
        } else { // 无手续费
            return chargesRatio;
        }
    }

    // 返回手续费比例
    public ResponseDto<OrderRefundPoundage> getChargesRatioItem(String performanceId) {
        KylinPerformanceVo performanceVo = dataUtils.getPerformanceVo(performanceId);
        int isRefundPoundage = performanceVo.getIsRefundPoundage(dataUtils.getRefundPoundage(1, performanceVo.getPerformancesId()).size());
        ArrayList<OrderRefundPoundage> refundPoundage = dataUtils.getRefundPoundage(isRefundPoundage, performanceId);
        OrderRefundPoundage a = null;
        if (!CollectionUtils.isEmpty(refundPoundage)) {
            // 票种演出开始时间
            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            // 当前时间
            LocalDateTime nowTime = LocalDateTime.now();
            //todo 阶梯退票 下面注释为原逻辑 这是判断是否支持退手续费和退多少
            for (OrderRefundPoundage item : refundPoundage) {
                LocalDateTime t = LocalDateTime.parse(item.getDay(), df);//当前阶段时间
                if(nowTime.isBefore(t)){
                    a = item;
                    break;
                }
            }
            return ResponseDto.success(a);
        } else { // 无手续费
            return ResponseDto.success(a);
        }
    }

    // 返回手续费比例
    public ResponseDto<String> getChargesRatioItem2(String performanceId) {
        return ResponseDto.success(dataUtils.getExplain(performanceId));
    }

    //    @Async
    public void expressPlace(Integer sendExpressType, String expressNumber, String expressContacts, String expressPhone, String sendExpressAddress, String appointmentTime, KylinOrderTicketVo orderTicketVo, KylinPerformanceVo performanceVo, String orderRefundId) {
        try {
//            Thread.sleep(1000 * 60);
            log.info("expressPlaceParams [sendExpressType:{}, expressContacts:{}, expressPhone:{}, sendExpressAddress:{}, appointmentTime:{}, orderRefundId:{}]",
                    sendExpressType, expressContacts, expressPhone, sendExpressAddress, appointmentTime, orderRefundId);

            expressContacts = (null == expressContacts) ? "" : expressContacts;
            expressPhone = (null == expressPhone) ? "" : expressPhone;
            sendExpressAddress = (null == sendExpressAddress) ? "" : sendExpressAddress;
            appointmentTime = (null == appointmentTime) ? "" : appointmentTime;
            if (sendExpressType == 1) { // 上门取件
                // 请求下单数据
                Map<String, String> hBody = new HashMap<>();
                hBody.put("custid", custid);
                hBody.put("jContact", expressContacts);
                hBody.put("jMobile", expressPhone);
                hBody.put("jAddress", sendExpressAddress);
                hBody.put("sendStartTime", appointmentTime);

                Integer isRefundExpress = performanceVo.getIsRefundExpress();
                if (isRefundExpress == 1) { // 1用户承担 0无 公司月结
                    hBody.put("payMethod", "1");// 运费付款方式：0-寄付月结；1-寄付现结；2-收方付；3-第三方付；
                } else {
                    // 收方付 派方小哥巴枪挂月结
                    hBody.put("payMethod", "2");// 运费付款方式：0-寄付月结；1-寄付现结；2-收方付；3-第三方付；
                }
                hBody.put("expressType", expressType.toString());// 顺丰特快
                hBody.put("depositumInfo", depositumInfo);
                hBody.put("isDoCall", "1");  // 是否通过手持终端通知顺丰收派员上门收件，支持以下值：1-要求；0-不要求

                String orderExpressId = IDGenerator.nextSnowId();
                String OrderExpressCode = "NOWUR" + orderExpressId;
                hBody.put("orderId", OrderExpressCode);
                hBody.put("depositumNo", orderTicketVo.getNumber().toString());

                OrderRefundAddress refundAddress = dataUtils.getRefundAddress(orderTicketVo.getGetTicketType());
                hBody.put("dContact", refundAddress.getName());
                hBody.put("dTel", refundAddress.getPhone());
                hBody.put("dAddress", refundAddress.getAddress());

                // 生成签名并请求
                String result = shunfengSignUtils.generateSignatureAndRequestNew(hBody, "/public/order/v1/placeOrder");
                log.info("expressPlaceResult result:[{}]", result);
                HashMap hashMap = new HashMap();
                try {
                    hashMap = JsonUtils.fromJson(result, HashMap.class);
                } catch (Exception e) {
                    log.error("expressPlaceFromJsonException e:[{}]", e);
                }

                LinkedList<String> sqls = CollectionUtil.linkedListString();
                sqls.add(SqlMapping.get("kylin_order_refund.refundOrderExpress"));
                LinkedList<Object[]> sqlsDataA = CollectionUtil.linkedListObjectArr();
                LocalDateTime now = LocalDateTime.now();
                String remark = "";
                String proName = "";
                String goodsValueTotal = "";
                String goodsNumber = "";
                String mailno = "";
                String filterResult = "";
                String cargoTypeCode = "";
                String limitTypeCode = "";
                String expressTypeCode = "";
                Integer orderExpressStatus = 0;
                if (null == hashMap.get("succ") || hashMap.get("succ").equals("fail")) {
                    String msg = "";
                    if (null == hashMap.get("succ")) {
                        msg = result;
                    } else {
                        msg = (String) hashMap.get("msg");
                    }
                    remark = msg;
                    orderExpressStatus = 1;
                } else { // 成功下单记录缓存
                    // 生成快递单
                    HashMap hashMapResult = (HashMap) hashMap.get("result");
                    remark = (String) hashMapResult.get("remark");
                    proName = (String) hashMapResult.get("proName");
                    goodsValueTotal = (String) hashMapResult.get("goodsValueTotal");
                    goodsNumber = (String) hashMapResult.get("goodsNumber");
                    mailno = (String) hashMapResult.get("mailno");
                    filterResult = (String) hashMapResult.get("filter_result");
                    cargoTypeCode = (String) hashMapResult.get("cargoTypeCode");
                    limitTypeCode = (String) hashMapResult.get("limitTypeCode");
                    expressTypeCode = (String) hashMapResult.get("expressTypeCode");
                    remark = (null == remark) ? "" : remark;
                    proName = (null == proName) ? "" : proName;
                    goodsValueTotal = (null == goodsValueTotal) ? "" : goodsValueTotal;
                    goodsNumber = (null == goodsNumber) ? "" : goodsNumber;
                    mailno = (null == mailno) ? "" : mailno;
                    filterResult = (null == filterResult) ? "" : filterResult;
                    cargoTypeCode = (null == cargoTypeCode) ? "" : cargoTypeCode;
                    limitTypeCode = (null == limitTypeCode) ? "" : limitTypeCode;
                    expressTypeCode = (null == expressTypeCode) ? "" : expressTypeCode;
                    orderExpressStatus = 2;
                }
                sqlsDataA.add(new Object[]{
                        orderExpressId, orderTicketVo.getPerformanceId(), orderTicketVo.getOrderTicketsId(), orderRefundId,
                        OrderExpressCode, mailno, expressType, filterResult, remark, orderExpressStatus
                        , 2, sendExpressType, expressContacts, expressPhone, sendExpressAddress, appointmentTime
                        , proName, cargoTypeCode, limitTypeCode, expressTypeCode, goodsValueTotal, goodsNumber
                        , now
                });
                queueUtils.sendMsgByRedis(MQConst.KylinQueue.SQL_ORDER_REFUND_EXPRESS.getKey(),
                        SqlMapping.gets(sqls, sqlsDataA));

                KylinOrderExpressVo kylinOrderExpressVo = KylinOrderExpressVo.getNew();
                kylinOrderExpressVo.setOrderExpressId(orderExpressId);
                kylinOrderExpressVo.setOrderTicketsId(orderTicketVo.getOrderTicketsId());
                kylinOrderExpressVo.setOrderExpressCode(OrderExpressCode);
                kylinOrderExpressVo.setMailno(mailno);
                kylinOrderExpressVo.setExpressStatus(orderExpressStatus);
                kylinOrderExpressVo.setSendExpressType(sendExpressType);
                dataUtils.setOrderRefundExpressInfo(orderTicketVo.getOrderTicketsId(), kylinOrderExpressVo);
            } else if (sendExpressType == 2) { // 自主发货
                // 生成快递单 REDIS 队列入数据库
                String orderExpressId = IDGenerator.nextSnowId();
                String OrderExpressCode = "NOWUR" + orderExpressId;
                LocalDateTime now = LocalDateTime.now();
                LinkedList<String> sqls = CollectionUtil.linkedListString();
                sqls.add(SqlMapping.get("kylin_order_refund.refundOrderExpress"));
                LinkedList<Object[]> sqlsDataA = CollectionUtil.linkedListObjectArr();
                sqlsDataA.add(new Object[]{
                        orderExpressId, orderTicketVo.getPerformanceId(), orderTicketVo.getOrderTicketsId(), orderRefundId, OrderExpressCode, expressNumber, expressType, "", "", KylinTableStatusConst.ORDER_EXPRESS_STATUS2
                        , 2, sendExpressType, expressContacts, expressPhone, sendExpressAddress, appointmentTime
                        , "", "", "", "", "", ""
                        , now
                });
                queueUtils.sendMsgByRedis(MQConst.KylinQueue.SQL_ORDER_REFUND_EXPRESS.getKey(),
                        SqlMapping.gets(sqls, sqlsDataA));

                KylinOrderExpressVo kylinOrderExpressVo = KylinOrderExpressVo.getNew();
                kylinOrderExpressVo.setOrderExpressId(orderExpressId);
                kylinOrderExpressVo.setOrderTicketsId(orderTicketVo.getOrderTicketsId());
                kylinOrderExpressVo.setOrderExpressCode(OrderExpressCode);
                kylinOrderExpressVo.setMailno(expressNumber);
                kylinOrderExpressVo.setExpressStatus(KylinTableStatusConst.ORDER_EXPRESS_STATUS2);
                kylinOrderExpressVo.setSendExpressType(sendExpressType);
                dataUtils.setOrderRefundExpressInfo(orderTicketVo.getOrderTicketsId(), kylinOrderExpressVo);
            }
        } catch (Exception e) {
            log.error("expressPlaceError e:{}", e);
        }
    }

    public ResponseDto<Boolean> orderRefundWithdraw(String orderRefundsId) {

        LinkedList<String> sqls = CollectionUtil.linkedListString();
        LinkedList<Object[]> sqlsDataA = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> sqlsDataB = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> sqlsDataC = CollectionUtil.linkedListObjectArr();

        LocalDateTime time = LocalDateTime.now();
        String strTime = DateUtil.Formatter.yyyyMMddHHmmss.format(time);
        try {
            KylinOrderRefundsVo orderRefundsVo = dataUtils.getOrderRefundVo(orderRefundsId);
            if (!orderRefundsVo.getStatus().equals(0)) {
                return ResponseDto.failure(ErrorMapping.get("20020"));
            }
            List<KylinOrderRefundEntitiesVo> refundEntities = orderRefundsVo.getOrderRefundEntitiesVoList();
            String orderTicketsId = orderRefundsVo.getOrderTicketsId();
            KylinOrderTicketVo orderTicketVo = dataUtils.getOrderTicketVo(orderTicketsId);

            // 更新数据
            // 订单状态表 判断是退到正在退款 已付款 部分退款？(取消，完成，失败)
            int newStatus;
            int refundingCount = 0;
            List<KylinOrderRefundsVo> orderRefundsVoList = dataUtils.getOrderRefundVoByOrderId(orderTicketsId);
            for (KylinOrderRefundsVo item : orderRefundsVoList) {
                int status = item.getStatus();
                log.info("status = " + status);
                if (status != 2 && status != 4 && status != 5 && !item.getOrderRefundsId().equals(orderRefundsId)) {
                    refundingCount += 1;
                }
            }

            if (refundingCount > 0) { // 存在其他正在退款的订单
                newStatus = KylinTableStatusConst.ORDER_STATUS3;
            } else {
                if (orderTicketVo.getPriceRefund().doubleValue() > 0) { // 已经有退完的 那就是部分退款了
                    newStatus = KylinTableStatusConst.ORDER_STATUS6;
                } else if (orderTicketVo.getStatus() != 2) {
                    newStatus = KylinTableStatusConst.ORDER_STATUS1;
                } else {
                    newStatus = KylinTableStatusConst.ORDER_STATUS2;
                }
            }

            KylinOrderTicketStatus orderStatusTable = KylinOrderTicketStatus.getNew();
            log.info("newStatus = " + newStatus);
            orderStatusTable.setStatus(newStatus);
            orderStatusTable.setUpdatedAt(time);
            LocalDateTime now = LocalDateTime.now();
            sqlsDataA.add(new Object[]{
                    orderStatusTable.getStatus(), orderStatusTable.getUpdatedAt(), orderTicketsId, now, now
            });

            KylinOrderTicketVo kylinOrderTicketVo = KylinOrderTicketVo.getNew();
            kylinOrderTicketVo.setStatus(newStatus);
            kylinOrderTicketVo.setUpdatedAt(strTime);
            kylinOrderTicketVo.setChangeDate(time);
            BasicDBObject orderObject = new BasicDBObject("$set", JSON.parse(JsonUtils.toJson(kylinOrderTicketVo)));
            mongoTemplate.getCollection(KylinOrderTicketVo.class.getSimpleName()).updateOne(
                    Query.query(Criteria.where("orderTicketsId").is(orderTicketsId)).getQueryObject(),
                    orderObject
            );

            // 入场人
            for (KylinOrderRefundEntitiesVo item : refundEntities) {
                // 订单状态表 判断是退到正在退款 已付款 部分退款？(取消，完成，失败)
                int newIsPayment = 0;
                int refundingEntitiesCount = 0;
                for (KylinOrderRefundsVo item2 : orderRefundsVoList) {
                    int status = item2.getStatus();
                    if (!item2.getOrderRefundsId().equals(orderRefundsId) && (status != 2 && status != 4 && status != 5)) {
                        for (KylinOrderRefundEntitiesVo item3 : item2.getOrderRefundEntitiesVoList()) {
                            if (item3.getOrderTicketEntitiesId().equals(item.getOrderTicketEntitiesId())) {
                                refundingEntitiesCount += 1;
                            }
                        }
                    }

                    /*for (KylinOrderRefundEntitiesVo item3 : item2.getOrderRefundEntitiesVoList()) {
                        if (item3.getOrderTicketEntitiesId().equals(item.getOrderTicketEntitiesId())) {
                            entitiesAllPrice.add(item3.getRefundPrice());
                        }
                    }*/

                }

                KylinOrderTicketEntitiesVo entitiesVo = null;
                for (KylinOrderTicketEntitiesVo entitiesVo1 : orderTicketVo.getEntitiesVoList()) {
                    if (entitiesVo1.getOrderTicketEntitiesId().equals(item.getOrderTicketEntitiesId())) {
                        entitiesVo = entitiesVo1;
                        break;
                    }
                }

                log.info("getRefundPrice =" + item.getRefundPrice());
                if (refundingEntitiesCount > 0) { // 存在其他正在退款的该入场人订单
                    newIsPayment = KylinTableStatusConst.ENTITIES_IS_PAYMENT2;
                } else {
                    if (orderTicketVo.getPriceRefund().compareTo(BigDecimal.ZERO) > 0) { // 已经有退完的 那就是部分退款了
                        newIsPayment = KylinTableStatusConst.ENTITIES_IS_PAYMENT4;
                    } else {
                        newIsPayment = KylinTableStatusConst.ENTITIES_IS_PAYMENT1;
                    }
                }
                KylinOrderTicketEntities entitiesTable = KylinOrderTicketEntities.getNew();
                entitiesTable.setIsPayment(newIsPayment);
                entitiesTable.setUpdatedAt(time);

                log.info("sqlsDataB data = " + entitiesTable.getIsPayment());

                sqlsDataB.add(new Object[]{
                        entitiesTable.getIsPayment(), entitiesTable.getUpdatedAt(), item.getOrderTicketEntitiesId(), now, now
                });

                KylinOrderTicketEntitiesVo kylinOrderTicketEntitiesVo = KylinOrderTicketEntitiesVo.getNew();
                kylinOrderTicketEntitiesVo.setIsPayment(newIsPayment);
                kylinOrderTicketEntitiesVo.setUpdatedAt(strTime);
                kylinOrderTicketEntitiesVo.setChangeDate(time);
//                for (KylinOrderRefundEntitiesVo item2:orderRefundsVo.getOrderRefundEntitiesVoList()){
//                    if(item2.getOrderTicketEntitiesId().equalsIgnoreCase(item.getOrderTicketEntitiesId())){
//                        log.info("entitiesVo.getRefundPrice() = "+entitiesVo.getRefundPrice());
//                        log.info("item2.getRefundPrice() = "+item2.getRefundPrice());
                kylinOrderTicketEntitiesVo.setRefundPrice(entitiesVo.getRefundPrice());
//                    }
//                }

                log.info("entitiesVo.getRefundPrice() = " + entitiesVo.getRefundPrice());
                BasicDBObject entitiesObject = new BasicDBObject("$set", JSON.parse(JsonUtils.toJson(kylinOrderTicketEntitiesVo)));
                mongoTemplate.getCollection(KylinOrderTicketEntitiesVo.class.getSimpleName()).updateOne(
                        Query.query(Criteria.where("orderTicketEntitiesId").is(item.getOrderTicketEntitiesId())).getQueryObject(),
                        entitiesObject
                );

                dataUtils.delOrderTicketEntitiesRedis(item.getOrderTicketEntitiesId());
            }

            orderUtils.resetOrderListVo(orderTicketVo.getUserId(), 2, orderTicketsId, null);

            // 退款细节取消
            KylinOrderRefunds kylinOrderRefunds = KylinOrderRefunds.getNew();
            kylinOrderRefunds.setStatus(KylinTableStatusConst.ORDER_REFUND_STATUS_CANCEL);
            kylinOrderRefunds.setUpdatedAt(LocalDateTime.now());

            mongoTemplate.getCollection(KylinOrderRefundsVo.class.getSimpleName()).updateOne(
                    Query.query(Criteria.where("orderRefundsId").is(orderRefundsId)).getQueryObject(),
                    new Document("$set", new Document("status", KylinTableStatusConst.ORDER_REFUND_STATUS_CANCEL).append("updatedAt", mongoTemplate.getConverter().convertToMongoType(time)))
            );

            sqlsDataC.add(new Object[]{
                    KylinTableStatusConst.ORDER_REFUND_STATUS_CANCEL, time, orderRefundsId
            });

            dataUtils.delOrderRefundVo(orderRefundsId);
            dataUtils.delOrderRefundVoByOrderId(orderTicketsId);
            dataUtils.delOrderTicketRedis(orderTicketsId);
            orderUtils.resetOrderListVo(CurrentUtil.getCurrentUid(), 2, orderTicketsId, null);


            sqls.add(SqlMapping.get("kylin_order_ticket_status.withDraw"));
            sqls.add(SqlMapping.get("kylin_order_ticket_entities.withDraw"));
            sqls.add(SqlMapping.get("kylin_order_refund.withDraw"));
            queueUtils.sendMsgByRedis(MQConst.KylinQueue.SQL_ORDER_WITHDRAW.getKey(),
                    SqlMapping.gets(sqls, sqlsDataA, sqlsDataB, sqlsDataC));
            return ResponseDto.success(true);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseDto.failure(ErrorMapping.get("20020"));
        }
    }

}