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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
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.entity.notify.CzgPayNotifyDTO;
import com.czg.entity.notify.CzgRefundNotifyDTO;
import com.czg.enums.ShopUserFlowBizEnum;
import com.czg.exception.ApiNotPrintException;
import com.czg.exception.OrderCancelException;
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.CashierCartService;
import com.czg.order.service.OrderDetailService;
import com.czg.order.service.OrderInfoService;
import com.czg.order.service.OrderPaymentService;
import com.czg.order.vo.*;
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.OrderInfoMapper;
import com.czg.service.order.print.PrinterHandler;
import com.czg.utils.AssertUtil;
import com.czg.utils.CzgStrUtils;
import com.czg.utils.PageUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotBlank;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.annotation.Lazy;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 订单表 服务层实现。
 *
 * @author ww
 * @since 2025-02-13
 */
@Slf4j
@DubboService
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Lazy
    @Resource
    private PrinterHandler printerHandler;
    @Resource
    private OrderDetailService orderDetailService;
    @Resource
    private OrderPaymentService paymentService;
    @Resource
    private CashierCartService cartService;
    @Resource
    private RedisService redisService;
    @Resource
    private RabbitPublisher rabbitPublisher;
    @DubboReference
    private MemberPointsService pointsService;
    @DubboReference
    private ShopInfoService shopInfoService;
    @DubboReference
    private UserInfoService userInfoService;
    @DubboReference
    private ShopUserService shopUserService;
    @DubboReference
    private ShopUserFlowService flowService;
    @DubboReference
    private ShopTableService shopTableService;
    @DubboReference
    private ShopActivateService activateService;
    @DubboReference
    private PointsBasicSettingService pointsBasicService;
    @DubboReference
    private ShopCouponService couponService;
    @DubboReference
    private ShopActivateCouponRecordService couponRecordService;

    @Override
    public Page<OrderInfoVo> getOrderByPage(OrderInfoQueryDTO param) {
        String productName = param.getProductName();
        List<Long> like = null;
        if (StrUtil.isNotBlank(productName)) {
            like = orderDetailService.queryChain()
                    .select(OrderDetail::getOrderId)
                    .eq(OrderDetail::getShopId, param.getShopId())
                    .like(OrderDetail::getProductName, productName).listAs(Long.class);
            if (CollUtil.isEmpty(like)) {
                return new Page<>();
            }
        }
        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 = pageAs(PageUtil.buildPage(), queryWrapper, OrderInfoVo.class);
        orderInfoVoPage.getRecords().parallelStream().forEach(s -> {
            List<OrderDetailSmallVO> orderDetails = orderDetailService.queryChain().select()
                    .eq(OrderDetail::getShopId, s.getShopId())
                    .eq(OrderDetail::getOrderId, s.getId())
                    .listAs(OrderDetailSmallVO.class);
            s.setGoods(orderDetails);
        });
        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 = 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("");
            }
            orderDetail.initGift();
            // 获取当前订单详情的 placeNum
            Integer placeNum = orderDetail.getPlaceNum();
            // 检查 Map 中是否已经存在该 placeNum 对应的列表
            resultMap.computeIfAbsent(placeNum.toString(), k -> new ArrayList<>()).add(orderDetail);
        }
        historyOrderVo.setDetailMap(resultMap);
        long count = queryChain()
                .eq(OrderInfo::getTradeDay, historyOrderVo.getTradeDay())
                .eq(OrderInfo::getStatus, OrderStatusEnums.DONE.getCode())
                .eq(OrderInfo::getShopId, historyOrderVo.getShopId())
                .le(OrderInfo::getCreateTime, historyOrderVo.getCreateTime()).count();
        historyOrderVo.setOrderNum(count);
        return CzgResult.success(historyOrderVo);
    }

    @Override
    public HistoryOrderVo historyOrder(Long orderId, String tableCode) {
        if (orderId == null && StrUtil.isBlank(tableCode)) {
            throw new ValidateException("订单id或台桌码不可为空");
        }
        HistoryOrderVo historyOrderVo;
        if (orderId == null) {
            historyOrderVo = queryChain()
                    .select()
                    .eq(OrderInfo::getShopId, StpKit.USER.getShopId())
                    .eq(OrderInfo::getTableCode, tableCode)
                    .eq(OrderInfo::getStatus, OrderStatusEnums.UNPAID.getCode())
                    .gt(OrderInfo::getCreateTime, DateUtil.offsetDay(new Date(), -1))
                    .oneAs(HistoryOrderVo.class);
        } else {
            historyOrderVo = getOneAs(new QueryWrapper()
                    .eq(OrderInfo::getId, orderId), HistoryOrderVo.class);
        }
        if (historyOrderVo == null || historyOrderVo.getId() == null) {
            return null;
        }
        List<OrderDetail> orderDetails = orderDetailService.queryChain().select()
                .eq(OrderDetail::getOrderId, historyOrderVo.getId())
                .list();
        Map<String, List<OrderDetail>> resultMap = new HashMap<>();
        // 遍历订单详情列表
        for (OrderDetail orderDetail : orderDetails) {
            orderDetail.initGift();
            // 获取当前订单详情的 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) {
        ShopInfo shopInfo = shopInfoService.getById(param.getShopId());
        AssertUtil.isNull(shopInfo, "生成订单失败，店铺信息不存在");
        if (!shopInfo.getEatModel().contains(param.getDineMode())) {
            throw new ValidateException("生成订单失败，店铺不支持该用餐模式");
        }
        if (param.getUserId() != null) {
            UserInfo userInfo = userInfoService.getById(param.getUserId());
            AssertUtil.isNull(userInfo, "生成订单失败，用户信息不存在");
        }
        ShopTable 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("未知");
            }
        }
        List<OrderDetail> orderDetails = cartService.getCartByTableCode(shopInfo.getId(), param.getTableCode(), param.getPlaceNum());
        AssertUtil.isListEmpty(orderDetails, "下单失败 购物车为空");
        processOrderDetails(orderDetails);
        //生成订单
        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())) {
            //发送打票信息 后付费推送多次 需要处理
            //orderId_0_0  订单ID_先付后付(1先付0后付)_订单状态 0未完成 1完成
            //orderInfo.getId() + "_" + (!"after-pay".equals(orderInfo.getPayMode()) ? 1 : 0) + "_0"
            rabbitPublisher.sendOrderPrintMsg(orderInfo.getId() + "_0_0", false);
        } else {
            redisService.set(RedisCst.classKeyExpired.EXPIRED_ORDER + orderInfo.getId(), "", 60 * 15);
        }
        rabbitPublisher.sendOrderStockMsg(orderInfo.getId().toString());
        return orderInfo;
    }

    @Override
    public OrderInfo checkOrderPay(CheckOrderPay param) {
        OrderInfo orderInfo = 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(() -> {
                        updateChain()
                                .set(OrderInfo::getStatus, OrderStatusEnums.CANCELLED.getCode())
                                .eq(OrderInfo::getId, param.getOrderId())
                                .update();
                        rabbitPublisher.sendOrderCancelMsg(orderInfo.getId().toString());
                    });
                }
                throw new OrderCancelException("订单已过期,请重新下单");
            }
        }
        ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
        AssertUtil.isNull(shopInfo, "生成订单失败，店铺信息不存在");
        if (param.isVipPrice() && !shopInfo.getIsMemberPrice().equals(1)) {
            throw new ValidateException("生成订单失败，该店铺不支持使用会员价");
        }
        if (param.getOrderAmount().compareTo(BigDecimal.ZERO) < 0) {
            throw new ValidateException("生成订单失败，订单金额不能小于0");
        }
        log.info("订单信息：{}，优惠信息：{}", JSONObject.toJSONString(orderInfo), JSONObject.toJSONString(param));
        Long shopId = orderInfo.getShopId();
        AssertUtil.isNull(shopId, "生成支付订单失败，订单信息异常");
        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);
        }
        PointsBasicSetting pointSetting = pointsBasicService.getById(shopId);
        if (param.getPointsNum() > 0) {
            if (pointSetting == null || !pointSetting.getEnableDeduction().equals(1)) {
                throw new ValidateException("生成支付订单失败，该店铺未开启积分抵扣");
            }
            if (param.getUserId() == null) {
                throw new ValidateException("生成支付订单失败，请选择用户后再使用积分抵扣");
            }
        } else if (param.getPointsDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
            throw new ValidateException("生成支付订单失败，已使用积分抵扣，积分数量不正确");
        }
        ShopUser shopUser = null;
        if (param.getUserId() != null) {
            UserInfo userInfo = userInfoService.getById(param.getUserId());
            AssertUtil.isNull(userInfo, "生成支付订单失败，用户信息不存在");
            shopUser = shopUserService.getShopUserInfo(shopId, param.getUserId());
            if (param.getPointsNum() > 0 && !shopUser.getIsVip().equals(1) && pointSetting.getDeductionGroup().contains("vip")) {
                throw new ValidateException("生成支付订单失败，该店铺仅会员可使用积分抵扣");
            }
            orderInfo.setUserId(userInfo.getId());
        }
        if (param.getDiscountRatio().compareTo(BigDecimal.ZERO) < 0 || param.getDiscountRatio().compareTo(BigDecimal.ONE) > 0) {
            throw new ValidateException("生成支付订单失败，折扣比例不正确");
        }
        //商品券 <商品id，数量>
        Map<Long, Integer> prodCouponMap = new HashMap<>();
        //满减券 满fullCouponAmount  减disCouponAmount
        BigDecimalDTO fullAmount = new BigDecimalDTO(BigDecimal.ZERO);
        BigDecimalDTO discountAmount = new BigDecimalDTO(BigDecimal.ZERO);
        //校验优惠券
        checkCoupon(prodCouponMap, fullAmount, discountAmount, param);

        //获取商品信息 计算金额 需要传入优惠券 减去优惠券
        List<OrderDetail> orderDetails = orderDetailService.queryChain().eq(OrderDetail::getOrderId, param.getOrderId()).select().list();
        //商品优惠券金额
        BigDecimalDTO prodCouponAmount = new BigDecimalDTO(BigDecimal.ZERO);
        //总商品支付金额 不包含打包费 用来计算后续
        BigDecimalDTO totalAmount = new BigDecimalDTO(BigDecimal.ZERO);
        //最终打包费
        BigDecimalDTO packAmount = new BigDecimalDTO(BigDecimal.ZERO);
        processOrderDetails2(orderDetails, prodCouponMap, prodCouponAmount, totalAmount, packAmount, param.isAllPack(), param.getUserAllPack(), param.isVipPrice());
        //总商品支付金额 不包含打包费 用来计算后续
        if (prodCouponAmount.getPrice().compareTo(param.getProductCouponDiscountAmount()) != 0) {
            log.info("支付计算金额不正确：商品券抵扣金额为：{}，传递为：{}", prodCouponAmount.getPrice(), param.getProductCouponDiscountAmount());
            throw new ValidateException("生成支付订单失败，商品优惠券优惠金额不正确");
        }
//        orderInfo.setOriginAmount(totalAmount.getPrice().add(packAmount.getPrice()).add(orderInfo.getSeatAmount()));
        orderInfo.setOriginAmount(param.getOriginAmount());
        BigDecimal newTotalAmount = totalAmount.getPrice();
        //折扣金额 如 9折 计算 为 订单金额*0.9 向上取整
        if (param.getDiscountRatio().compareTo(BigDecimal.ZERO) > 0) {
            newTotalAmount = totalAmount.getPrice().multiply(param.getDiscountRatio()).setScale(2, RoundingMode.UP);

        } else if (param.getDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
            newTotalAmount = totalAmount.getPrice().subtract(param.getDiscountAmount());
        }

        //满减券 校验
        if (newTotalAmount.compareTo(fullAmount.getPrice()) < 0) {
            throw new ValidateException("生成支付订单失败，满减券不满足条件");
        }
        //减去满减优惠券
        newTotalAmount = newTotalAmount.subtract(discountAmount.getPrice());
        //积分抵扣 金额范围校验 抵扣金额校验
//        if (param.getPointsNum() > 0) {
//            if (pointSetting.getMinPaymentAmount().compareTo(newTotalAmount) > 0) {
//                throw new ValidateException("生成支付订单失败，未满足积分抵扣最低门槛");
//            }
//            if (pointSetting.getMaxDeductionRatio().multiply(newTotalAmount).compareTo(param.getPointsDiscountAmount()) < 0) {
//                throw new ValidateException("生成支付订单失败，积分抵扣金额已超出最大抵扣金额");
//            }
//            BigDecimal pointAmount = new BigDecimal(param.getPointsNum()).divide(new BigDecimal(pointSetting.getEquivalentPoints()), 2, RoundingMode.DOWN);
//            if (pointAmount.compareTo(param.getPointsDiscountAmount()) != 0) {
//                throw new ValidateException("生成支付订单失败，积分抵扣金额不正确");
//            }
//        }
        newTotalAmount = newTotalAmount.subtract(param.getPointsDiscountAmount());
        //抹零
        newTotalAmount = newTotalAmount.subtract(param.getRoundAmount());
        //校验最终金额（订单金额 (扣除各类折扣)+打包费 餐位费）
        newTotalAmount = newTotalAmount.add(packAmount.getPrice()).add(orderInfo.getSeatAmount());
        if (newTotalAmount.compareTo(param.getOrderAmount()) != 0) {
            log.info("支付计算金额不正确，订单Id:{},最终计算金额为：{},打包费：{}，餐位费：{},商品券金额：{},满减券金额：{},积分抵扣金额：{},抹零金额：{}",
                    orderInfo.getId(), newTotalAmount, packAmount.getPrice(), orderInfo.getSeatAmount(), param.getProductCouponDiscountAmount(),
                    discountAmount.getPrice(), param.getPointsDiscountAmount(), param.getRoundAmount());
            throw new ValidateException("生成支付订单失败，订单金额不正确");
        }
        orderInfo.setPackFee(packAmount.getPrice());
        //生成订单 //discount_info 所有折扣 几折 折扣金额 满减金额 优惠券金额 积分抵扣金额 抹零
        upOrderPayInfo(orderInfo, param);
        orderDetailService.updateBatch(orderDetails);
        return orderInfo;
    }

    @Override
    public CzgResult<Object> mergeOrder(MergeOrderDTO param) {
        if (param.getTargetOrderId() == null && StrUtil.isBlank(param.getTargetTableCode())) {
            throw new ValidateException("转台失败，请选择目标台桌后转台");
        }
        OrderInfo sourceOrder = getById(param.getSourceOrderId());
        if (sourceOrder == null || !sourceOrder.getStatus().equals(OrderStatusEnums.UNPAID.getCode())) {
            throw new ValidateException("转台失败，无可转订单");
        }
        OrderInfo targetOrder = queryChain()
                .eq(OrderInfo::getId, param.getTargetOrderId())
                .eq(OrderInfo::getTableCode, param.getTargetTableCode())
                .eq(OrderInfo::getStatus, OrderStatusEnums.UNPAID.getCode())
                .one();
        if (targetOrder == null) {
            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, null);
        } else {
            targetOrder.setPlaceNum(targetOrder.getPlaceNum() + 1);
            //下单次数+1
            updateChain().set(OrderInfo::getPlaceNum, targetOrder.getPlaceNum() + 1).eq(OrderInfo::getId, targetOrder.getId()).update();
        }
        if (CollUtil.isEmpty(param.getDetailIds())) {
            long count = orderDetailService.queryChain().eq(OrderDetail::getOrderId, sourceOrder.getId()).count();
            if (count < 1) {
                throw new ValidateException("转台失败，该订单无可转商品");
            }
            orderDetailService.updateChain()
                    .eq(OrderDetail::getOrderId, sourceOrder.getId())
                    .set(OrderDetail::getPlaceNum, targetOrder.getPlaceNum())
                    .set(OrderDetail::getOrderId, targetOrder.getId())
                    .update();
        } else {
            orderDetailService.updateChain()
                    .eq(OrderDetail::getOrderId, sourceOrder.getId())
                    .in(OrderDetail::getId, param.getDetailIds())
                    .set(OrderDetail::getPlaceNum, targetOrder.getPlaceNum())
                    .set(OrderDetail::getOrderId, targetOrder.getId())
                    .update();
        }
        return CzgResult.success();
    }

    /**
     * 填充 单价/付款金额
     *
     * @param orderDetails 订单详情 需要回填
     */
    private void processOrderDetails(List<OrderDetail> orderDetails) {
        for (OrderDetail detail : orderDetails) {
            if (detail.getDiscountSaleAmount() != null && detail.getDiscountSaleAmount().compareTo(BigDecimal.ZERO) > 0) {
                detail.setUnitPrice(detail.getDiscountSaleAmount());
            } else {
                if (detail.getDiscountSaleAmount() != null && detail.getDiscountSaleAmount().compareTo(BigDecimal.ZERO) > 0) {
                    detail.setUnitPrice(detail.getDiscountSaleAmount());
                } else {
                    detail.setUnitPrice(detail.getPrice());

                }
            }
            detail.setPayAmount(detail.getNum().multiply(detail.getUnitPrice()));
        }
    }

    /**
     * 填充 优惠券使用数量 以及 付款金额
     *
     * @param orderDetails     订单详情 需要回填 优惠券抵扣数量
     * @param prodCouponMap    使用优惠券<商品id,数量>
     * @param prodCouponAmount 商品券优惠金额 商品单价*优惠数量 的总和
     * @param totalAmount      最终总金额（没加打包费 餐位费） 去除优惠券金额后的
     */
    @Override
    public void processOrderDetails2(List<OrderDetail> orderDetails, Map<Long, Integer> prodCouponMap,
                                     BigDecimalDTO prodCouponAmount, BigDecimalDTO totalAmount, BigDecimalDTO packAmount,
                                     boolean isAllPack, Integer userAllPack, boolean isVipPrice) {
        Map<Long, List<OrderDetail>> detailMap = new HashMap<>();
        for (OrderDetail detail : orderDetails) {
            detailMap.computeIfAbsent(detail.getProductId(), k -> new ArrayList<>()).add(detail);
        }
        List<OrderDetail> resultList = new ArrayList<>();
        for (Map.Entry<Long, List<OrderDetail>> entry : detailMap.entrySet()) {
            Long key = entry.getKey();
            List<OrderDetail> value = entry.getValue();
            BigDecimal couponNum = BigDecimal.ZERO;
            if (CollUtil.isNotEmpty(prodCouponMap) && prodCouponMap.containsKey(key)) {
                couponNum = new BigDecimal(prodCouponMap.get(key));
                if (value.size() > 1) {
                    value.sort(Comparator.comparing(OrderDetail::getPrice));
                }
            }
            for (OrderDetail orderDetail : value) {
                if (orderDetail.getDiscountSaleAmount() != null && orderDetail.getDiscountSaleAmount().compareTo(BigDecimal.ZERO) > 0) {
                    orderDetail.setUnitPrice(orderDetail.getDiscountSaleAmount());
                } 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);
                    }
                }
                packAmount.setPrice(packAmount.getPrice().add(orderDetail.getPackAmount().multiply(orderDetail.getPackNumber()).setScale(2, RoundingMode.DOWN)));
                if (couponNum.compareTo(BigDecimal.ZERO) > 0) {
                    if (couponNum.compareTo(orderDetail.getNum()) >= 0) {
                        orderDetail.setCouponNum(orderDetail.getNum());
                        orderDetail.setPayAmount(BigDecimal.ZERO);
                        couponNum = couponNum.subtract(orderDetail.getNum());
                    } else {
                        orderDetail.setCouponNum(couponNum);
                        orderDetail.setPayAmount((orderDetail.getNum().subtract(orderDetail.getReturnNum()).subtract(couponNum)).multiply(orderDetail.getUnitPrice()).setScale(2, RoundingMode.DOWN));
                        couponNum = BigDecimal.ZERO;
                    }
                    prodCouponAmount.setPrice((prodCouponAmount.getPrice().add(orderDetail.getUnitPrice())).multiply(orderDetail.getCouponNum()).setScale(2, RoundingMode.DOWN));
                } else {
                    orderDetail.setCouponNum(BigDecimal.ZERO);
                    orderDetail.setPayAmount((orderDetail.getNum().subtract(orderDetail.getReturnNum())).multiply(orderDetail.getUnitPrice()).setScale(2, RoundingMode.DOWN));
                }
                totalAmount.setPrice(totalAmount.getPrice().add(orderDetail.getPayAmount()));
                resultList.add(orderDetail);
            }
//            if (couponNum.compareTo(BigDecimal.ZERO) != 0) {
//                throw new ValidateException("生成支付订单失败，优惠券数量不正确");
//            }
        }
        orderDetails = resultList;
    }


    /**
     * 校验优惠券可用性
     */
    private void checkCoupon(Map<Long, Integer> prodCouponMap, BigDecimalDTO fullAmount, BigDecimalDTO discountAmount, CheckOrderPay param) {
        if (CollUtil.isNotEmpty(param.getCouponList())) {
            //校验优惠券
            List<ShopActivateCouponRecord> records = couponRecordService.listAs(
                    QueryWrapper.create()
                            .where(ShopActivateCouponRecord::getId).in(param.getCouponList())
                            .and(ShopActivateCouponRecord::getStatus).eq(0), ShopActivateCouponRecord.class);
            if (CollUtil.isEmpty(records)) {
                throw new ValidateException("生成支付订单失败，优惠券信息不存在");
            } else if (records.size() != param.getCouponList().size()) {
                throw new ValidateException("生成支付订单失败，优惠券信息不正确");
            }
            boolean isFullMinus = false;
            for (ShopActivateCouponRecord record : records) {
                if (record.getType().equals(1)) {
                    if (isFullMinus) {
                        throw new ValidateException("生成支付订单失败，满减券仅可使用一张");
                    }
                    fullAmount.setPrice(record.getFullAmount());
                    discountAmount.setPrice(record.getDiscountAmount());
                    isFullMinus = true;
                } else if (record.getType().equals(2)) {
                    prodCouponMap.compute(record.getProId(), (key, oldValue) -> oldValue == null ? 1 : oldValue + 1);
                }
            }
            if (discountAmount.getPrice().compareTo(param.getFullCouponDiscountAmount()) != 0) {
                throw new ValidateException("生成支付订单失败，满减券减免金额不正确");
            }
        }
    }

    @Override
    @Transactional
    public void payCallBackOrder(@NotBlank String orderNo, @NotNull JSONObject resultJson) {
        CzgPayNotifyDTO czgCallBackDto = JSONObject.parseObject(resultJson.toString(), CzgPayNotifyDTO.class);
        OrderPayment payment = paymentService.queryChain().eq(OrderPayment::getOrderNo, orderNo).one();
        if (payment == null) {
            log.error("订单支付回调失败,支付记录不存在,payment：{}", payment);
            return;
        }
        if (StrUtil.isNotBlank(payment.getTradeNumber())) {
            log.info("订单处理过，payment id：{}", payment.getId());
            return;
        }
        paymentService.updateChain()
                .set(OrderPayment::getTradeNumber, czgCallBackDto.getPayOrderId())
                .set(OrderPayment::getRespJson, resultJson.toString())
                .where(OrderPayment::getId).eq(payment.getId())
                .update();

        if ("TRADE_SUCCESS".equals(czgCallBackDto.getState())) {
            if ("order".equals(payment.getPayType())) {
                OrderInfo orderInfo = getById(payment.getSourceId());
                if (orderInfo == null) {
                    log.error("订单支付回调失败,订单不存在,支付记录Id,{}", payment.getId());
                    return;
                }
                upOrderInfo(orderInfo, new BigDecimal(czgCallBackDto.getAmount()).divide(new BigDecimal(100), 2, RoundingMode.DOWN),
                        DateUtil.parseLocalDateTime(czgCallBackDto.getPayTime()), payment.getId(), null);
            } else if ("memberIn".equals(payment.getPayType()) || "free".equals(payment.getPayType())) {
                boolean isFree = "free".equals(payment.getPayType());
                ShopUser shopUser = shopUserService.getById(payment.getSourceId());
                if (shopUser == null) {
                    log.error("会员充值失败，会员不存在，会员id：{}", payment.getSourceId());
                } else {
                    if (shopUser.getIsVip().equals(0)) {
                        ShopUser shopUser1 = new ShopUser();
                        shopUser1.setId(shopUser.getId());
                        shopUser1.setIsVip(1);
                        shopUser1.setJoinTime(LocalDateTime.now());
                        shopUserService.updateById(shopUser1);
                    }
                    ShopUserMoneyEditDTO shopUserMoneyEditDTO = new ShopUserMoneyEditDTO()
                            .setId(payment.getSourceId())
                            .setMoney(new BigDecimal(czgCallBackDto.getAmount()).divide(new BigDecimal(100), 2, RoundingMode.DOWN))
                            .setType(1)
                            .setRelationId(payment.getId());
                    if ("WECHAT".equals(czgCallBackDto.getPayType())) {
                        shopUserMoneyEditDTO.setBizEnum(ShopUserFlowBizEnum.WECHAT_IN);
                    } else if ("ALIPAY".equals(czgCallBackDto.getPayType())) {
                        shopUserMoneyEditDTO.setBizEnum(ShopUserFlowBizEnum.ALIPAY_IN);
                    } else {
                        shopUserMoneyEditDTO.setBizEnum(ShopUserFlowBizEnum.CASH_IN);
                    }
                    //更新会员余额 并生成流水
                    Long flowId = shopUserService.updateMoney(shopUser.getShopId(), shopUserMoneyEditDTO);
                    if (payment.getRelatedId() == null) {
                        return;
                    }
                    if (isFree) {
                        shopUserMoneyEditDTO.setBizEnum(ShopUserFlowBizEnum.FREE_IN);
                        updateChain().eq(OrderInfo::getId, payment.getRelatedId())
                                .set(OrderInfo::getStatus, OrderStatusEnums.DONE.getCode())
                                .set(OrderInfo::getIsFreeDine, 1)
                                .set(OrderInfo::getPayAmount, 0)
                                .update();
                    } else {
                        //会员活动
                        activateService.giveActivate(shopUser, new BigDecimal(czgCallBackDto.getAmount()).divide(new BigDecimal(100), 2, RoundingMode.DOWN),
                                payment.getRelatedId(), flowId);
                    }

                }
            }
        }
    }

    @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;
        }
        paymentService.updateChain()
                .set(OrderPayment::getTradeNumber, czgCallBackDto.getRefundOrderId())
                .set(OrderPayment::getRespJson, resultJson.toString())
                .set(OrderPayment::getPayTime, czgCallBackDto.getRefundTime())
                .where(OrderPayment::getId).eq(payment.getId())
                .update();
        if (!"SUCCESS".equals(czgCallBackDto.getState())) {
            if ("refund".equals(payment.getPayType())) {
                //TODO 订单退款失败 暂不考虑回滚 填充退款原因
                updateChain()
                        .set(OrderInfo::getRefundRemark, czgCallBackDto.getRefundReason())
                        .eq(OrderInfo::getId, payment.getSourceId())
                        .update();
            } else if ("memberRefund".equals(payment.getPayType())) {
                //TODO 会员退款  暂不考虑回滚(钱 赠送金额 赠送的券) 填充退款原因
                flowService
                        .updateChain()
                        .set(ShopUserFlow::getFailMsg, czgCallBackDto.getRefundReason())
                        .eq(ShopUserFlow::getId, payment.getSourceId()).update();
            }
        }
    }


    /**
     * 更新订单信息 (支付成功后调用)
     *
     * @param payAmount  注意是分 还是元
     * @param payTime    支付时间
     * @param payOrderId 支付订单号
     *                   现金支付为空
     *                   会员支付为tb_shop_user_flow.id
     *                   其它支付为 tb_order_payment.id
     */
    @Override
    public void upOrderInfo(OrderInfo orderInfo, BigDecimal payAmount, LocalDateTime payTime, Long payOrderId, PayEnums payType) {
        UpdateChain<OrderInfo> updateChain = updateChain()
                .set(OrderInfo::getPayAmount, payAmount)
                .set(OrderInfo::getStatus, OrderStatusEnums.DONE.getCode())
                .set(OrderInfo::getPaidTime, payTime)
                .where(OrderInfo::getId).eq(orderInfo.getId());
        if (payOrderId != null) {
            updateChain.set(OrderInfo::getPayOrderId, payOrderId);
            orderInfo.setPayOrderId(payOrderId);
        }
        if (orderInfo.getCreditBuyerId() != null) {
            updateChain.set(OrderInfo::getCreditBuyerId, orderInfo.getCreditBuyerId());
        }
        if (ObjectUtil.isNotNull(payType)) {
            updateChain.set(OrderInfo::getPayType, payType.getValue());
            orderInfo.setPayType(payType.getValue());
        }
        boolean update = updateChain.update();
        if (update) {
            orderInfo.setPayAmount(payAmount);
            orderInfo.setStatus(OrderStatusEnums.DONE.getCode());
            orderInfo.setPaidTime(payTime);
        }
        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 {
                //积分使用
                if (orderInfo.getPointsNum() != null && orderInfo.getPointsNum() > 0) {
                    pointsService.deductPoints(shopUser.getId(), orderInfo.getPointsNum(), "积分抵扣账单", orderInfo);
                }
                //更新优惠券信息
                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());
                    }
                }
                String[] payTypes = {PayEnums.VIP_PAY.getValue(), PayEnums.CREDIT_PAY.getValue()};
                if ((orderInfo.getPayType() != null && !ArrayUtil.contains(payTypes, orderInfo.getPayType()))
                        || (payType != null && !ArrayUtil.contains(payTypes, payType))) {
                    //下单赠送积分
                    pointsService.consumeAwardPoints(shopUser.getId(), orderInfo);
                }
            }
        }
        orderDetailService.updateChain().set(OrderDetail::getStatus, OrderStatusEnums.DONE.getCode()).eq(OrderDetail::getOrderId, orderInfo.getId()).update();
//        if (!"after-pay".equals(orderInfo.getPayMode())) {
        //发送打票信息

        //orderId_0_0  订单ID_先付后付(1先付0后付)_订单状态 0未完成 1完成
        rabbitPublisher.sendOrderPrintMsg(orderInfo.getId() + "_" + (!"after-pay".equals(orderInfo.getPayMode()) ? 1 : 0) + "_1", orderInfo.getIsPrint() == 1);
//        }
        redisService.del(RedisCst.classKeyExpired.EXPIRED_ORDER + orderInfo.getId());
    }

    /**
     * 订单到期
     */
    @Override
    @Transactional
    public void expired(Long orderId) {
        OrderInfo orderInfo = getById(orderId);
        if (orderInfo.getStatus().equals(OrderStatusEnums.UNPAID.getCode())) {
            updateChain().set(OrderInfo::getStatus, OrderStatusEnums.CANCELLED.getCode())
                    .where(OrderInfo::getId).eq(orderId)
                    .update();
            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);
        return initOrderInfo(param, shopInfo, null);
    }

    /**
     * 初始化订单信息
     */
    private OrderInfo initOrderInfo(OrderInfoAddDTO param, ShopInfo shopInfo, ShopTable table) {
        OrderInfo orderInfo = new OrderInfo();
        if (param.getOrderId() != null) {
            orderInfo = getById(param.getOrderId());
            if (!OrderStatusEnums.UNPAID.getCode().equals(orderInfo.getStatus())) {
                throw new ValidateException("生成订单失败，订单已结束，请重新下单");
            }
        } else {
            orderInfo.setOrderNo(param.getPlatformType() + IdUtil.getSnowflakeNextId());
            orderInfo.setShopId(param.getShopId());
            if (table != null) {
                orderInfo.setTableCode(table.getTableCode());
                orderInfo.setTableName(table.getName());
            }
            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);
            //取餐码 多端一致
            orderInfo.setTakeCode(getCode(shopInfo.getId()));
        }
        // 餐位费
        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());
        if (param.getOrderAmount() != null && param.getOrderAmount().compareTo(BigDecimal.ZERO) >= 0) {
            orderInfo.setOrderAmount(param.getOrderAmount());
        } else {
            orderInfo.setOrderAmount(BigDecimal.ZERO);
        }
        orderInfo.setPackFee(orderInfo.getPackFee().add(param.getPackFee()));
        orderInfo.setRoundAmount(BigDecimal.ZERO);
        orderInfo.setPointsNum(0);
        saveOrUpdate(orderInfo);
        return orderInfo;
    }

    /**
     * 更新订单 优惠信息
     */
    private void upOrderPayInfo(OrderInfo orderInfo, CheckOrderPay param) {
        orderInfo.setPointsNum(param.getPointsNum());
        orderInfo.setIsPrint(param.getIsPrint());
        orderInfo.setRoundAmount(param.getRoundAmount());
        orderInfo.setOrderAmount(param.getOrderAmount());
        orderInfo.setPointsDiscountAmount(param.getPointsDiscountAmount());
        orderInfo.setProductCouponDiscountAmount(param.getProductCouponDiscountAmount());
        orderInfo.setFullCouponDiscountAmount(param.getFullCouponDiscountAmount());
        orderInfo.setDiscountAmount(param.getDiscountAmount());
        //优惠券
        orderInfo.setCouponInfoList(CollUtil.isEmpty(param.getCouponList()) ? "" : JSONObject.toJSONString(param.getCouponList()));
        //折扣信息
        orderInfo.setDiscountInfo(buildDiscountInfo(orderInfo));
        //最终折扣
        if (param.getOrderAmount().compareTo(BigDecimal.ZERO) != 0) {
            orderInfo.setDiscountRatio(orderInfo.getOrderAmount().divide(orderInfo.getOriginAmount(), 2, RoundingMode.UP));
        } else {
            orderInfo.setDiscountRatio(BigDecimal.ZERO);
        }
        //0元按照现金支付处理
        if (orderInfo.getOrderAmount().compareTo(BigDecimal.ZERO) == 0) {
            orderInfo.setStatus(OrderStatusEnums.DONE.getCode());
            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 {
                    //积分使用
                    if (orderInfo.getPointsNum() != null && orderInfo.getPointsNum() > 0) {
                        pointsService.deductPoints(shopUser.getId(), orderInfo.getPointsNum(), "积分抵扣账单", orderInfo);
                    }
                    //更新优惠券信息
                    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());
                        }
                    }
                }
            }
        }
        saveOrUpdate(orderInfo);
    }

    /**
     * 构建优惠内容
     */
    private String buildDiscountInfo(OrderInfo orderInfo) {
        JSONObject jsonObject = new JSONObject();
        if (orderInfo.getProductCouponDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
            jsonObject.put("商品券抵扣", orderInfo.getProductCouponDiscountAmount());
        }
        if (orderInfo.getDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
            jsonObject.put("打折优惠", orderInfo.getDiscountAmount());
        }
        if (orderInfo.getFullCouponDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
            jsonObject.put("满减券抵扣", orderInfo.getFullCouponDiscountAmount());
        }
        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) {
        OrderInfo orderInfo = getOne(new QueryWrapper().eq(OrderInfo::getShopId, shopId).eq(OrderInfo::getId, orderInfoPrintDTO.getId()));
        if (orderInfo == null) {
            throw new ApiNotPrintException("订单信息不存在");
        }

        switch (orderInfoPrintDTO.getType()) {
            case 0:
                printerHandler.handler(orderInfo.getId().toString(), PrinterHandler.PrintTypeEnum.ONE_AND_ORDER);
                break;
            case 1:
                printerHandler.handler(orderInfo.getId().toString(), PrinterHandler.PrintTypeEnum.PRE_ORDER);
                break;
            case 2:
                printerHandler.handler(orderInfo.getId().toString(), PrinterHandler.PrintTypeEnum.ORDER);
                break;
        }
        return true;
    }

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

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

        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 ApiNotPrintException("不处于待支付或订单详情不存在");
        }

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean cancelledOrder(Long shopId, Long orderId) {
        OrderInfo orderInfo = getById(orderId);
        if (orderInfo == null) {
            throw new ApiNotPrintException("订单不存在");
        }
        if (!OrderStatusEnums.UNPAID.getCode().equals(orderInfo.getStatus())) {
            throw new ApiNotPrintException("订单不可取消");
        }
        updateChain()
                .set(OrderInfo::getStatus, OrderStatusEnums.CANCELLED.getCode())
                .eq(OrderInfo::getShopId, shopId)
                .eq(OrderInfo::getId, orderId)
                .update();
        redisService.del(RedisCst.classKeyExpired.EXPIRED_ORDER + orderInfo.getId());
        return true;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean cancelledPlaceOrder(Long shopId, Long orderId, Integer placeNum) {
        OrderInfo orderInfo = getById(orderId);
        if (orderInfo == null) {
            throw new ApiNotPrintException("订单不存在");
        }
        if (!OrderStatusEnums.UNPAID.getCode().equals(orderInfo.getStatus())) {
            throw new ApiNotPrintException("订单不可取消");
        }
        if (orderInfo.getPlaceNum().equals(1)) {
            updateChain()
                    .set(OrderInfo::getStatus, OrderStatusEnums.CANCELLED.getCode())
                    .eq(OrderInfo::getShopId, shopId)
                    .eq(OrderInfo::getId, orderId)
                    .update();
            return true;
        }
        orderDetailService.remove(new QueryWrapper().eq(OrderDetail::getOrderId, orderId).eq(OrderDetail::getPlaceNum, placeNum));
        List<OrderDetail> list = orderDetailService.queryChain().eq(OrderDetail::getOrderId, orderId).eq(OrderDetail::getShopId, shopId).list();
        if (CollUtil.isEmpty(list)) {
            updateChain()
                    .set(OrderInfo::getStatus, OrderStatusEnums.CANCELLED.getCode())
                    .set(OrderInfo::getOriginAmount, BigDecimal.ZERO)
                    .eq(OrderInfo::getShopId, shopId)
                    .eq(OrderInfo::getId, orderId);
            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();
                }
            }
            updateChain().eq(OrderInfo::getId, orderId)
                    .eq(OrderInfo::getShopId, shopId)
                    .set(OrderInfo::getOriginAmount, totalAmount)
                    .set(OrderInfo::getPlaceNum, orderInfo.getPlaceNum() - 1)
                    .update();
        }
        return true;
    }
}
