package com.czg.service.order.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.czg.account.dto.shopuser.ShopUserMoneyEditDTO;
import com.czg.account.entity.*;
import com.czg.account.service.*;
import com.czg.config.RabbitPublisher;
import com.czg.config.RedisCst;
import com.czg.constant.MarketConstants;
import com.czg.constant.TableValueConstant;
import com.czg.constants.PayTypeConstants;
import com.czg.entity.notify.CzgRefundNotifyDTO;
import com.czg.enums.ShopTableStatusEnum;
import com.czg.enums.ShopUserFlowBizEnum;
import com.czg.exception.CzgException;
import com.czg.exception.OrderCancelException;
import com.czg.exception.OrderValidateException;
import com.czg.market.dto.MkDiscountActivityDTO;
import com.czg.market.entity.MkDiscountThreshold;
import com.czg.market.entity.MkPointsConfig;
import com.czg.market.entity.MkShopCouponRecord;
import com.czg.market.entity.ShopCoupon;
import com.czg.market.enums.PointsConstant;
import com.czg.market.service.*;
import com.czg.order.dto.*;
import com.czg.order.entity.CashierCart;
import com.czg.order.entity.OrderDetail;
import com.czg.order.entity.OrderInfo;
import com.czg.order.entity.OrderPayment;
import com.czg.order.enums.PayEnums;
import com.czg.order.service.*;
import com.czg.order.vo.*;
import com.czg.pay.PayNotifyRespDTO;
import com.czg.product.entity.Product;
import com.czg.product.entity.ShopProdCategory;
import com.czg.product.service.ProductRpcService;
import com.czg.product.service.ProductService;
import com.czg.product.service.ShopProdCategoryService;
import com.czg.product.vo.ConsStockRecord;
import com.czg.product.vo.ProductStockVO;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.service.RedisService;
import com.czg.service.order.enums.OrderStatusEnums;
import com.czg.service.order.mapper.OrderInfoCustomMapper;
import com.czg.service.order.print.PrintConfig;
import com.czg.service.order.print.PrinterHandler;
import com.czg.utils.*;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotBlank;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * 订单表 服务层实现。
 *
 * @author ww
 * @since 2025-02-13
 */
@Slf4j
@Service
public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
    @Resource
    private OrderInfoCustomMapper orderInfoCustomMapper;
    @Resource
    private OrderInfoService orderInfoService;
    @Resource
    private PrintConfig printConfig;
    @Resource
    private OrderDetailService orderDetailService;
    @Resource
    private OrderPaymentService paymentService;
    @Resource
    private CashierCartService cartService;
    @Resource
    private RedisService redisService;
    @Resource
    private RabbitPublisher rabbitPublisher;
    @Resource
    private MkDistributionUserService distributionUserService;
    @DubboReference
    private ProductService productService;
    @DubboReference
    private ShopProdCategoryService shopProdCategoryService;
    @DubboReference
    private ProductRpcService productRpcService;
    @DubboReference
    private ShopInfoService shopInfoService;
    @DubboReference
    private UserInfoService userInfoService;
    @DubboReference
    private ShopUserService shopUserService;
    @DubboReference
    private ShopUserFlowService flowService;
    @DubboReference
    private ShopTableService shopTableService;
    @Resource
    private MkShopConsumerCouponService consumerCouponService;
    @Resource
    private MkPointsUserService pointsUserService;
    @Resource
    private MkPointsConfigService pointsConfigService;
    @Resource
    private PointsGoodPayService goodPayService;
    @Resource
    private GbOrderService gbOrderService;
    @Resource
    private ShopCouponService couponService;
    @Resource
    private MkShopCouponRecordService couponRecordService;
    @Resource
    private TbMemberConfigService memberConfigService;
    @Resource
    private MkShopConsumeDiscountRecordService newConsumerDiscountRecordService;
    @Resource
    private MkDiscountActivityService discountActService;
    @Resource
    private MkShopRechargeService shopRechargeService;
    @Resource
    private MkConsumeCashbackService consumeCashbackService;
    @DubboReference
    private PpPackageOrderService ppPackageOrderService;
    // 延迟 5 秒
    private static final long DELAY = 5;
    //重试次数
    private static final int MAX_RETRIES = 3;
    private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);

    @Override
    public Page<OrderInfoVo> getOrderByPage(OrderInfoQueryDTO param) {
        List<ShopInfo> list = shopInfoService.list(QueryWrapper.create().select(ShopInfo::getId, ShopInfo::getShopName));
        Map<Long, String> shopMap = list.stream().collect(Collectors.toMap(ShopInfo::getId, ShopInfo::getShopName));
        String productName = param.getProductName();
        List<Long> like = null;
        if (StrUtil.isNotBlank(productName)) {
            QueryWrapper queryWrapper = QueryWrapper.create();
            queryWrapper.select(OrderDetail::getOrderId)
                    .eq(OrderDetail::getShopId, param.getShopId())
                    .like(OrderDetail::getProductName, productName);
            like = orderDetailService.listAs(queryWrapper, Long.class);
            if (CollUtil.isEmpty(like)) {
                return PageUtil.emptyPage();
            }
        }
        QueryWrapper queryWrapper = PageUtil.buildSortQueryWrapper();

        queryWrapper.eq(OrderInfo::getShopId, param.getShopId())
                .eq(OrderInfo::getStatus, CzgStrUtils.getStrOrNull(param.getStatus()))
                .eq(OrderInfo::getPayType, CzgStrUtils.getStrOrNull(param.getPayType()))
                .eq(OrderInfo::getUserId, param.getUserId())
                .eq(OrderInfo::getTableCode, CzgStrUtils.getStrOrNull(param.getTableCode()))
                .eq(OrderInfo::getTableName, CzgStrUtils.getStrOrNull(param.getTableName()))
                .eq(OrderInfo::getOrderNo, CzgStrUtils.getStrOrNull(param.getOrderNo()))
                .eq(OrderInfo::getIsDel, param.getIsDel())
                .gt(OrderInfo::getCreateTime, CzgStrUtils.getStrOrNull(param.getStartTime()))
                .le(OrderInfo::getCreateTime, CzgStrUtils.getStrOrNull(param.getEndTime()))
                .in(OrderInfo::getId, like)
                .orderBy(OrderInfo::getId).desc();
        Page<OrderInfoVo> orderInfoVoPage = orderInfoService.pageAs(PageUtil.buildPage(), queryWrapper, OrderInfoVo.class);
        orderInfoVoPage.getRecords().parallelStream().forEach(s -> {
            List<OrderDetailSmallVO> orderDetails = orderDetailService.listAs(
                    QueryWrapper.create().eq(OrderDetail::getOrderId, s.getId()).eq(OrderDetail::getShopId, s.getShopId()), OrderDetailSmallVO.class);
            s.setGoods(orderDetails);
            s.setShopName(shopMap.get(Long.parseLong(s.getShopId())));
        });
        return orderInfoVoPage;
    }

    @Override
    public CzgResult<HistoryOrderVo> getOrderDetails(Long orderId) {
        AssertUtil.isNull(orderId, "订单id不能为空");
        return CzgResult.success(historyOrder(orderId, null));
    }

    @Override
    public CzgResult<HistoryOrderPrintVo> getOrderByIdPrint(Long orderId) {
        HistoryOrderPrintVo historyOrderVo = orderInfoService.getOneAs(new QueryWrapper()
                .eq(OrderInfo::getId, orderId), HistoryOrderPrintVo.class);
        AssertUtil.isNull(historyOrderVo, "订单不存在");
        List<OrderDetailPrintVo> orderDetails = orderDetailService.getOrderDetailPrint(orderId);
        Map<String, List<OrderDetailPrintVo>> resultMap = new HashMap<>();
        // 遍历订单详情列表
        for (OrderDetailPrintVo orderDetail : orderDetails) {
            if ("Array".equals(orderDetail.getProGroupInfo())) {
                orderDetail.setProGroupInfo("");
            }
            // 获取当前订单详情的 placeNum
            Integer placeNum = orderDetail.getPlaceNum();
            // 检查 Map 中是否已经存在该 placeNum 对应的列表
            resultMap.computeIfAbsent(placeNum.toString(), k -> new ArrayList<>()).add(orderDetail);
        }
        historyOrderVo.setDetailMap(resultMap);
        long count = orderInfoService.count(QueryWrapper.create()
                .eq(OrderInfo::getTradeDay, historyOrderVo.getTradeDay())
                .eq(OrderInfo::getStatus, OrderStatusEnums.DONE.getCode())
                .eq(OrderInfo::getShopId, historyOrderVo.getShopId())
                .le(OrderInfo::getCreateTime, historyOrderVo.getCreateTime()));
        historyOrderVo.setOrderNum(count);
        return CzgResult.success(historyOrderVo);
    }

    @Override
    public HistoryOrderVo historyOrder(Long orderId, String tableCode) throws CzgException {
        if (orderId == null && StrUtil.isBlank(tableCode)) {
            throw new CzgException("订单id或台桌码不可为空");
        }
        if (orderId == null && ("null".equals(tableCode) || "undefined".equals(tableCode))) {
            throw new CzgException("台桌码不可用");
        }
        HistoryOrderVo historyOrderVo;
        if (orderId == null) {
            historyOrderVo = orderInfoService.getOneAs(QueryWrapper.create()
                    .eq(OrderInfo::getShopId, StpKit.USER.getShopId())
                    .eq(OrderInfo::getTableCode, tableCode)
                    .eq(OrderInfo::getStatus, OrderStatusEnums.UNPAID.getCode())
                    .gt(OrderInfo::getCreateTime, DateUtil.offsetDay(new Date(), -1)), HistoryOrderVo.class);
        } else {
            historyOrderVo = orderInfoService.getOneAs(new QueryWrapper()
                    .eq(OrderInfo::getId, orderId), HistoryOrderVo.class);
        }
        if (historyOrderVo == null || historyOrderVo.getId() == null) {
            return null;
        }
        if (StrUtil.isNotBlank(historyOrderVo.getLimitRateJson())) {
            historyOrderVo.setLimitRate(JSONUtil.toBean(historyOrderVo.getLimitRateJson(), LimitRateDTO.class));
        }
        List<OrderDetail> orderDetails = orderDetailService.queryChain().select()
                .eq(OrderDetail::getOrderId, historyOrderVo.getId())
                .list();
        Map<String, List<OrderDetail>> resultMap = new HashMap<>();
        // 遍历订单详情列表
        for (OrderDetail orderDetail : orderDetails) {
            // 获取当前订单详情的 placeNum
            Integer placeNum = orderDetail.getPlaceNum();
            // 检查 Map 中是否已经存在该 placeNum 对应的列表
            resultMap.computeIfAbsent(placeNum.toString(), k -> new ArrayList<>()).add(orderDetail);
        }
        historyOrderVo.setDetailMap(resultMap);
        return historyOrderVo;
    }

    @Override
    @Transactional
    public OrderInfo createOrder(OrderInfoAddDTO param) throws ValidateException, CzgException {
        ShopInfo shopInfo = shopInfoService.getById(param.getShopId());
        AssertUtil.isNull(shopInfo, "生成订单失败，店铺信息不存在");
        if (!shopInfo.getEatModel().contains(param.getDineMode())) {
            throw new CzgException("生成订单失败，店铺不支持该用餐模式");
        }
        if (param.getUserId() != null) {
            UserInfo userInfo = userInfoService.getById(param.getUserId());
            AssertUtil.isNull(userInfo, "生成订单失败，用户信息不存在");
        }
        ShopTable table = null;
        if (StrUtil.isBlank(param.getTableCode())) {
            param.setPayMode("no-table");
        } else {
            table = shopTableService.getOneByTableCode(param.getShopId(), param.getTableCode());
            if (table == null) {
                param.setPayMode("no-table");
            } else {
                if ("before".equals(shopInfo.getRegisterType())) {
                    param.setPayMode("before-pay");
                } else if ("after".equals(shopInfo.getRegisterType())) {
                    param.setPayMode("after-pay");
                } else {
                    param.setPayMode("未知");
                }
                table.setStatus(ShopTableStatusEnum.UNSETTLED.getValue());
                shopTableService.updateById(table);
            }
        }
        List<OrderDetail> orderDetails = cartService.getCartByTableCode(shopInfo.getId(), param.getTableCode(), param.getPlaceNum());
        if (StrUtil.isNotBlank(param.getSubStatus())) {
            if ("URGENT".equals(param.getSubStatus())) {
                orderDetails.forEach(item -> {
                    item.setUrgent(true);
                    item.setSubStatus(TableValueConstant.OrderDetail.SubStatus.READY_TO_SERVE.getCode());
                    item.setStartOrderTime(DateUtil.date().toLocalDateTime());
                });
            } else {
                switch (EnumUtil.fromString(TableValueConstant.OrderDetail.SubStatus.class, param.getSubStatus())) {
                    case TableValueConstant.OrderDetail.SubStatus.READY_TO_SERVE:
                        orderDetails.forEach(item -> item.setStartOrderTime(DateUtil.date().toLocalDateTime()));
                        break;
                }
                orderDetails.forEach(item -> item.setSubStatus(param.getSubStatus()));
            }
        }
        orderDetails.forEach(item -> item.setOrderTime(DateUtil.date().toLocalDateTime()));
        AssertUtil.isListEmpty(orderDetails, "下单失败 购物车为空");
        processOrderDetails(orderDetails, param.getLimitRate(), param);
        //生成订单
        OrderInfo orderInfo = initOrderInfo(param, shopInfo, table);
        orderDetailService.createOrderDetails(orderInfo.getId(), orderDetails);
        //清空购物车
        cartService.remove(new QueryWrapper()
                .eq(CashierCart::getShopId, orderInfo.getShopId())
                .eq(CashierCart::getTableCode, param.getTableCode())
        );
        if ("after-pay".equals(orderInfo.getPayMode())) {
            log.info("后付费生成订单{},第{}", orderInfo.getId(), orderInfo.getPlaceNum());
            FunUtils.transactionSafeRun(() -> {
                //客看单
                printConfig.orderHandler(orderInfo.getId(), PrinterHandler.PrintTypeEnum.GUEST_ORDER, orderInfo.getPlaceNum());
                // 消息通知 本地打印机执行
                rabbitPublisher.sendOrderPrintMsg(orderInfo.getId(), 0, 0, orderInfo.getPlaceNum(), "后付费打印");
            });
        } else {
            redisService.set(RedisCst.classKeyExpired.EXPIRED_ORDER + orderInfo.getId(), "", 60 * 15);
        }
        rabbitPublisher.sendOrderStockMsg(orderInfo.getId().toString());
        rabbitPublisher.sendOrderDetailStatusMsg(orderInfo.getShopId().toString(), "bc");
        return orderInfo;
    }

    @Override
    public OrderInfo checkOrderPay(CheckOrderPay param) throws OrderValidateException, OrderCancelException, CzgException {
        AssertUtil.isNull(param.getOrderId(), "支付失败，订单id不能为空");
        OrderInfo orderInfo = orderInfoService.getById(param.getOrderId());
        if (!orderInfo.getStatus().equals(OrderStatusEnums.UNPAID.getCode())) {
            throw new OrderCancelException("生成支付订单失败，订单不可支付");
        }
        if (!"after-pay".equals(orderInfo.getPayMode())) {
            if (redisService.hasKey(RedisCst.classKeyExpired.EXPIRED_ORDER + param.getOrderId())) {
                redisService.set(RedisCst.classKeyExpired.EXPIRED_ORDER + param.getOrderId(), "", 60 * 15);
            } else {
                if (!orderInfo.getStatus().equals(OrderStatusEnums.CANCELLED.getCode())) {
                    ThreadUtil.execAsync(() -> {
                        OrderInfo orderInfoUpdate = new OrderInfo();
                        orderInfoUpdate.setId(orderInfo.getId());
                        orderInfoUpdate.setStatus(OrderStatusEnums.CANCELLED.getCode());
                        orderInfoService.updateById(orderInfoUpdate);
                        rabbitPublisher.sendOrderCancelMsg(orderInfo.getId().toString());
                    });
                }
                throw new OrderCancelException("订单已过期,请重新下单");
            }
        }
        if (StrUtil.isNotBlank(param.getDineMode())) {
            orderInfo.setDineMode(param.getDineMode());
        }
        ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
        AssertUtil.isNull(shopInfo, "生成订单失败，店铺信息不存在");
        if (param.isVipPrice() && !shopInfo.getIsMemberPrice().equals(1)) {
            throw new OrderValidateException("生成订单失败，该店铺不支持使用会员价");
        }
        if (param.getOrderAmount().compareTo(BigDecimal.ZERO) < 0) {
            throw new OrderValidateException("生成订单失败，订单金额不能小于0");
        }
        log.info("订单信息：{}，\r\n 优惠信息：{}", JSONObject.toJSONString(orderInfo), JSONObject.toJSONString(param));
        Long shopId = orderInfo.getShopId();
        AssertUtil.isNull(shopId, "生成支付订单失败，订单信息异常");
        //霸王餐不参与满减
        if (param.isFreeDine() && param.getDiscountActId() != null) {
            throw new OrderValidateException("生成订单失败，霸王餐不能享受满减活动");
        }
        MkDiscountActivityDTO discountAct = null;
        // 满减活动校验
        if (param.getDiscountActId() != null && param.getDiscountActAmount().compareTo(BigDecimal.ZERO) > 0) {
            //检查满减活动是否开启
            discountAct = discountActService.checkDiscountAct(param.getDiscountActId(),
                    CollUtil.isNotEmpty(param.getCouponList()), param.isVipPrice(), param.getLimitRate() != null,
                    param.getPointsDiscountAmount().compareTo(BigDecimal.ZERO) > 0);
        }
        // 积分校验
        MkPointsConfig pointSetting = pointsConfigService.getOne(QueryWrapper.create().eq(MkPointsConfig::getShopId, shopId));
        boolean usePointsDeduction = param.getPointsNum() > 0 || param.getPointsDiscountAmount().compareTo(BigDecimal.ZERO) > 0;
        if (usePointsDeduction) {
            if (pointSetting == null || !pointSetting.getEnableRewards().equals(1)) {
                throw new OrderValidateException("生成支付订单失败，该店铺未开启积分抵扣");
            }
            if (param.getUserId() == null) {
                throw new OrderValidateException("生成支付订单失败，请选择用户后再使用积分抵扣");
            }
            //霸王餐
            if (param.isFreeDine() && !param.isWithPoints()) {
                throw new OrderValidateException("生成支付订单失败，霸王餐不支持积分抵扣");
            }
        } else {
            if (param.getPointsNum() != 0 || param.getPointsDiscountAmount().compareTo(BigDecimal.ZERO) != 0) {
                throw new OrderValidateException("生成支付订单失败，积分抵扣数量或金额不正确");
            }
        }

        ShopUser shopUser = null;
        if (param.getUserId() != null) {
            UserInfo userInfo = userInfoService.getById(param.getUserId());
            AssertUtil.isNull(userInfo, "生成支付订单失败，用户信息不存在");
            shopUser = shopUserService.getShopUserInfo(shopId, param.getUserId());
            orderInfo.setUserId(userInfo.getId());
        }
        //会员价校验
        if (param.isVipPrice() && (shopUser == null || shopUser.getIsMemberPrice() == null
                || shopUser.getIsMemberPrice() == 0 || shopUser.getIsVip().equals(0))) {
            throw new OrderValidateException("生成支付订单失败，仅会员可使用会员价");
        }

        List<OrderDetail> orderDetails = orderDetailService.queryChain().eq(OrderDetail::getOrderId, param.getOrderId()).select().list();
        //总商品金额 不包含打包费 不包含临时菜
        BigDecimalDTO totalAmount = new BigDecimalDTO(BigDecimal.ZERO);
        //最终打包费
        BigDecimalDTO packAmount = new BigDecimalDTO(BigDecimal.ZERO);
        //临时菜总费用
        BigDecimalDTO tempAmount = new BigDecimalDTO(BigDecimal.ZERO);
        //商品兑换券金额
        BigDecimalDTO prodCouponAmount = new BigDecimalDTO(BigDecimal.ZERO);
        //买一送一券金额
        BigDecimalDTO oneGiftAmount = new BigDecimalDTO(BigDecimal.ZERO);
        //第二件半价券金额
        BigDecimalDTO twoHalfAmount = new BigDecimalDTO(BigDecimal.ZERO);
        //折扣金额
        BigDecimalDTO rateAmount = new BigDecimalDTO(BigDecimal.ZERO);
        //满减金额
        BigDecimalDTO fullReductionAmount = new BigDecimalDTO(BigDecimal.ZERO);
        getOrderAmount(orderDetails, totalAmount, packAmount, tempAmount, param.getLimitRate(),
                param.isAllPack(), param.getUserAllPack(), param.isVipPrice());
        if (totalAmount.getPrice().compareTo(param.getOriginAmount()) != 0) {
            log.info("订单原价不正确：订单原价：{}，传递为：{}", totalAmount.getPrice(), param.getOriginAmount());
            throw new OrderValidateException("生成支付订单失败，订单原金额不正确");
        }

        //优惠券部分 目前规则 每个券只能用一张
        couponExecute(orderDetails, param, totalAmount, tempAmount, prodCouponAmount,
                oneGiftAmount, twoHalfAmount, rateAmount, fullReductionAmount);

        //总商品支付金额 不包含打包费  用来计算后续
        BigDecimal newTotalAmount = totalAmount.getPrice();

        //减去商品优惠券
        newTotalAmount = newTotalAmount.subtract(prodCouponAmount.getPrice());
        //减去其它优惠券金额
        newTotalAmount = newTotalAmount.subtract(fullReductionAmount.getPrice());
        newTotalAmount = newTotalAmount.subtract(rateAmount.getPrice());
        newTotalAmount = newTotalAmount.subtract(oneGiftAmount.getPrice());
        newTotalAmount = newTotalAmount.subtract(twoHalfAmount.getPrice());
        if (param.getOriginAmount().subtract(param.getProductCouponDiscountAmount()).subtract(param.getOtherCouponDiscountAmount()).compareTo(newTotalAmount) != 0) {
            log.info("其它优惠券金额不正确：满减金额为：{}，折扣金额为：{}，买一赠一金额为：{}，第二件半价券金额为:{} 传递为：{}",
                    fullReductionAmount.getPrice(), rateAmount.getPrice(), oneGiftAmount.getPrice(), twoHalfAmount.getPrice(), param.getOtherCouponDiscountAmount());
            throw new OrderValidateException("生成支付订单失败，其它优惠券金额不正确");
        }
        if (newTotalAmount.compareTo(BigDecimal.ZERO) <= 0) {
            newTotalAmount = BigDecimal.ZERO;
        }

        //优惠券金额结束
        //餐位费
        orderInfo.setSeatNum(param.getSeatNum());
        if (shopInfo.getIsTableFee() != 1 && shopInfo.getTableFee().compareTo(BigDecimal.ZERO) != 0) {
            orderInfo.setSeatAmount(new BigDecimal(param.getSeatNum()).multiply(shopInfo.getTableFee()));
        } else {
            orderInfo.setSeatAmount(BigDecimal.ZERO);
        }
        //（商品金额+打包费+餐位费）
        newTotalAmount = newTotalAmount.add(packAmount.getPrice()).add(orderInfo.getSeatAmount());
        //填充原价
        orderInfo.setOriginAmount(totalAmount.getPrice().add(packAmount.getPrice()).add(orderInfo.getSeatAmount()));
        //新客立减
        if (shopUser != null) {
            newTotalAmount = newTotalAmount.subtract(param.getNewCustomerDiscountAmount());
        } else {
            param.setNewCustomerDiscountAmount(BigDecimal.ZERO);
        }
        //满减活动
        BigDecimal discountActAmount = calculateDiscountActAmount(orderDetails, discountAct, packAmount.getPrice(), orderInfo.getSeatAmount());
        if (discountActAmount.compareTo(param.getDiscountActAmount()) != 0) {
            log.info("满减活动金额不正确：传递为：{}，计算为：{}", param.getDiscountActAmount(), discountActAmount);
            throw new OrderValidateException("生成支付订单失败，满减活动金额不正确");
        }
        newTotalAmount = newTotalAmount.subtract(discountActAmount);

        //会员整单折扣
        if (shopUser != null && shopUser.getDiscount() != null && shopUser.getDiscount() < 100 && shopUser.getDiscount() > 0) {
            if (param.getVipDiscountAmount().compareTo(BigDecimal.ZERO) <= 0) {
                param.setVipDiscountAmount(BigDecimal.ZERO);
            } else {
                BigDecimal discount = BigDecimal.valueOf(100).subtract(BigDecimal.valueOf(shopUser.getDiscount())).divide(BigDecimal.valueOf(100), 2, RoundingMode.DOWN);
                BigDecimal discountAmount = newTotalAmount.multiply(discount);
                discountAmount = discountAmount.setScale(2, RoundingMode.DOWN);
                if (discountAmount.compareTo(param.getVipDiscountAmount()) != 0) {
                    log.info("会员整单折扣金额不正确：传递为：{}，计算为：{}", param.getVipDiscountAmount(), discountAmount);
                    throw new OrderValidateException("生成支付订单失败，会员整单折扣金额不正确");
                }
                newTotalAmount = newTotalAmount.subtract(discountAmount);
            }
        }
        //积分抵扣 金额范围校验 抵扣金额校验
        if (param.getPointsNum() > 0) {
            if (pointSetting.getMinPaymentAmount().compareTo(newTotalAmount) > 0) {
                throw new OrderValidateException("生成支付订单失败，未满足积分抵扣最低门槛");
            }
            if (pointSetting.getMaxDeductionRatio().multiply(newTotalAmount).compareTo(param.getPointsDiscountAmount()) < 0) {
                throw new OrderValidateException("生成支付订单失败，积分抵扣金额已超出最大抵扣金额");
            }
            BigDecimal pointAmount = new BigDecimal(param.getPointsNum()).divide(new BigDecimal(pointSetting.getEquivalentPoints()), 2, RoundingMode.DOWN);
            if (pointAmount.compareTo(param.getPointsDiscountAmount()) != 0) {
                throw new OrderValidateException("生成支付订单失败，积分抵扣金额不正确");
            }
            newTotalAmount = newTotalAmount.subtract(param.getPointsDiscountAmount());
        }
        //商家最终改价
        if (param.getDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
            newTotalAmount = newTotalAmount.subtract(param.getDiscountAmount());
        }
        //抹零
        newTotalAmount = newTotalAmount.subtract(param.getRoundAmount());
        if (newTotalAmount.compareTo(BigDecimal.ZERO) <= 0) {
            newTotalAmount = BigDecimal.ZERO;
        }
        if (newTotalAmount.compareTo(param.getOrderAmount()) != 0) {
            log.info("""
                              支付计算金额不正确，
                              订单Id:{},支付计算金额为:{},商品总金额:{},临时菜价格:{},打包费:{}，餐位费:{},
                              传递支付金额为:{},商品券:{},其它券:{},新客立减:{},满减活动:{},
                              超级会员折扣金额:{},商家最终改价:{},积分抵扣金额:{},抹零金额:{}
                            """,
                    orderInfo.getId(), newTotalAmount, totalAmount.getPrice(), tempAmount.getPrice(), packAmount.getPrice(), orderInfo.getSeatAmount(),
                    param.getOrderAmount(), param.getProductCouponDiscountAmount(), param.getOtherCouponDiscountAmount(), param.getNewCustomerDiscountAmount(),
                    discountActAmount, param.getVipDiscountAmount(), param.getDiscountAmount(), param.getPointsDiscountAmount(), param.getRoundAmount());
            throw new OrderValidateException("生成支付订单失败，支付金额不正确");
        }
        orderInfo.setPackFee(packAmount.getPrice());
        if (StrUtil.isNotBlank(param.getRemark())) {
            orderInfo.setRemark(param.getRemark());
        }
        //生成订单 //discount_info 所有折扣 几折 折扣金额 满减金额 优惠券金额 积分抵扣金额 抹零
        upOrderPayInfo(orderInfo, param);


        orderDetailService.updateBatch(orderDetails);
        return orderInfo;
    }

    @Override
    @Transactional
    public CzgResult<Object> mergeOrder(MergeOrderDTO param) {
        if (param.getTargetOrderId() == null && StrUtil.isBlank(param.getTargetTableCode())) {
            throw new CzgException("转台失败，请选择目标台桌后转台");
        }
        if (param.getAllMerge() == null) {
            param.setAllMerge(0);
        }
        OrderInfo sourceOrder = orderInfoService.getById(param.getSourceOrderId());
        if (sourceOrder == null || !sourceOrder.getStatus().equals(OrderStatusEnums.UNPAID.getCode())) {
            throw new CzgException("转台失败，无可转订单");
        }
        String sourceTableCode = sourceOrder.getTableCode();
        OrderInfo targetOrder = orderInfoService.getOne(QueryWrapper.create().eq(OrderInfo::getId, param.getTargetOrderId())
                .eq(OrderInfo::getTableCode, param.getTargetTableCode())
                .eq(OrderInfo::getStatus, OrderStatusEnums.UNPAID.getCode()));
        if (targetOrder == null) {
            ShopTable shopTable = shopTableService.getOneByTableCode(sourceOrder.getShopId(), param.getTargetTableCode());
            sourceOrder.setTableCode(shopTable.getTableCode());
            sourceOrder.setTableName(shopTable.getName());
            if (param.getAllMerge() == 1) {
                OrderInfo upOrder = new OrderInfo();
                upOrder.setTableCode(shopTable.getTableCode());
                upOrder.setTableName(shopTable.getName());
                orderInfoService.update(upOrder, new QueryWrapper().eq(OrderInfo::getId, sourceOrder.getId()));
                targetOrder = sourceOrder;
            } else {
                OrderInfoAddDTO addDTO = new OrderInfoAddDTO();
                addDTO.setShopId(sourceOrder.getShopId());
                addDTO.setStaffId(sourceOrder.getStaffId());
                addDTO.setTableCode(param.getTargetTableCode());
                addDTO.setOrderType(sourceOrder.getOrderType());
                addDTO.setPlatformType(sourceOrder.getPlatformType());
                addDTO.setPayMode(sourceOrder.getPayMode());
                addDTO.setDineMode("dine-in");
                addDTO.setPlaceNum(1);
                addDTO.setWaitCall(false);
                addDTO.setVipPrice(false);
                ShopInfo shopInfo = shopInfoService.getById(sourceOrder.getShopId());
                targetOrder = initOrderInfo(addDTO, shopInfo, shopTable);
                OrderDetail orderDetailUp = new OrderDetail();
                orderDetailUp.setOrderId(targetOrder.getId());
                orderDetailUp.setPlaceNum(1);
                QueryWrapper updateWrapper = new QueryWrapper().eq(OrderDetail::getOrderId, sourceOrder.getId());
                if (CollUtil.isNotEmpty(param.getDetailIds())) {
                    updateWrapper.in(OrderDetail::getId, param.getDetailIds());
                }
                orderDetailService.update(orderDetailUp,
                        updateWrapper);
                redisService.set(RedisCst.classKeyExpired.EXPIRED_ORDER + targetOrder.getId(), "", 60 * 15);
            }
        } else {
            targetOrder.setPlaceNum(targetOrder.getPlaceNum() + 1);
            //下单次数+1
            OrderInfo updateTargetOrder = new OrderInfo();
            updateTargetOrder.setPlaceNum(targetOrder.getPlaceNum() + 1);
            orderInfoService.update(updateTargetOrder, new QueryWrapper().eq(OrderInfo::getId, targetOrder.getId()));

            OrderDetail orderDetailUp = new OrderDetail();
            orderDetailUp.setOrderId(targetOrder.getId());
            orderDetailUp.setPlaceNum(targetOrder.getPlaceNum());
            if (CollUtil.isEmpty(param.getDetailIds())) {
                long count = orderDetailService.count(new QueryWrapper().eq(OrderDetail::getOrderId, sourceOrder.getId()));
                if (count < 1) {
                    throw new CzgException("转台失败，该订单无可转商品");
                }
                orderDetailService.update(orderDetailUp, new QueryWrapper().eq(OrderDetail::getOrderId, sourceOrder.getId()));
            } else {
                orderDetailService.update(orderDetailUp,
                        new QueryWrapper().eq(OrderDetail::getOrderId, sourceOrder.getId()).in(OrderDetail::getId, param.getDetailIds()));
            }
            if (param.getAllMerge() == 1) {
                orderInfoService.remove(new QueryWrapper().eq(OrderInfo::getId, sourceOrder.getId()));
            }
        }
        if (param.getAllMerge() == 1) {
            shopTableService.updateStatus(sourceOrder.getShopId(), null, sourceTableCode, ShopTableStatusEnum.IDLE.getValue());
        }
        shopTableService.updateStatus(sourceOrder.getShopId(), null, targetOrder.getTableCode(), ShopTableStatusEnum.UNSETTLED.getValue());
        return CzgResult.success();
    }

    /**
     * 优惠券部分 计算
     */
    private void couponExecute(List<OrderDetail> orderDetails, CheckOrderPay param, BigDecimalDTO totalAmount, BigDecimalDTO tempAmount,
                               BigDecimalDTO prodCouponAmount, BigDecimalDTO oneGiftAmount, BigDecimalDTO twoHalfAmount,
                               BigDecimalDTO rateAmount, BigDecimalDTO fullReductionAmount) throws CzgException {
        if (CollUtil.isNotEmpty(param.getCouponList()) && (!param.isFreeDine() || param.isWithCoupon())) {
            QueryWrapper couponRecordQuery = new QueryWrapper();
            couponRecordQuery.in(MkShopCouponRecord::getId, param.getCouponList());
//            couponRecordQuery.le(MkShopCouponRecord::getUseStartTime, LocalDateTime.now());
//            couponRecordQuery.ge(MkShopCouponRecord::getUseEndTime, LocalDateTime.now());
            couponRecordQuery.eq(MkShopCouponRecord::getStatus, 0);
            couponRecordQuery.ne(MkShopCouponRecord::getIsDel, 1);
            List<MkShopCouponRecord> list = couponRecordService.list(couponRecordQuery);
            if (CollUtil.isEmpty(list) || param.getCouponList().size() > list.size()) {
                throw new OrderValidateException("生成支付订单失败，优惠券不可用");
            }
            Map<Integer, MkShopCouponRecord> couponRecordMap = list.stream().collect(Collectors.toMap(MkShopCouponRecord::getType, t -> t));
            AtomicBoolean otherCouponShare = new AtomicBoolean(true);
            couponRecordMap.forEach((type, record) -> {
                ShopCoupon coupon = checkCoupon(record);
                boolean isTimeDiscountShare = coupon.getDiscountShare() == 1;
                boolean isVipShare = coupon.getVipPriceShare() == 1;
                //1-满减券，2-商品兑换券，3-折扣券，4-第二件半价券， 6-买一送一券，
                //   7-固定价格券，8-免配送费券 暂时没有
                if (type == 2) {//商品券z
                    if (coupon.getOtherCouponShare() != 1) {
                        otherCouponShare.set(false);
                    }
                    thresholdCalculation(orderDetails, coupon.getFullAmount(), true, null,
                            param.isVipPrice(), isTimeDiscountShare, isVipShare, "商品");
                    boolean isAllFoods = true;
                    List<Long> couponFoodIds = new ArrayList<>();
                    if (StrUtil.isNotBlank(coupon.getFoods()) && !",".equals(coupon.getFoods())) {
                        couponFoodIds = Arrays.stream(coupon.getFoods().split(",")).map(Long::parseLong).toList();
                        if (CollUtil.isNotEmpty(couponFoodIds)) {
                            isAllFoods = false;
                        }
                    }
                    foodsCalculate(orderDetails, isTimeDiscountShare,
                            isAllFoods, couponFoodIds, coupon.getDiscountNum(),
                            "price_asc".equals(coupon.getUseRule()), prodCouponAmount);
                } else if (type == 4 || type == 6) {//4-第二件半价券， 6-买一送一券
                    if (!otherCouponShare.get()) {
                        throw new OrderValidateException("生成支付订单失败，商品券与其它券不可共用");
                    }
                    boolean isAllFoods = true;
                    List<Long> couponFoodIds = new ArrayList<>();
                    if (StrUtil.isNotBlank(coupon.getFoods()) && !",".equals(coupon.getFoods())) {
                        couponFoodIds = Arrays.stream(coupon.getFoods().split(",")).map(Long::parseLong).toList();
                        if (CollUtil.isNotEmpty(couponFoodIds)) {
                            isAllFoods = false;
                        }
                    }
                    if (type == 6) {
                        oneGiftCalculate(orderDetails, isAllFoods, couponFoodIds, isTimeDiscountShare, oneGiftAmount);
                    } else {
                        twoHalfCalculate(orderDetails, isAllFoods, couponFoodIds, isTimeDiscountShare, twoHalfAmount);
                    }
                } else if (type == 1 || type == 3) {//1-满减券 3-折扣券
                    if (!otherCouponShare.get()) {
                        throw new OrderValidateException("生成支付订单失败，商品券与其它券不可共用");
                    }
                    //计算门槛
                    boolean isAllFoods = true;
                    List<Long> couponFoodIds = new ArrayList<>();
                    if (StrUtil.isNotBlank(coupon.getFoods()) && !",".equals(coupon.getFoods())) {
                        couponFoodIds = Arrays.stream(coupon.getFoods().split(",")).map(Long::parseLong).toList();
                        if (CollUtil.isNotEmpty(couponFoodIds)) {
                            isAllFoods = false;
                        }
                    }
                    log.info("满减券门槛检验 coupon:{},isAllFoods:{},orderDetails:{},couponFoodIds:{}", coupon, isAllFoods, orderDetails, couponFoodIds);
                    thresholdCalculation(orderDetails, coupon.getFullAmount(), isAllFoods, couponFoodIds,
                            param.isVipPrice(), isTimeDiscountShare, isVipShare, type == 1 ? "满减券" : "折扣券");
                    if (type == 3) {
                        BigDecimal rate = new BigDecimal(100 - record.getDiscountRate());
                        rateAmount.setPrice(rate.multiply(totalAmount.getPrice().subtract(tempAmount.getPrice()).subtract(prodCouponAmount.getPrice()))
                                .divide(BigDecimal.valueOf(100), 2, RoundingMode.DOWN));
                        if (coupon.getMaxDiscountAmount().compareTo(BigDecimal.ZERO) > 0 && rateAmount.getPrice().compareTo(coupon.getMaxDiscountAmount()) > 0) {
                            rateAmount.setPrice(coupon.getMaxDiscountAmount());
                        }
                    } else {
                        fullReductionAmount.setPrice(record.getDiscountAmount());
                    }
                }
            });
        }
        if (prodCouponAmount.getPrice().compareTo(param.getProductCouponDiscountAmount()) != 0) {
            log.info("支付计算金额不正确：商品券抵扣金额为：{}，传递为：{}", prodCouponAmount.getPrice(), param.getProductCouponDiscountAmount());
            throw new OrderValidateException("生成支付订单失败，商品优惠券优惠金额不正确");
        }
    }


    /**
     * 优惠券通用校验规则 不包括门槛校验
     *
     */
    private ShopCoupon checkCoupon(MkShopCouponRecord record) {
        ShopCoupon coupon = couponService.getById(record.getCouponId());
        AssertUtil.isNull(coupon, "生成支付订单失败，券信息不存在");
        isUseLimit(coupon, record);
        return coupon;
    }

    /**
     * 判断每日使用限量
     */
    private void isUseLimit(ShopCoupon coupon, MkShopCouponRecord record) {
        if (coupon.getUseLimit() != MarketConstants.Num.NOT_LIMIT) {
            long useNum = couponRecordService.count(new QueryWrapper()
                    .eq(MkShopCouponRecord::getCouponId, coupon.getId())
                    .eq(MkShopCouponRecord::getShopId, record.getShopId())
                    .eq(MkShopCouponRecord::getUserId, record.getUserId())
                    .eq(MkShopCouponRecord::getStatus, 1)
                    .between(MkShopCouponRecord::getUseTime, LocalDateTime.now().with(LocalTime.MIN), LocalDateTime.now().with(LocalTime.MAX))
            );
            if (useNum >= coupon.getUseLimit()) {
                throw new CzgException("优惠券:" + coupon.getTitle() + " 已达到今日使用限量");
            }
        }
    }

    /**
     * 使用优惠券时段校验
     */
    private void isUseTime(ShopCoupon coupon) {
        if (!coupon.getUseDays().contains(CzgStrUtils.getStrWeek())) {
            throw new CzgException("生成支付订单失败," + coupon.getTitle() + " 今天不可用");
        }
        if (!"all".equals(coupon.getUseTimeType())) {
            // 获取当前时间（仅包含时分秒）
            LocalTime currentTime = LocalTime.now();
            LocalTime startTime = coupon.getUseStartTime().toLocalTime();
            LocalTime endTime = coupon.getUseEndTime().toLocalTime();
            if (currentTime.isBefore(startTime)) {
                if (startTime.isBefore(endTime)) {
                    throw new CzgException("生成支付订单失败,优惠券:" + coupon.getTitle() + " 当前时段不可用");
                } else if (currentTime.isAfter(endTime)) {
                    throw new CzgException("生成支付订单失败,优惠券:" + coupon.getTitle() + " 当前时段不可用");
                }
            } else if (startTime.isBefore(endTime)) {
                if (currentTime.isAfter(endTime)) {
                    throw new CzgException("生成支付订单失败,优惠券:" + coupon.getTitle() + " 当前时段不可用");
                }
            }
        }
    }

    /**
     * 优惠券 门槛 计算 赠送商品和临时商品不参与计算
     *
     * @param orderDetails        订单商品列表
     * @param isAllFoods          是否所有商品
     * @param couponFoodIds       参与门槛计算商品id列表
     * @param fullAmount          门槛金额
     * @param isVipPrice          是否使用会员价
     * @param isTimeDiscountShare 门槛计算是否限时折扣共享
     * @param isVipShare          门槛计算是否与会员价共享
     */
    private void thresholdCalculation(List<OrderDetail> orderDetails, BigDecimal fullAmount, boolean isAllFoods, List<Long> couponFoodIds,
                                      boolean isVipPrice, boolean isTimeDiscountShare, boolean isVipShare, String title) throws CzgException {
        BigDecimal calculationAmount = BigDecimal.ZERO;
        for (OrderDetail orderDetail : orderDetails) {
            if (orderDetail.getIsGift() == 1 || orderDetail.getIsTemporary() == 1) {
                continue;
            }
            if (!isAllFoods) {
                if (CollUtil.isEmpty(couponFoodIds) || !couponFoodIds.contains(orderDetail.getProductId())) {
                    continue;
                }
            }
            BigDecimal num = orderDetail.getNum().subtract(orderDetail.getReturnNum());
            if (orderDetail.getDiscountSaleAmount().compareTo(BigDecimal.ZERO) > 0) {
                //单品改价 按原价计算门槛金额
                calculationAmount = calculationAmount.add(orderDetail.getPrice().multiply(num).setScale(2, RoundingMode.HALF_UP));
            } else {
                if (orderDetail.getIsTimeDiscount() == 1 && isTimeDiscountShare) {
                    calculationAmount = calculationAmount.add(orderDetail.getUnitPrice().multiply(num).setScale(2, RoundingMode.HALF_UP));
                } else if (isVipPrice && orderDetail.getMemberPrice().compareTo(BigDecimal.ZERO) > 0 && isVipShare) {
                    calculationAmount = calculationAmount.add(orderDetail.getUnitPrice().multiply(num).setScale(2, RoundingMode.HALF_UP));
                } else if ((!isVipPrice || orderDetail.getMemberPrice().compareTo(BigDecimal.ZERO) <= 0) && orderDetail.getIsTimeDiscount() == 0) {
                    calculationAmount = calculationAmount.add(orderDetail.getPrice().multiply(num).setScale(2, RoundingMode.HALF_UP));
                }
            }
            log.info("优惠券门槛金额 calculationAmount:{}", calculationAmount);
        }
        if (calculationAmount.compareTo(fullAmount) < 0) {
            throw new CzgException("生成支付订单失败," + title + "优惠券门槛金额不足");
        }
    }

    /**
     * 商品优惠券计算
     */
    private void foodsCalculate(List<OrderDetail> orderDetails, boolean isTimeDiscountShare,
                                boolean isAllFoods, List<Long> couponFoodIds, int discountNum,
                                boolean isAsc, BigDecimalDTO prodCouponAmount) {
        orderDetails = getDetailsSort(orderDetails, isAsc);
//        log.info("商品券 计算 orderDetails:{}", orderDetails);
        BigDecimal remaining = new BigDecimal(discountNum);
        for (OrderDetail detail : orderDetails) {
            if (detail.getIsTemporary() != 1 && (isAllFoods || (CollUtil.isNotEmpty(couponFoodIds) && couponFoodIds.contains(detail.getProductId()))) && detail.getUnitPrice().compareTo(BigDecimal.ZERO) > 0) {
                if (remaining.compareTo(BigDecimal.ZERO) > 0) {
//                    if (isTimeDiscountShare && detail.getIsTimeDiscount() == 1) {
//                        continue;
//                    }
                    if (remaining.compareTo(detail.getNum().subtract(detail.getReturnNum())) >= 0) {
                        detail.setCouponNum(detail.getNum().subtract(detail.getReturnNum()).setScale(2, RoundingMode.CEILING));
                        detail.setDiscountAmount(detail.getPayAmount());
                        detail.setPayAmount(BigDecimal.ZERO);
                        remaining = remaining.subtract(detail.getNum().subtract(detail.getReturnNum()).setScale(2, RoundingMode.CEILING));
                    } else {
                        detail.setCouponNum(remaining);
                        detail.setDiscountAmount(remaining.multiply(detail.getUnitPrice()).setScale(2, RoundingMode.DOWN));
                        detail.setPayAmount(detail.getPayAmount().subtract(detail.getDiscountAmount()));
                        remaining = BigDecimal.ZERO;
                    }
                    prodCouponAmount.setPrice(prodCouponAmount.getPrice().add(detail.getDiscountAmount()));
                }
            }
//            log.info("商品券 计算 已经抵扣金额：{} ,剩余可抵扣数量:{}", prodCouponAmount.getPrice(), remaining);
            if (remaining.compareTo(BigDecimal.ZERO) <= 0) {
                break;
            }
        }
    }

    /**
     * 买一送一优惠券计算
     */
    private void oneGiftCalculate(List<OrderDetail> orderDetails, boolean isAllFoods, List<Long> couponFoodIds,
                                  boolean isAsc, BigDecimalDTO oneGiftAmount) {
        orderDetails = getDetailsSort(orderDetails, isAsc);
        for (OrderDetail detail : orderDetails) {
            if ((isAllFoods || couponFoodIds.contains(detail.getProductId()))
                    && detail.getUnitPrice().compareTo(BigDecimal.ZERO) > 0
                    && detail.getNum().subtract(detail.getReturnNum()).subtract(detail.getCouponNum()).compareTo(BigDecimal.TWO) >= 0) {
                detail.setCouponNum(detail.getCouponNum().add(BigDecimal.ONE));
                detail.setDiscountAmount(detail.getDiscountAmount().add(detail.getUnitPrice()));
                detail.setPayAmount(detail.getPayAmount().subtract(detail.getUnitPrice()));
                oneGiftAmount.setPrice(detail.getUnitPrice());
                return;
            }
        }
    }

    /**
     * 第二件半价优惠券计算
     */
    private void twoHalfCalculate(List<OrderDetail> orderDetails, boolean isAllFoods, List<Long> couponFoodIds,
                                  boolean isAsc, BigDecimalDTO oneGiftAmount) {
        orderDetails = getDetailsSort(orderDetails, isAsc);
        for (OrderDetail detail : orderDetails) {
            if ((isAllFoods || couponFoodIds.contains(detail.getProductId()))
                    && detail.getUnitPrice().compareTo(BigDecimal.ZERO) > 0
                    && detail.getNum().subtract(detail.getReturnNum()).subtract(detail.getCouponNum()).compareTo(BigDecimal.TWO) >= 0) {

                detail.setHalfPriceCouponNum(BigDecimal.ONE);
                BigDecimal halfPrice = detail.getUnitPrice().divide(new BigDecimal("2"), 2, RoundingMode.FLOOR);
                detail.setDiscountAmount(detail.getDiscountAmount().add(halfPrice));
                detail.setPayAmount(detail.getPayAmount().subtract(halfPrice));
                oneGiftAmount.setPrice(halfPrice);
                return;
            }
        }
    }

    /**
     * 获取价格排序后的orderDetail
     *
     * @param isAsc true为升序
     */
    private List<OrderDetail> getDetailsSort(List<OrderDetail> orderDetails, boolean isAsc) {
        if (isAsc) {
            return orderDetails.stream()
                    .sorted(Comparator.comparing(OrderDetail::getUnitPrice))
                    .toList();
        } else {
            return orderDetails.stream()
                    .sorted(Comparator.comparing(OrderDetail::getUnitPrice).reversed())
                    .toList();
        }
    }

    /**
     * 满减活动 校验门槛获取减免金额
     */
    private BigDecimal calculateDiscountActAmount(List<OrderDetail> orderDetails, MkDiscountActivityDTO discountAct, BigDecimal packPrice, BigDecimal seatPrice) {
        if (discountAct == null) {
            return BigDecimal.ZERO;
        }
        BigDecimal originalPrice = BigDecimal.ZERO;
        for (OrderDetail orderDetail : orderDetails) {
            if (orderDetail.getIsGift() == 1 || orderDetail.getIsTemporary() == 1) {
                continue;
            }
            if (orderDetail.getDiscountSaleAmount().compareTo(BigDecimal.ZERO) > 0) {
                BigDecimal num = orderDetail.getNum().subtract(orderDetail.getReturnNum());
                //单品改价 按原价计算门槛金额
                originalPrice = originalPrice.add(orderDetail.getPrice().multiply(num).setScale(2, RoundingMode.HALF_UP));
            } else {
                originalPrice = originalPrice.add(orderDetail.getPayAmount());
            }
        }
        originalPrice = originalPrice.add(packPrice).add(seatPrice);
        for (MkDiscountThreshold threshold : discountAct.getThresholds()) {
            if (originalPrice.compareTo(threshold.getFullAmount()) >= 0) {
                return threshold.getDiscountAmount();
            }
        }
        return BigDecimal.ZERO;
    }

    @Override
    public void getOrderAmount(List<OrderDetail> orderDetails, BigDecimalDTO totalAmount, BigDecimalDTO packAmount,
                               BigDecimalDTO tempAmount, LimitRateDTO limitRate, boolean isAllPack, Integer userAllPack, boolean isVipPrice) {
        for (OrderDetail orderDetail : orderDetails) {
            if (orderDetail.getIsGift() == 1) {
                orderDetail.setUnitPrice(BigDecimal.ZERO);
            } else if (orderDetail.getDiscountSaleAmount() != null && orderDetail.getDiscountSaleAmount().compareTo(BigDecimal.ZERO) > 0) {
                orderDetail.setUnitPrice(orderDetail.getDiscountSaleAmount());
            } else {
                if (orderDetail.getIsTimeDiscount() == 1) {
                    if (limitRate == null || (limitRate.getFoodType() == 2 && CollUtil.isEmpty(limitRate.getFoodIds()))) {
                        throw new OrderValidateException("限时折扣使用失败,商品范围不正确");
                    }
                    if (limitRate.getFoodType() == 2 && !limitRate.getFoodIds().contains(orderDetail.getProductId())) {
                        throw new OrderValidateException("限时折扣使用失败,商品" + orderDetail.getProductName() + "不享受限时折扣");
                    }
                    if (orderDetail.getPrice().compareTo(BigDecimal.ZERO) == 0) {
                        orderDetail.setUnitPrice(orderDetail.getPrice());
                    } else {
                        // 确保最终结果保留两位小数并向上取整
                        orderDetail.setUnitPrice(
                                orderDetail.getPrice()
                                        .multiply(new BigDecimal(limitRate.getDiscountRate()).divide(new BigDecimal("100"), 2, RoundingMode.CEILING))
                                        .setScale(2, RoundingMode.CEILING)
                        );
                    }
                } else {
                    if (isVipPrice) {
                        orderDetail.setUnitPrice(
                                (orderDetail.getMemberPrice() == null || orderDetail.getMemberPrice().compareTo(BigDecimal.ZERO) <= 0)
                                        ? orderDetail.getPrice() : orderDetail.getMemberPrice());
                    } else {
                        orderDetail.setUnitPrice(orderDetail.getPrice());
                    }
                }
            }
            if (userAllPack != null) {
                if (userAllPack.equals(1)) {
                    orderDetail.setPackNumber(orderDetail.getNum().subtract(orderDetail.getReturnNum()));
                    if ("weight".equals(orderDetail.getProductType())) {
                        orderDetail.setPackNumber(BigDecimal.ONE);
                    }
                } else {
                    orderDetail.setPackNumber(BigDecimal.ZERO);
                }
            } else if (isAllPack) {
                if ("weight".equals(orderDetail.getProductType())) {
                    orderDetail.setPackNumber(BigDecimal.ONE);
                } else {
                    orderDetail.setPackNumber(orderDetail.getNum().subtract(orderDetail.getReturnNum()));
                }
            } else {
                if ("weight".equals(orderDetail.getProductType()) && orderDetail.getPackNumber() != null && orderDetail.getPackNumber().compareTo(BigDecimal.ZERO) > 0) {
                    orderDetail.setPackNumber(BigDecimal.ONE);
                }
            }
            orderDetail.setCouponNum(BigDecimal.ZERO);
            orderDetail.setPayAmount((orderDetail.getNum().subtract(orderDetail.getReturnNum())).multiply(orderDetail.getUnitPrice()).setScale(2, RoundingMode.DOWN));
            if (orderDetail.getIsTemporary() == 1) {
                tempAmount.setPrice(tempAmount.getPrice().add(orderDetail.getPayAmount()));
            }
            packAmount.setPrice(packAmount.getPrice().add(orderDetail.getPackAmount().multiply(orderDetail.getPackNumber()).setScale(2, RoundingMode.DOWN)));
            totalAmount.setPrice(totalAmount.getPrice().add(orderDetail.getPayAmount()));
        }
    }


    /**
     * 填充 单价/付款金额
     *
     * @param orderDetails 订单详情 需要回填
     */
    private void processOrderDetails(List<OrderDetail> orderDetails, LimitRateDTO limitRate, OrderInfoAddDTO param) throws CzgException {
        BigDecimal packFee = BigDecimal.ZERO;
        Map<Long, BigDecimal> productNumMap = new HashMap<>();
        for (OrderDetail detail : orderDetails) {
            if (!detail.getIsTemporary().equals(1) && detail.getProductId() > 0 && 1 == detail.getIsAutoSoldStock()) {
                if (productNumMap.containsKey(detail.getProductId())) {
                    productNumMap.put(detail.getProductId(), productNumMap.get(detail.getProductId()).add(detail.getNum().subtract(detail.getReturnNum())));
                } else {
                    productNumMap.put(detail.getProductId(), detail.getNum().subtract(detail.getReturnNum()));
                }
            }
            if (detail.getDiscountSaleAmount() != null && detail.getDiscountSaleAmount().compareTo(BigDecimal.ZERO) > 0) {
                detail.setUnitPrice(detail.getDiscountSaleAmount());
            } else {
                if (detail.getIsTimeDiscount() == 1) {
                    if (limitRate == null || (limitRate.getFoodType() == 2 && CollUtil.isEmpty(limitRate.getFoodIds()))) {
                        throw new CzgException("限时折扣使用失败,商品范围不正确");
                    }
                    if (limitRate.getFoodType() == 2 && !limitRate.getFoodIds().contains(detail.getProductId())) {
                        throw new CzgException("限时折扣使用失败,商品" + detail.getProductName() + "不享受限时折扣");
                    }
                }
                detail.setUnitPrice(detail.getPrice());
            }
            detail.setPayAmount(detail.getNum().multiply(detail.getUnitPrice()));
            packFee = packFee.add(detail.getPackAmount().multiply(detail.getPackNumber()));
        }
        if (CollUtil.isNotEmpty(productNumMap)) {
            checkStock(param.getShopId(), productNumMap);
        }
        param.setPackFee(packFee);
    }

    /**
     * 校验库存数
     *
     * @param productNumMap 商品Id ，使用数量
     */
    private void checkStock(Long shopId, Map<Long, BigDecimal> productNumMap) {
        if (CollUtil.isEmpty(productNumMap)) {
            return;
        }
        List<ConsStockRecord> consNumList = orderInfoCustomMapper.getConsByProductAndNum(shopId, productNumMap);
        for (ConsStockRecord consStockRecord : consNumList) {
            if (consStockRecord.getStockNumber().compareTo(consStockRecord.getCurrentStockNumber()) > 0) {
                throw new CzgException("耗材：" + consStockRecord.getConName() + "库存不足，当前库存：" + consStockRecord.getCurrentStockNumber());
            }
        }
    }

    @Override
    @Transactional
    public void payCallBackOrder(@NotBlank String orderNo, @NotNull PayNotifyRespDTO notifyRespDTO, String channel, int retryCount) {
        OrderPayment payment = paymentService.getOne(new QueryWrapper().eq(OrderPayment::getOrderNo, orderNo));
        if (payment == null) {
            if (retryCount < MAX_RETRIES) {
                log.info("支付记录不存在，第 {} 次重试，将在 {} 秒后进行", retryCount + 1, DELAY);
                executorService.schedule(() -> payCallBackOrder(orderNo, notifyRespDTO, channel, retryCount + 1), DELAY, TimeUnit.SECONDS);
            } else {
                log.error("订单支付回调失败, 达到最大重试次数, 支付记录不存在, orderNo: {}", orderNo);
            }
            return;
        }
        if (StrUtil.isNotBlank(payment.getTradeNumber())) {
            log.info("订单处理过，payment id：{}", payment.getId());
            return;
        }
        payment.setTradeNumber(notifyRespDTO.getThirdOrderNo());
        payment.setRespJson(notifyRespDTO.getOriginalData());
        payment.setPayStatus(PayTypeConstants.PayStatus.FAIL);
        payment.setPlatformType(notifyRespDTO.getPlatform());
        payment.setChannel(channel);
        payment.setPayTime(LocalDateTimeUtil.parse(notifyRespDTO.getPaySuccessTime(), "yyyy-MM-dd HH:mm:ss"));
        if ("TRADE_SUCCESS".equals(notifyRespDTO.getStatus())) {
            payment.setPayStatus(PayTypeConstants.PayStatus.SUCCESS);
            if (PayTypeConstants.SourceType.ORDER.equals(payment.getSourceType())) {
                OrderInfo orderInfo = orderInfoService.getById(payment.getSourceId());
                if (orderInfo == null) {
                    log.error("订单支付回调失败,订单不存在,支付记录Id,{}", payment.getId());
                    return;
                }
                upOrderInfo(orderInfo, new BigDecimal(notifyRespDTO.getAmount()).divide(new BigDecimal(100), 2, RoundingMode.DOWN),
                        DateUtil.parseLocalDateTime(notifyRespDTO.getPaySuccessTime()), payment.getId(), null);
                if (orderInfo.getUserId() != null) {
                    // 分销员升级等级
                    distributionUserService.costUpgradeLevelBefore(orderInfo.getUserId(), orderInfo.getShopId());
                    // 分销奖励
                    distributionUserService.distribute(orderInfo.getId(), orderInfo.getOrderNo(), payment.getAmount(), orderInfo.getUserId(), orderInfo.getShopId(), "order");
                }
            } else if (PayTypeConstants.SourceType.FREE.equals(payment.getSourceType())) {
                ShopUser shopUser = shopUserService.getById(payment.getSourceId());
                if (shopUser == null) {
                    log.error("霸王餐回调失败，会员不存在，会员id：{}", payment.getSourceId());
                } else {
                    OrderInfo orderInfo = orderInfoService.getOne(new QueryWrapper().eq(OrderInfo::getId, payment.getRelatedId()));
                    if (orderInfo == null) {
                        log.error("霸王餐支付，订单不存在，支付记录Id,{}", payment.getId());
                    } else {
                        //增加余额
                        ShopUserMoneyEditDTO shopUserMoneyEditDTO = new ShopUserMoneyEditDTO()
                                .setId(shopUser.getId()).setType(1)
                                .setBizEnum(ShopUserFlowBizEnum.FREE_IN)
                                .setRelationId(orderInfo.getId())
                                .setMoney(BigDecimal.valueOf(notifyRespDTO.getAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.DOWN));
                        shopUserService.updateMoney(shopUserMoneyEditDTO);
                        upOrderInfo(orderInfo, BigDecimal.ZERO, LocalDateTime.now(), null, PayEnums.FREE_PAY);
                    }
                }
            } else if (PayTypeConstants.SourceType.MEMBER_IN.equals(payment.getSourceType())) {
                ShopUser shopUser = shopUserService.getById(payment.getSourceId());
                if (shopUser == null) {
                    log.error("会员充值失败，会员不存在，会员id：{}", payment.getSourceId());
                } else {
                    ShopUserFlowBizEnum bizEnum;
                    if ("WECHAT".equals(notifyRespDTO.getPlatform())) {
                        bizEnum = ShopUserFlowBizEnum.WECHAT_IN;
                    } else if ("ALIPAY".equals(notifyRespDTO.getPlatform())) {
                        bizEnum = ShopUserFlowBizEnum.ALIPAY_IN;
                    } else {
                        bizEnum = ShopUserFlowBizEnum.CASH_IN;
                    }
                    //充值并支付 ↓
                    OrderInfo orderInfo = orderInfoService.getOne(new QueryWrapper()
                            .eq(OrderInfo::getPayOrderId, payment.getId())
                            .eq(OrderInfo::getPayType, PayEnums.VIP_PAY.getValue()));
                    if (orderInfo != null) {
                        ShopUserMoneyEditDTO shopUserMoneyEditDTO = new ShopUserMoneyEditDTO()
                                .setId(shopUser.getId()).setType(0)
                                .setBizEnum(ShopUserFlowBizEnum.ORDER_PAY)
                                .setRelationId(orderInfo.getId())
                                .setMoney(orderInfo.getOrderAmount());
                        shopUserService.updateMoney(shopUserMoneyEditDTO);
                        upOrderInfo(orderInfo, orderInfo.getOrderAmount(), LocalDateTime.now(), null, PayEnums.VIP_PAY);
                    }
                    shopRechargeService.recharge(payment.getShopId(), payment.getSourceId(), payment.getRelatedId(),
                            BigDecimal.valueOf(notifyRespDTO.getAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.DOWN),
                            payment.getId(), payment.getSourceType(), payment.getPayTime(), bizEnum, orderInfo == null, null);
                }
            } else if (PayTypeConstants.SourceType.MEMBER_PAY.equals(payment.getSourceType())) {
                //购买会员
                ShopUser shopUser = shopUserService.getById(payment.getSourceId());
                memberConfigService.joinMember(payment.getShopId(), shopUser.getUserId(), payment.getRelatedId());
            } else if (PayTypeConstants.SourceType.DISTRIBUTION.equals(payment.getSourceType())) {
                distributionUserService.open(payment.getSourceId(), payment.getAmount(), payment.getShopId(), payment.getId());
            } else if (PayTypeConstants.SourceType.POINT.equals(payment.getSourceType())) {
                goodPayService.payCallBack(payment.getSourceId(), payment.getId());
            } else if (PayTypeConstants.SourceType.WARE.equals(payment.getSourceType())) {
                gbOrderService.payCallBack(payment.getSourceId(), payment.getId());
            } else if (PayTypeConstants.SourceType.PP.equals(payment.getSourceType())) {
                ppPackageOrderService.paySuccess(payment.getSourceId(), payment.getId());
            }
        }
        paymentService.updateById(payment);
    }

    @Override
    public void refundCallBackOrder(@NotBlank String orderNo, @NotNull JSONObject resultJson) {
        CzgRefundNotifyDTO czgCallBackDto = JSONObject.parseObject(resultJson.toString(), CzgRefundNotifyDTO.class);
        OrderPayment payment = paymentService.queryChain().eq(OrderPayment::getOrderNo, orderNo).one();
        if (StrUtil.isNotBlank(payment.getTradeNumber())) {
            log.info("订单处理过，payment id：{}", payment.getId());
            return;
        }
        payment.setPayStatus(PayTypeConstants.PayStatus.SUCCESS);
        if (!"SUCCESS".equals(czgCallBackDto.getState())) {
            payment.setPayStatus(PayTypeConstants.PayStatus.FAIL);
            if ("refund".equals(payment.getPayType())) {
                //TODO 订单退款失败 暂不考虑回滚 填充退款原因
                orderInfoService.updateById(new OrderInfo()
                        .setId(payment.getSourceId())
                        .setRefundRemark(czgCallBackDto.getRefundReason()));
            } else if ("memberRefund".equals(payment.getPayType())) {
                //TODO 会员退款  暂不考虑回滚(钱 赠送金额 赠送的券) 填充退款原因
                flowService
                        .updateChain()
                        .set(ShopUserFlow::getFailMsg, czgCallBackDto.getRefundReason())
                        .eq(ShopUserFlow::getId, payment.getSourceId()).update();
            }
        }
        paymentService.updateChain()
                .set(OrderPayment::getTradeNumber, czgCallBackDto.getRefundOrderId())
                .set(OrderPayment::getRespJson, resultJson.toString())
                .set(OrderPayment::getPayTime, czgCallBackDto.getRefundTime())
                .set(OrderPayment::getPayStatus, payment.getPayStatus())
                .where(OrderPayment::getId).eq(payment.getId())
                .update();
    }


    /**
     * 更新订单信息 (支付成功后调用)
     *
     * @param payAmount  注意是分 还是元
     * @param payTime    支付时间
     * @param payOrderId 支付订单号
     *                   现金支付为空
     *                   会员支付为tb_shop_user_flow.id
     *                   其它支付为 tb_order_payment.id
     */
    @Override
    @Transactional
    public void upOrderInfo(OrderInfo orderInfo, BigDecimal payAmount, LocalDateTime payTime, Long payOrderId, PayEnums payType) {
        if (orderInfo.getStatus().equals(OrderStatusEnums.DONE.getCode())) {
            log.info("订单{}已完成，不再更新", orderInfo.getId());
            return;
        }
        OrderInfo upOrderInfo = new OrderInfo()
                .setId(orderInfo.getId())
                .setPayAmount(payAmount)
                .setPaidTime(payTime)
                .setRemark(orderInfo.getRemark())
                .setStatus(OrderStatusEnums.DONE.getCode());
        if (payOrderId != null) {
            upOrderInfo.setPayOrderId(payOrderId);
            orderInfo.setPayOrderId(payOrderId);
        }
        if (orderInfo.getCreditBuyerId() != null) {
            upOrderInfo.setCreditBuyerId(orderInfo.getCreditBuyerId());
        }
        if (PayEnums.FREE_PAY.equals(payType)) {
            if (orderInfo.getDiscountAllAmount() == null) {
                upOrderInfo.setDiscountAllAmount(orderInfo.getOrderAmount());
            } else {
                upOrderInfo.setDiscountAllAmount(orderInfo.getDiscountAllAmount().add(orderInfo.getOrderAmount()));
            }
        }
        if (ObjectUtil.isNotNull(payType)) {
            upOrderInfo.setPayType(payType.getValue());
            orderInfo.setPayType(payType.getValue());
        }
        boolean update = orderInfoService.updateById(upOrderInfo);
        if (update) {
            orderInfo.setPayAmount(payAmount);
            orderInfo.setStatus(OrderStatusEnums.DONE.getCode());
            orderInfo.setPaidTime(payTime);
        }
        orderDetailService.updateOrderDetailStatus(orderInfo.getId(), OrderStatusEnums.DONE.getCode());

        // 保存消息参数（避免闭包中引用的变量被修改）
        final Long orderId = orderInfo.getId();
        final String payMode = orderInfo.getPayMode();

        // 【关键改造】注册事务同步器，在事务提交后发送消息
        if (TransactionSynchronizationManager.isSynchronizationActive()) {
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    if (orderInfo.getUserId() != null) {
                        ThreadUtil.execAsync(() -> exShopUserInfo(orderInfo));
                    }
                    if (StrUtil.isNotBlank(orderInfo.getTableCode())) {
                        ThreadUtil.execAsync(() -> exTable(orderInfo));
                    }
                    if (payType != PayEnums.BACK_SCAN) {
                        // 事务成功提交后执行消息发送
                        rabbitPublisher.sendOrderPrintMsg(orderId, !"after-pay".equals(payMode) ? 1 : 0, 1, 1, "事务环境打印");
                    }
                }
            });
        } else {
            if (payType != PayEnums.BACK_SCAN) {
                // 非事务环境下直接发送（兼容无事务场景）
                rabbitPublisher.sendOrderPrintMsg(orderId, !"after-pay".equals(payMode) ? 1 : 0, 1, 1, "非事务环境打印");

            }
//            log.info("非事务环境下，直接发送订单{}打印消息", orderId);
        }
        rabbitPublisher.sendOrderDetailStatusMsg(orderInfo.getShopId().toString(), "bc");
        redisService.del(RedisCst.classKeyExpired.EXPIRED_ORDER + orderInfo.getId());
    }

    //订单回调后 跟用户相关的部分
//    @Async
    public void exShopUserInfo(OrderInfo orderInfo) {
        ShopUser shopUser = shopUserService.getShopUserInfo(orderInfo.getShopId(), orderInfo.getUserId());
        if (shopUser == null) {
            if ((orderInfo.getPointsNum() != null && orderInfo.getPointsNum() > 0) || (StrUtil.isNotBlank(orderInfo.getCouponInfoList()) && !"null".equals(orderInfo.getCouponInfoList()))) {
                log.error("订单积分使用或优惠券扣除失败，订单id：{}", orderInfo.getId());
            }
            return;
        }
        //使用内容的 执行
        shopUserUseInfo(orderInfo, shopUser);
        // 后续 赠送等功能 挂账支付不赠送
        if (!orderInfo.getPayType().equals(PayEnums.CREDIT_PAY.getValue())) {
            if (!orderInfo.getPayType().equals(PayEnums.FREE_PAY.getValue())) {
                FunUtils.safeRunVoid(() -> consumerCouponService.receiveConsumerCoupon(shopUser.getSourceShopId(), orderInfo.getId(),
                        orderInfo.getPayAmount(), shopUser.getUserId(), shopUser.getId()), "订单{}消费赠券失败", orderInfo.getId());
                FunUtils.safeRunVoid(() -> pointsConfigService.consumeAwardPoints(shopUser, orderInfo), "订单{}赠送积分失败", orderInfo.getId());

                FunUtils.safeRunVoid(() -> consumeCashbackService.cashback(orderInfo.getShopId(), shopUser.getUserId(),
                        orderInfo.getPayAmount(), orderInfo.getId(), orderInfo.getOrderNo()), "订单{}消费返现失败", orderInfo.getId());
            }
            FunUtils.safeRunVoid(() -> {
                if (shopUser.getIsVip().equals(0)) {
                    // 消费累计成为会员的情况
                    memberConfigService.joinMemberByCondition(orderInfo.getShopId(), orderInfo.getUserId(), shopUser);
                }
                memberConfigService.deliver(shopUser, TableValueConstant.MemberExpFlow.Type.COST, orderInfo.getPayAmount(), null, orderInfo.getId());
            }, "订单{}用户累计/赠送成长值失败", orderInfo.getId());
        }
    }

    public void shopUserUseInfo(OrderInfo orderInfo, ShopUser shopUser) {
        //新客立减
        if (orderInfo.getNewCustomerDiscountAmount() != null && orderInfo.getNewCustomerDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
            newConsumerDiscountRecordService.useDiscount(shopUser.getId(), orderInfo.getId(), orderInfo.getNewCustomerDiscountAmount());
        }
        //积分使用
        if (orderInfo.getPointsNum() != null && orderInfo.getPointsNum() > 0) {
            pointsUserService.alterPoints(null, shopUser.getId(), orderInfo.getShopId(), PointsConstant.SUB,
                    orderInfo.getPointsNum(), orderInfo.getId(), "积分抵扣");
        }
        //更新优惠券信息
        if (StrUtil.isNotBlank(orderInfo.getCouponInfoList()) && !"null".equals(orderInfo.getCouponInfoList())) {
            //券消耗
            List<Long> coupons = JSON.parseArray(orderInfo.getCouponInfoList(), Long.class);
            if (CollUtil.isNotEmpty(coupons)) {
                couponService.use(coupons, shopUser.getId(), orderInfo.getId());
            }
        }
    }

    public void exTable(OrderInfo orderInfo) {
        ShopTable table = shopTableService.getOneByTableCode(orderInfo.getShopId(), orderInfo.getTableCode());
        if (table != null) {
            ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
            if ("auto".equals(shopInfo.getTableClearType())) {
                table.setStatus(ShopTableStatusEnum.IDLE.getValue());
            } else {
                DateTime dateTime = DateUtil.offsetMinute(DateUtil.date(), shopInfo.getTableClearTime());
                table.setCreateTime(LocalDateTimeUtil.of(dateTime));
                redisService.set(RedisCst.classKeyExpired.EXPIRED_TABLE + table.getId(), "", 60L * shopInfo.getTableClearTime());
            }
            shopTableService.updateById(table);
        }
    }

    /**
     * 订单到期
     */
    @Override
    @Transactional
    public void expired(Long orderId) {
        OrderInfo orderInfo = orderInfoService.getById(orderId);
        if (orderInfo == null) {
            log.info("订单取消失败,订单Id:{} 为空", orderId);
            return;
        }
        if (orderInfo.getStatus().equals(OrderStatusEnums.UNPAID.getCode())) {
            orderInfoService.updateById(new OrderInfo().setId(orderId).setStatus(OrderStatusEnums.CANCELLED.getCode()));
            if (StrUtil.isNotBlank(orderInfo.getTableCode())) {
                ShopTable table = shopTableService.getOneByTableCode(orderInfo.getShopId(), orderInfo.getTableCode());
                if (table != null) {
                    table.setStatus(ShopTableStatusEnum.IDLE.getValue());
                    shopTableService.updateById(table);
                }
            }
            rabbitPublisher.sendOrderCancelMsg(orderId.toString());
        } else {
            log.info("订单取消失败,订单Id:{},订状态:{}", orderInfo.getId(), orderInfo.getStatus());
        }
    }

    /**
     * 支付使用的空订单
     */
    @Override
    public OrderInfo createPayOrder(Long shopId, BigDecimal amount, String remark) {
        ShopInfo shopInfo = shopInfoService.getById(shopId);
        OrderInfoAddDTO param = new OrderInfoAddDTO();
        param.setShopId(shopInfo.getId());
        param.setUserId(0L);
        param.setStaffId(0L);
        param.setSeatNum(0);
        param.setOriginAmount(amount);
        param.setOrderAmount(amount);
        param.setTableCode("");
        param.setOrderType("cash");
        param.setPlatformType("H5");
        param.setPayMode("no-table");
        param.setDineMode("dine-in");
        param.setRemark(remark);
        param.setPlaceNum(1);
        param.setCreditBuyerId(null);
        param.setWaitCall(false);
        param.setVipPrice(false);
        param.setPackFee(BigDecimal.ZERO);
        OrderInfo orderInfo = initOrderInfo(param, shopInfo, null);
        redisService.set(RedisCst.classKeyExpired.EXPIRED_ORDER + orderInfo.getId(), "", 60 * 15);
        return orderInfo;
    }

    /**
     * 初始化订单信息
     */
    private OrderInfo initOrderInfo(OrderInfoAddDTO param, ShopInfo shopInfo, ShopTable table) throws CzgException {
        OrderInfo orderInfo = new OrderInfo();
        if (param.getOrderId() != null) {
            orderInfo = orderInfoService.getById(param.getOrderId());
            if (!OrderStatusEnums.UNPAID.getCode().equals(orderInfo.getStatus())) {
                throw new CzgException("生成订单失败，订单已结束，请重新下单");
            }
        } else {
            orderInfo.setOrderNo(param.getPlatformType() + CzgRandomUtils.snowflake());
            orderInfo.setShopId(param.getShopId());
            orderInfo.setRefundAmount(BigDecimal.ZERO);
            orderInfo.setPayAmount(BigDecimal.ZERO);

            orderInfo.setOrderType(param.getOrderType());
            orderInfo.setPlatformType(param.getPlatformType());
            orderInfo.setDineMode(param.getDineMode());
            orderInfo.setPayMode(param.getPayMode());
            orderInfo.setStatus(OrderStatusEnums.UNPAID.getCode());
            orderInfo.setRefundAble(0);
            orderInfo.setTradeDay(DateUtil.formatDate(new Date()));
            orderInfo.setRemark(param.getRemark());
            orderInfo.setStaffId(param.getStaffId());
            orderInfo.setIsWaitCall(param.isWaitCall() ? 1 : 0);
            orderInfo.setCreditBuyerId(param.getCreditBuyerId());
            orderInfo.setIsDel(0);
            if (param.getLimitRate() != null) {
                orderInfo.setLimitRateJson(JSONObject.toJSONString(param.getLimitRate()));
            }
            //取餐码 多端一致
            orderInfo.setTakeCode(getCode(shopInfo.getId()));
        }
        if (table != null) {
            orderInfo.setTableCode(table.getTableCode());
            orderInfo.setTableName(shopTableService.getTableAreaAndName(shopInfo.getId(), table.getTableCode(), table.getName()));
        }
        // 餐位费
        if (shopInfo.getIsTableFee().equals(0)) {
            orderInfo.setSeatAmount(shopInfo.getTableFee().multiply(new BigDecimal(param.getSeatNum())));
        }
        orderInfo.setSeatNum(param.getSeatNum());
        orderInfo.setUserId(param.getUserId());
        orderInfo.setTableCode(param.getTableCode());
        orderInfo.setPlaceNum(param.getPlaceNum());
        orderInfo.setOriginAmount(param.getOriginAmount());
        orderInfo.setDiscountAllAmount(BigDecimal.ZERO);
        if (param.getOrderAmount() != null && param.getOrderAmount().compareTo(BigDecimal.ZERO) >= 0) {
            orderInfo.setOrderAmount(param.getOrderAmount());
        } else {
            orderInfo.setOrderAmount(BigDecimal.ZERO);
        }
        if (orderInfo.getPackFee() == null) {
            orderInfo.setPackFee(param.getPackFee());
        } else {
            orderInfo.setPackFee(orderInfo.getPackFee().add(param.getPackFee()));
        }
        orderInfo.setRoundAmount(BigDecimal.ZERO);
        orderInfo.setPointsNum(0);
        orderInfoService.saveOrUpdate(orderInfo);
        return orderInfo;
    }

    /**
     * 更新订单 优惠信息
     */
    private void upOrderPayInfo(OrderInfo orderInfo, CheckOrderPay param) {
        orderInfo.setPointsNum(param.getPointsNum());
        orderInfo.setIsPrint(param.getIsPrint());
        orderInfo.setOrderAmount(param.getOrderAmount());
        // ----------------------优惠金额-------------------------
        //优惠卷
        orderInfo.setCouponInfoList(CollUtil.isEmpty(param.getCouponList()) ? "" : JSONObject.toJSONString(param.getCouponList()));
        orderInfo.setProductCouponDiscountAmount(param.getProductCouponDiscountAmount());
        orderInfo.setOtherCouponDiscountAmount(param.getOtherCouponDiscountAmount());
        //积分
        orderInfo.setPointsDiscountAmount(param.getPointsDiscountAmount());
        //新客立减
        orderInfo.setNewCustomerDiscountAmount(param.getNewCustomerDiscountAmount());
        //商家最终改价
        orderInfo.setDiscountAmount(param.getDiscountAmount());
        //满减活动抵扣金额
        orderInfo.setDiscountActAmount(param.getDiscountActAmount());
        //会员折扣金额
        orderInfo.setVipDiscountAmount(param.getVipDiscountAmount());
        //抹零
//        orderInfo.setRoundAmount(param.getRoundAmount());
        //优惠总金额
        orderInfo.initDiscountAllAmount();
        //折扣信息
        orderInfo.setDiscountInfo(buildDiscountInfo(orderInfo));


        //0元按照现金支付处理
        if (orderInfo.getOrderAmount().compareTo(BigDecimal.ZERO) == 0) {
            orderInfo.setStatus(OrderStatusEnums.DONE.getCode());
            if (param.getPointsDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
                orderInfo.setPayType(PayEnums.VIP_PAY.getValue());
            } else {
                orderInfo.setPayType(PayEnums.CASH_PAY.getValue());
            }
            orderInfo.setPaidTime(LocalDateTime.now());
            if (orderInfo.getUserId() != null) {
                ShopUser shopUser = shopUserService.getShopUserInfo(orderInfo.getShopId(), orderInfo.getUserId());
                if (shopUser == null) {
                    if ((orderInfo.getPointsNum() != null && orderInfo.getPointsNum() > 0)
                            || (StrUtil.isNotBlank(orderInfo.getCouponInfoList()) && !"null".equals(orderInfo.getCouponInfoList()))) {
                        log.error("订单积分使用或优惠券扣除失败，订单id：{}", orderInfo.getId());
                    }
                } else {
                    shopUserUseInfo(orderInfo, shopUser);
                }
            }
            exTable(orderInfo);
        }
        orderInfoService.saveOrUpdate(orderInfo);
    }

    /**
     * 构建优惠内容
     */
    private String buildDiscountInfo(OrderInfo orderInfo) {
        JSONObject jsonObject = new JSONObject();
        if (orderInfo.getNewCustomerDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
            jsonObject.put("新客立减", orderInfo.getNewCustomerDiscountAmount());
        }
        if (orderInfo.getProductCouponDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
            jsonObject.put("商品券抵扣", orderInfo.getProductCouponDiscountAmount());
        }
        if (orderInfo.getOtherCouponDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
            jsonObject.put("其它优惠券折扣", orderInfo.getOtherCouponDiscountAmount());
        }
        if (orderInfo.getDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
            jsonObject.put("打折优惠", orderInfo.getDiscountAmount());
        }
        if (orderInfo.getDiscountActAmount() != null && orderInfo.getDiscountActAmount().compareTo(BigDecimal.ZERO) > 0) {
            jsonObject.put("满减活动抵扣", orderInfo.getDiscountActAmount());
        }
        if (orderInfo.getVipDiscountAmount() != null && orderInfo.getVipDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
            jsonObject.put("会员整单折扣", orderInfo.getVipDiscountAmount());
        }
        if (orderInfo.getPointsDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
            jsonObject.put("积分抵扣", orderInfo.getPointsDiscountAmount());
        }
        if (orderInfo.getRoundAmount().compareTo(BigDecimal.ZERO) > 0) {
            jsonObject.put("抹零", orderInfo.getPointsNum());
        }
        return jsonObject.toString();
    }

    /**
     * 生成取餐码
     */
    private String getCode(Long shopId) {
        String key = RedisCst.SHOP_CODE + DateUtil.today() + ":" + shopId;
        int count = 1;
        if (redisService.hasKey(key)) {
            count = Integer.parseInt(redisService.get(key).toString());
            count++;
        }
        // 设置缓存并设置过期时间
        redisService.set(key, count, 24 * 60 * 60);
        return "#" + count;
    }

    @Override
    public Boolean printOrder(Long shopId, OrderInfoPrintDTO orderInfoPrintDTO) {
        if (redisService.hasKey("order:print:" + orderInfoPrintDTO.getId())) {
            throw new CzgException("网络打印机正在尝试打印中。如需重打，请稍后再试！");
        }
        OrderInfo orderInfo = orderInfoService.getOne(new QueryWrapper().eq(OrderInfo::getShopId, shopId).eq(OrderInfo::getId, orderInfoPrintDTO.getId()));
        if (orderInfo == null) {
            throw new CzgException("订单信息不存在");
        }

        switch (orderInfoPrintDTO.getType()) {
            case 1://预结算单
                printConfig.orderHandler(orderInfo.getId(), PrinterHandler.PrintTypeEnum.PRE_ORDER, null);
                break;
            case 2://结算单
                printConfig.orderHandler(orderInfo.getId(), PrinterHandler.PrintTypeEnum.ORDER, null);
                break;
            case 3://后厨单
                printConfig.orderHandler(orderInfo.getId(), PrinterHandler.PrintTypeEnum.ALL_KITCHEN, null);
                printConfig.orderHandler(orderInfo.getId(), PrinterHandler.PrintTypeEnum.ONLY_KITCHEN, null);
                break;
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean removeOrderDetail(Long shopId, Long orderId, Long detailId) {
        OrderInfo orderInfo = orderInfoService.getOne(new QueryWrapper().eq(OrderInfo::getId, orderId).eq(OrderInfo::getShopId, shopId));
        if (orderInfo == null) {
            throw new CzgException("订单不存在");
        }

        if (!OrderStatusEnums.UNPAID.getCode().equals(orderInfo.getStatus())) {
            throw new CzgException("订单不处于待支付状态");
        }

        OrderDetail orderDetail = orderDetailService.getOne(new QueryWrapper().eq(OrderDetail::getId, detailId).eq(OrderDetail::getOrderId, orderId));
        if (orderDetail == null || !orderDetail.getStatus().equals(OrderStatusEnums.UNPAID.getCode())) {
            throw new CzgException("不处于待支付或订单详情不存在");
        }

        int i = orderInfoCustomMapper.decrMoney(orderInfo.getId(), orderDetail.getPayAmount().add(orderDetail.getPackAmount()));
        if (i > 0) {
            return orderDetailService.removeById(orderDetail.getId());
        }
        throw new CzgException("操作失败");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean cancelledOrder(Long shopId, Long orderId) throws OrderCancelException {
        OrderInfo orderInfo = orderInfoService.getById(orderId);
        if (orderInfo == null) {
//            throw new OrderCancelException("订单不存在");
            return true;
        }
        if (!OrderStatusEnums.UNPAID.getCode().equals(orderInfo.getStatus())) {
//            throw new OrderCancelException("订单不可取消");
            return true;
        }
        orderInfoService.updateById(new OrderInfo().setId(orderId)
                .setStatus(OrderStatusEnums.CANCELLED.getCode()));
        redisService.del(RedisCst.classKeyExpired.EXPIRED_ORDER + orderInfo.getId());
        rabbitPublisher.sendOrderCancelMsg(orderInfo.getId().toString());
        orderDetailService.updateOrderDetailStatus(orderId, OrderStatusEnums.CANCELLED.getCode());
        // 还原台桌状态
        if (StrUtil.isNotBlank(orderInfo.getTableCode())) {
            ShopTable table = shopTableService.getOneByTableCode(orderInfo.getShopId(), orderInfo.getTableCode());
            if (table != null) {
                ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
                if ("auto".equals(shopInfo.getTableClearType())) {
                    table.setStatus(ShopTableStatusEnum.IDLE.getValue());
                } else {
                    DateTime dateTime = DateUtil.offsetMinute(DateUtil.date(), shopInfo.getTableClearTime());
                    table.setCreateTime(LocalDateTimeUtil.of(dateTime));
                    redisService.set(RedisCst.classKeyExpired.EXPIRED_TABLE + table.getId(), "", 60L * shopInfo.getTableClearTime());
                }
                shopTableService.updateById(table);
            }
        }
        return true;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean cancelledPlaceOrder(Long shopId, Long orderId, Integer placeNum) {
        OrderInfo orderInfo = orderInfoService.getById(orderId);
        if (orderInfo == null) {
//            throw new OrderCancelException("订单不存在");
            return true;
        }
        if (!OrderStatusEnums.UNPAID.getCode().equals(orderInfo.getStatus())) {
//            throw new OrderCancelException("订单不可取消");
            return true;
        }
        if (orderInfo.getPlaceNum().equals(1)) {
            orderInfoService.updateById(new OrderInfo().setId(orderId)
                    .setStatus(OrderStatusEnums.CANCELLED.getCode()));
            ShopTable table = shopTableService.getOneByTableCode(orderInfo.getShopId(), orderInfo.getTableCode());
            if (table != null) {
                ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
                if ("auto".equals(shopInfo.getTableClearType())) {
                    table.setStatus(ShopTableStatusEnum.IDLE.getValue());
                } else {
                    DateTime dateTime = DateUtil.offsetMinute(DateUtil.date(), shopInfo.getTableClearTime());
                    table.setCreateTime(LocalDateTimeUtil.of(dateTime));
                    redisService.set(RedisCst.classKeyExpired.EXPIRED_TABLE + table.getId(), "", 60L * shopInfo.getTableClearTime());
                }
                shopTableService.updateById(table);
            }
            rabbitPublisher.sendOrderCancelMsg(orderInfo.getId().toString());
            return true;
        }
        List<OrderDetail> details = orderDetailService.list(QueryWrapper.create().eq(OrderDetail::getOrderId, orderId).eq(OrderDetail::getPlaceNum, placeNum));
        List<ProductStockVO> listStock = new ArrayList<>();
        for (OrderDetail detail : details) {
            listStock.add(new ProductStockVO(detail.getProductId(), NumberUtil.sub(detail.getNum(), detail.getReturnNum())));
        }
        orderDetailService.remove(new QueryWrapper().eq(OrderDetail::getOrderId, orderId).eq(OrderDetail::getPlaceNum, placeNum));
        if (CollUtil.isNotEmpty(listStock)) {
            productRpcService.orderCancelRecoverStock(shopId, orderId, listStock);
        }
        List<OrderDetail> list = orderDetailService.queryChain().eq(OrderDetail::getOrderId, orderId).eq(OrderDetail::getShopId, shopId).list();
        if (CollUtil.isEmpty(list)) {
            orderInfoService.updateById(new OrderInfo().setId(orderId)
                    .setStatus(OrderStatusEnums.CANCELLED.getCode())
                    .setOriginAmount(BigDecimal.ZERO));
            ShopTable table = shopTableService.getOneByTableCode(orderInfo.getShopId(), orderInfo.getTableCode());
            if (table != null) {
                ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
                if ("auto".equals(shopInfo.getTableClearType())) {
                    table.setStatus(ShopTableStatusEnum.IDLE.getValue());
                } else {
                    DateTime dateTime = DateUtil.offsetMinute(DateUtil.date(), shopInfo.getTableClearTime());
                    table.setCreateTime(LocalDateTimeUtil.of(dateTime));
                    redisService.set(RedisCst.classKeyExpired.EXPIRED_TABLE + table.getId(), "", 60L * shopInfo.getTableClearTime());
                }
                shopTableService.updateById(table);
            }
            return true;
        } else {
            BigDecimal totalAmount = BigDecimal.ZERO;
            for (OrderDetail orderDetail : list) {
                BigDecimal subtract = orderDetail.getNum().subtract(orderDetail.getReturnNum());
                if (subtract.compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal unitPrice;
                    if (orderDetail.getDiscountSaleAmount().compareTo(BigDecimal.ZERO) > 0) {
                        unitPrice = orderDetail.getDiscountSaleAmount();
                    } else {
                        unitPrice = orderDetail.getPrice();
                    }
                    totalAmount = totalAmount.add((orderDetail.getNum().subtract(orderDetail.getReturnNum())).multiply(unitPrice));
                }
                if (subtract.compareTo(BigDecimal.ZERO) > 0
                        && orderDetail.getPackAmount().compareTo(BigDecimal.ZERO) > 0
                        && orderDetail.getPackNumber().compareTo(BigDecimal.ZERO) > 0) {
                    totalAmount = totalAmount.add(orderDetail.getPackAmount().multiply(orderDetail.getPackNumber()));
                }
                if (orderDetail.getPlaceNum() > placeNum) {
                    orderDetailService.updateChain()
                            .eq(OrderDetail::getId, orderDetail.getId())
                            .set(OrderDetail::getPlaceNum, orderDetail.getPlaceNum() - 1)
                            .update();
                }
            }
            orderInfoService.updateById(new OrderInfo().setId(orderId)
                    .setOriginAmount(totalAmount)
                    .setPlaceNum(orderInfo.getPlaceNum() - 1));
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updatePayOrderId(Long orderId, Long paymentId, String payType, String remark) {
        orderInfoCustomMapper.updatePayOrderId(orderId, paymentId, payType, remark);
        return true;
    }

    @Override
    public void updateOrderDetailStatus(Long orderDetailId) {
        OrderDetail orderDetail = orderDetailService.getById(orderDetailId);
        if (orderDetail == null) {
            log.warn("订单详情不存在");
            return;
        }

        if (!TableValueConstant.OrderDetail.SubStatus.READY_TO_SERVE.getCode().equals(orderDetail.getSubStatus())
                && !TableValueConstant.OrderDetail.SubStatus.SENT_OUT.getCode().equals(orderDetail.getSubStatus())) {
            log.warn("订单详情状态不正确");
            return;
        }


        switch (EnumUtil.fromString(TableValueConstant.OrderDetail.SubStatus.class, orderDetail.getSubStatus())) {
            case TableValueConstant.OrderDetail.SubStatus.READY_TO_SERVE:
                orderDetail.setSubStatus(TableValueConstant.OrderDetail.SubStatus.SENT_OUT.getCode());
                orderDetail.setDishOutTime(DateUtil.date().toLocalDateTime());
                break;
            case TableValueConstant.OrderDetail.SubStatus.SENT_OUT:
                orderDetail.setSubStatus(TableValueConstant.OrderDetail.SubStatus.DELIVERED.getCode());
                orderDetail.setFoodServeTime(DateUtil.date().toLocalDateTime());

        }
        orderDetailService.updateById(orderDetail);
    }

    @Override
    public Boolean upOrderDetail(Long shopId, OrderDetailStatusDTO detailStatusDTO) {
        // 起菜
        if (detailStatusDTO.getType() == 0) {
            AssertUtil.isNull(detailStatusDTO.getOrderDetailId(), "订单详情id不能为空");
            OrderDetail detail = orderDetailService.getOne(new QueryWrapper().eq(OrderDetail::getId, detailStatusDTO.getOrderDetailId())
                    .eq(OrderDetail::getShopId, shopId));
            AssertUtil.isNull(detail, "订单详情不存在");
            orderDetailService.updateChain().set(OrderDetail::getSubStatus, TableValueConstant.OrderDetail.SubStatus.READY_TO_SERVE.getCode())
                    .set(OrderDetail::getStartOrderTime, DateUtil.date().toLocalDateTime())
                    .eq(OrderDetail::getId, detailStatusDTO.getOrderDetailId()).update();
            // 上菜
        } else if (detailStatusDTO.getType() == 2) {
            boolean update = orderDetailService.updateChain()
                    .eq(OrderDetail::getSubStatus, TableValueConstant.OrderDetail.SubStatus.READY_TO_SERVE.getCode())
                    .set(OrderDetail::getSubStatus, TableValueConstant.OrderDetail.SubStatus.SENT_OUT.getCode())
                    .set(OrderDetail::getDishOutTime, DateUtil.date().toLocalDateTime())
                    .eq(OrderDetail::getId, detailStatusDTO.getOrderDetailId()).update();
            AssertUtil.isTrue(!update, "已出菜，请勿重复出菜");

        } else {
            if (detailStatusDTO.getOrderId() != null) {
                orderDetailService.updateChain()
                        .set(OrderDetail::getFoodServeTime, DateUtil.date().toLocalDateTime())
                        .set(OrderDetail::getSubStatus, TableValueConstant.OrderDetail.SubStatus.DELIVERED.getCode())
                        .set(OrderDetail::getFoodServeTime, DateUtil.date().toLocalDateTime())
                        .eq(OrderDetail::getOrderId, detailStatusDTO.getOrderId()).update();
            } else {
                orderDetailService.updateChain()
                        .set(OrderDetail::getSubStatus, TableValueConstant.OrderDetail.SubStatus.DELIVERED.getCode())
                        .set(OrderDetail::getFoodServeTime, DateUtil.date().toLocalDateTime())
                        .set(OrderDetail::getFoodServeTime, DateUtil.date().toLocalDateTime())
                        .eq(OrderDetail::getId, detailStatusDTO.getOrderDetailId()).update();
            }
        }

        rabbitPublisher.sendOrderDetailStatusMsg(shopId.toString(), "bc");
        return true;
    }


    /**
     * 退单库存问题
     * 1退菜退库存 2仅退菜不退库存 3每次询问-退菜后弹窗提示1
     */
    @Override
    public void refundStock(ShopInfo shopInfo, Long orderId, Map<Long, BigDecimal> products, boolean refundStock) {
        List<Product> list = productService.list(new QueryWrapper().select(Product::getId, Product::getCategoryId, Product::getRefundMode)
                .eq(Product::getShopId, shopInfo.getId())
                .in(Product::getId, products.keySet()));
        if (CollUtil.isEmpty(list)) {
            return;
        }
        List<ProductStockVO> resultProduct = new ArrayList<>();
        HashMap<Long, Integer> categoryMap = new HashMap<>();
        for (Product product : list) {
            Integer refundMode;
            if (shopInfo.getRefundMode().equals(1)) {
                //分类
                if (!categoryMap.containsKey(product.getCategoryId())) {
                    refundMode = shopProdCategoryService.getOneAs(new QueryWrapper().select(ShopProdCategory::getRefundMode)
                            .eq(ShopProdCategory::getShopId, shopInfo.getId())
                            .eq(ShopProdCategory::getId, product.getCategoryId()), Integer.class);
                    if (refundMode == null) {
                        refundMode = 2;
                    }
                    categoryMap.put(product.getCategoryId(), refundMode);
                } else {
                    refundMode = categoryMap.get(product.getCategoryId());
                }
            } else if (shopInfo.getRefundMode().equals(2)) {
                //单商品
                refundMode = product.getRefundMode();
            } else {
                log.error("退菜模式错误 店铺{},退款模式{},商品Id{}分类Id{}", shopInfo.getShopName(), shopInfo.getRefundMode(), product.getId(), product.getCategoryId());
                throw new CzgException("退菜模式错误");
            }
            if (refundMode.equals(1)) {
                resultProduct.add(new ProductStockVO(product.getId(), products.get(product.getId())));
            } else if (refundMode.equals(3) && refundStock) {
                resultProduct.add(new ProductStockVO(product.getId(), products.get(product.getId())));
            }
        }
        if (CollUtil.isNotEmpty(resultProduct)) {
            rabbitPublisher.sendOrderRefundMsg(JSONObject.toJSONString(Map.of("orderId", orderId, "returnProList", resultProduct)));
        }
    }
}
