package com.yc.ship.module.product.api;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yc.ship.framework.common.util.collection.CollectionUtils;
import com.yc.ship.framework.common.util.collection.MapUtils;
import com.yc.ship.framework.common.util.object.BeanUtils;
import com.yc.ship.module.product.api.dto.OrderRoomUseDTO;
import com.yc.ship.module.product.api.dto.ReduceStockReqDTO;
import com.yc.ship.module.product.controller.admin.voyagestockdistributeNew.vo.VoyageStockDistributeNewDetailReqVO;
import com.yc.ship.module.product.controller.admin.voyagestockdistributeNew.vo.VoyageStockDistributeNewRespVO;
import com.yc.ship.module.product.dal.dataobject.voyagestock.VoyageStockDO;
import com.yc.ship.module.product.dal.dataobject.voyagestock.VoyageStockLogDO;
import com.yc.ship.module.product.dal.dataobject.voyagestock.VoyageStockRoomUsedDO;
import com.yc.ship.module.product.dal.dataobject.voyagestockdetail.VoyageStockDetailDO;
import com.yc.ship.module.product.dal.dataobject.voyagestockdetail.VoyageStockDetailLogDO;
import com.yc.ship.module.product.dal.dataobject.voyagestockdistribute.VoyageStockDistributeNewDO;
import com.yc.ship.module.product.dal.mysql.voyagestock.VoyageStockLogMapper;
import com.yc.ship.module.product.dal.mysql.voyagestock.VoyageStockMapper;
import com.yc.ship.module.product.dal.mysql.voyagestock.VoyageStockRoomUsedMapper;
import com.yc.ship.module.product.dal.mysql.voyagestockdetail.VoyageStockDetailLogMapper;
import com.yc.ship.module.product.dal.mysql.voyagestockdetail.VoyageStockDetailMapper;
import com.yc.ship.module.product.dal.mysql.voyagestockdistribute.VoyageStockDistributeNewMapper;
import com.yc.ship.module.product.enums.DistributorOrStoreEnum;
import com.yc.ship.module.product.enums.VoyageStockLogTypeEnum;
import com.yc.ship.module.product.enums.YesOrNoEnum;
import com.yc.ship.module.product.framework.lock.ProductRedisKeyConstants;
import com.yc.ship.module.product.service.voyagestockdistribute.VoyageStockDistributeNewService;
import com.yc.ship.module.product.utils.ProductRedisUtils;
import com.yc.ship.module.trade.enums.TradeOrderStatusEnum;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.utils.UuidUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static com.yc.ship.module.product.enums.ErrorCodeConstants.*;

/**
 * @author qsl
 */
@Service
@Slf4j
public class VoyageApiImpl implements VoyageApi {

    @Resource
    private VoyageStockDistributeNewMapper voyageStockDistributeNewMapper;

    @Resource
    private VoyageStockMapper voyageStockMapper;

    @Resource
    private VoyageStockDetailMapper voyageStockDetailMapper;

    @Resource
    private VoyageStockDistributeNewService voyageStockDistributeNewService;

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private ProductRedisUtils productRedisUtils;

    @Resource
    private VoyageStockRoomUsedMapper voyageStockRoomUsedMapper;

    @Resource
    private VoyageStockLogMapper voyageStockLogMapper;

    @Resource
    private VoyageStockDetailLogMapper voyageStockDetailLogMapper;

    @Override
    @Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class)
    public void preReduceStock(ReduceStockReqDTO reqDTO) {
        log.info("开始初定订单扣库存：请求参数：{}", JSONObject.toJSONString(reqDTO));
        //TODO: 当前阶段不考虑门店库存
        log.info("开始初定订单扣库存：订单ID:{}old订单ID:{}", reqDTO.getOrderId(), reqDTO.getOldOrderId());

        Long voyageId = reqDTO.getVoyageId();
        //现在给整个航次的库存加锁
        String lockKey = String.format(ProductRedisKeyConstants.STOCK_REDIS_KEY_PREFIX, voyageId);
        RLock lock = redissonClient.getLock(lockKey);
        //用来控制redis缓存
        try {
            lock.lock(60, TimeUnit.SECONDS);
            String uuid = UuidUtils.getUUID();
            //判断是分销商还是门店下单 1：分销商，2：门店
            Integer type = reqDTO.getType();
            //分销商下单，当前阶段不考虑门店下单
            if (Objects.equals(type, DistributorOrStoreEnum.DISTRIBUTOR.getValue())) {
                //分销商下单只扣分销商库存，默认是OTA，默认OTC只能门店下单
                //初定扣分销商库存
                //先返还初定扣的库存,使用修改前一步订单的 ID
                preCancelReduceStockDistributor(reqDTO.getOrderId(), reqDTO.getType(),reqDTO.getOrderRoomList(), uuid);
                log.info("先还该订单的库存-orderId: {}", reqDTO.getOrderId());
                if (reqDTO.getOldOrderId() != null && !reqDTO.getOldOrderId().equals(reqDTO.getOrderId())) {
                    log.info("如果是修改就还修改前的订单的库存-oldOrderId: {}", reqDTO.getOldOrderId());
                    preCancelReduceStockDistributor(reqDTO.getOldOrderId(), reqDTO.getType(),reqDTO.getOrderRoomList(), uuid);
                }
                //再去扣初定的库存
                preReduceStockDistributor(reqDTO, uuid);
            }
        } finally {
            if (lock.isHeldByCurrentThread() && lock.isLocked()) {
                lock.unlock();
            }
        }
    }

    @Override
    @Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class)
    public void preCancelReduceStock(ReduceStockReqDTO reqDTO) {
        //TODO: 当前阶段不考虑门店库存
        log.info("开始初定订单还库存：请求参数：{}", JSONObject.toJSONString(reqDTO));
        Long voyageId = reqDTO.getVoyageId();
        //现在给整个航次的库存加锁
        String lockKey = String.format(ProductRedisKeyConstants.STOCK_REDIS_KEY_PREFIX, voyageId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            lock.lock(60, TimeUnit.SECONDS);
            String uuid = UuidUtils.getUUID();
            //判断是分销商还是门店下单 1：分销商，2：门店
            Integer type = reqDTO.getType();
            //分销商下单，当前阶段不考虑门店下单
            if (Objects.equals(type, DistributorOrStoreEnum.DISTRIBUTOR.getValue())) {
                //分销商下单只扣分销商库存，默认是OTA，默认OTC只能门店下单
                //初定扣分销商库存
                preCancelReduceStockDistributor(reqDTO.getOrderId(), reqDTO.getType(),reqDTO.getOrderRoomList(), uuid);
                if (reqDTO.getOldOrderId() != null && !reqDTO.getOldOrderId().equals(reqDTO.getOrderId())) {
                    preCancelReduceStockDistributor(reqDTO.getOldOrderId(), reqDTO.getType(),reqDTO.getOrderRoomList(), uuid);
                }
            }
        } finally {
            if (lock.isHeldByCurrentThread() && lock.isLocked()) {
                lock.unlock();
            }
        }
    }

    @Override
    @Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class)
    public void reduceStock(ReduceStockReqDTO reqDTO) {
        //TODO: 当前阶段不考虑门店库存
        log.info("开始确定订单扣库存：请求参数：{}", JSONObject.toJSONString(reqDTO));
        Long voyageId = reqDTO.getVoyageId();
        //现在给整个航次的库存加锁
        String lockKey = String.format(ProductRedisKeyConstants.STOCK_REDIS_KEY_PREFIX, voyageId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            lock.lock(60, TimeUnit.SECONDS);
            String uuid = UuidUtils.getUUID();
            //判断是分销商还是门店下单 1：分销商，2：门店
            Integer type = reqDTO.getType();
            //分销商下单，当前阶段不考虑门店下单
            if (Objects.equals(type, DistributorOrStoreEnum.DISTRIBUTOR.getValue())) {
                //分销商下单只扣分销商库存，默认是OTA，默认OTC只能门店下单
                //初定扣分销商库存
                //先返还初定扣的库存
                preCancelReduceStockDistributor(reqDTO.getOrderId(), reqDTO.getType(),reqDTO.getOrderRoomList(), uuid);
                if(reqDTO.getOldOrderId() != null && !reqDTO.getOldOrderId().equals(reqDTO.getOrderId())) {
                    if(reqDTO.getOldOrderStatus() != null && reqDTO.getOldOrderStatus().equals(TradeOrderStatusEnum.YD.getStatus())) {
                        preCancelReduceStockDistributor(reqDTO.getOldOrderId(), reqDTO.getType(),reqDTO.getOrderRoomList(), uuid);
                    }else {
                        cancelReduceStockDistributor(reqDTO.getOldOrderId(), reqDTO.getType(),reqDTO.getOrderRoomList(), uuid);
                    }
                }
                //再去扣确定的库存
                reduceStockDistributor(reqDTO, uuid);
            }
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw e;
        } finally {
            if (lock.isHeldByCurrentThread() && lock.isLocked()) {
                lock.unlock();
            }

        }
    }

    @Override
    @Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class)
    public void cancelReduceStock(ReduceStockReqDTO reqDTO) {
        log.info("开始确定订单还库存：请求参数：{}", JSONObject.toJSONString(reqDTO));
        //TODO: 当前阶段不考虑门店库存
        Long voyageId = reqDTO.getVoyageId();
        //现在给整个航次的库存加锁
        String lockKey = String.format(ProductRedisKeyConstants.STOCK_REDIS_KEY_PREFIX, voyageId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            lock.lock(60, TimeUnit.SECONDS);
            String uuid = UuidUtils.getUUID();
            //判断是分销商还是门店下单 1：分销商，2：门店
            Integer type = reqDTO.getType();
            //分销商下单，当前阶段不考虑门店下单
            if (Objects.equals(type, DistributorOrStoreEnum.DISTRIBUTOR.getValue())) {
                //分销商下单只扣分销商库存，默认是OTA，默认OTC只能门店下单
                //初定扣分销商库存
                cancelReduceStockDistributor(reqDTO.getOrderId(), reqDTO.getType(),reqDTO.getOrderRoomList(), uuid);
                if (reqDTO.getOldOrderId() != null && !reqDTO.getOldOrderId().equals(reqDTO.getOrderId())) {
                    cancelReduceStockDistributor(reqDTO.getOldOrderId(), reqDTO.getType(),reqDTO.getOrderRoomList(), uuid);
                }
            }
        } finally {
            if (lock.isHeldByCurrentThread() && lock.isLocked()) {
                lock.unlock();
            }
        }
    }

    @Override
    @Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class)
    public void cancelReduceStockNew(ReduceStockReqDTO reqDTO) {
        log.error("开始确定订单还库存：请求参数：{}", JSONObject.toJSONString(reqDTO));
        //TODO: 当前阶段不考虑门店库存
        Long voyageId = reqDTO.getVoyageId();
        //现在给整个航次的库存加锁
        String lockKey = String.format(ProductRedisKeyConstants.STOCK_REDIS_KEY_PREFIX, voyageId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            lock.lock(60, TimeUnit.SECONDS);
            String uuid = UuidUtils.getUUID();
            //判断是分销商还是门店下单 1：分销商，2：门店
            Integer type = reqDTO.getType();
            //分销商下单，当前阶段不考虑门店下单
            if (Objects.equals(type, DistributorOrStoreEnum.DISTRIBUTOR.getValue())) {
                //分销商下单只扣分销商库存，默认是OTA，默认OTC只能门店下单
                //初定扣分销商库存
                cancelReduceStockDistributor(reqDTO.getOrderId(), reqDTO.getType(),reqDTO.getOrderRoomList(), uuid);
                if (reqDTO.getOldOrderId() != null && !reqDTO.getOldOrderId().equals(reqDTO.getOrderId())) {
                    cancelReduceStockDistributor(reqDTO.getOldOrderId(), reqDTO.getType(),reqDTO.getOrderRoomList(), uuid);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (lock.isHeldByCurrentThread() && lock.isLocked()) {
                lock.unlock();
            }
        }
    }

    /**
     * 确定状态时取消订单还库存
     * roomUseDTOList 需要退的房间
     */
    private void cancelReduceStockDistributor(Long orderId, Integer type,List<OrderRoomUseDTO> roomUseDTOList, String uuid) {
        if (orderId == null) {
            return;
        }

        //退还航次总库存
        //找到确定时扣库存的记录
        VoyageStockLogDO voyageStockLogDO = voyageStockLogMapper.selectByOrder(orderId);
        if (voyageStockLogDO != null) {
            //删除已使用房间记录
            voyageStockRoomUsedMapper.deleteByOrderId(orderId);
            Long voyageId = voyageStockLogDO.getVoyageId();
            // 获取航次总库存
            VoyageStockDO stockDO = voyageStockMapper.selectById(voyageId);
            //还航次总库存
            BigDecimal totalNum = voyageStockLogDO.getVirtualNum().add(voyageStockLogDO.getRealNum());
            if (voyageStockLogDO.getStockType() != null && voyageStockLogDO.getStockType() == 1) {
                //退回共享库存
                stockDO.setShareNum(stockDO.getShareNum().add(voyageStockLogDO.getShareNum()));
            }
            //退回虚拟库存
            stockDO.setVirtualNum(stockDO.getVirtualNum().add(voyageStockLogDO.getVirtualNum()));
            // 减去超卖库存，减的是虚拟的
            stockDO.setOversoldNum(stockDO.getOversoldNum().subtract(voyageStockLogDO.getVirtualNum()));
            //退回真实库存
            stockDO.setRealTotalNum(stockDO.getRealTotalNum().add(voyageStockLogDO.getRealNum()));
            //退回可售库存
            stockDO.setCanSellNum(stockDO.getCanSellNum().add(totalNum));
            // 减去已预订数量
            stockDO.setBookNum(stockDO.getBookNum().subtract(totalNum));
            //更新航次总库存
            voyageStockMapper.updateById(stockDO);
            productRedisUtils.set(ProductRedisKeyConstants.STOCK_TOTAL_REDIS_KEY_PREFIX + voyageId + "_" + uuid, stockDO);
            //删除航次库存操作记录
            voyageStockLogMapper.deleteById(voyageStockLogDO);
        } else {
            log.error("订单取消时，未找到对应的航次库存操作记录，订单ID：{}", orderId);
            return;
        }
        Long voyageId = voyageStockLogDO.getVoyageId();
        Long distributorId = voyageStockLogDO.getDistributorId();
        //找到初定时扣库存详情的记录
        List<VoyageStockDetailLogDO> detailLogList = voyageStockDetailLogMapper.selectListByOrder(orderId);
        if (detailLogList != null && !detailLogList.isEmpty()) {
            Integer stockType = detailLogList.get(0).getStockType();
            //退还航次库存详情
            List<VoyageStockDetailDO> stockDetailList = voyageStockDetailMapper.selectListByVoyageId(voyageId);
            Map<String, BigDecimal> realNumMap = CollectionUtils.convertMap(detailLogList, item -> item.getRoomModelId() + "_" + item.getFloor(), VoyageStockDetailLogDO::getRealNum);
            Map<String, BigDecimal> virtualNumMap = CollectionUtils.convertMap(detailLogList, item -> item.getRoomModelId() + "_" + item.getFloor(), VoyageStockDetailLogDO::getVirtualNum);
//            Map<String, BigDecimal> shareNumMap = CollectionUtils.convertMap(detailLogList, item -> item.getRoomModelId() + "_" + item.getFloor(), VoyageStockDetailLogDO::getShareNum);
            Map<String, BigDecimal> totalNumMap = CollectionUtils.convertMap(detailLogList, item -> item.getRoomModelId() + "_" + item.getFloor(), item -> item.getRealNum().add(item.getVirtualNum()));

            stockDetailList.forEach(item -> {
                String key = item.getRoomModelId() + "_" + item.getFloor();
                BigDecimal totalNum = totalNumMap.get(key);
                if (totalNum == null) {
                    totalNum = BigDecimal.ZERO;
                }
                BigDecimal realNum = realNumMap.get(key);
                if (realNum == null) {
                    realNum = BigDecimal.ZERO;
                }
                BigDecimal virtualNum = virtualNumMap.get(key);
                if (virtualNum == null) {
                    virtualNum = BigDecimal.ZERO;
                }
                item.setBookNum(item.getBookNum().subtract(totalNum));
                item.setCanSellNum(item.getCanSellNum().add(totalNum));
                item.setRealTotalNum(item.getRealTotalNum().add(realNum));
                item.setVirtualNum(item.getVirtualNum().add(virtualNum));
                item.setOversoldNum(item.getOversoldNum().subtract(virtualNum));
                if(item.getTenantId() == null && voyageStockLogDO.getTenantId() != null) {
                    item.setTenantId(voyageStockLogDO.getTenantId());
                }
                if (stockType == 1) {//使用的是共享库存，才退回共享库存
                    item.setShareNum(item.getShareNum().add(totalNum));
                }
            });
            voyageStockDetailMapper.updateBatch(stockDetailList);
            productRedisUtils.set(ProductRedisKeyConstants.STOCK_DETAIL_REDIS_KEY_PREFIX + voyageId + "_" + uuid, stockDetailList);


            //2：还分销商库存
            if (stockType == 2) {
                //判断分销商库存是否存在
                VoyageStockDistributeNewDetailReqVO detailReqVO = new VoyageStockDistributeNewDetailReqVO();
                detailReqVO.setVoyageId(voyageId);
                detailReqVO.setType(type);
                detailReqVO.setDistributorId(distributorId);
                List<VoyageStockDistributeNewRespVO> distributeNewResp = voyageStockDistributeNewService.getDetail(detailReqVO);
                List<VoyageStockDistributeNewDO> list = BeanUtils.toBean(distributeNewResp, VoyageStockDistributeNewDO.class);
                if (list != null && !list.isEmpty()) {
                    list.forEach(item -> {
                        String key = item.getRoomModelId() + "_" + item.getFloor();
                        item.setNum(item.getNum().add(totalNumMap.get(key)));
                        item.setBookNum(item.getBookNum() == null ? BigDecimal.ZERO : item.getBookNum().subtract(totalNumMap.get(key)));
                    });
                    voyageStockDistributeNewMapper.updateBatch(list);
                    productRedisUtils.set(ProductRedisKeyConstants.STOCK_DISTRIBUTOR_REDIS_KEY_PREFIX + voyageId + "_" + distributorId + "_" + uuid, list);
                }
            }
            // 删除库存详情初定记录
            voyageStockDetailLogMapper.deleteByOrder(orderId);

        }
    }

    /**
     * 确定时扣库存,有限扣实际库存，不足再扣虚拟库存
     */
    private void reduceStockDistributor(ReduceStockReqDTO reqDTO, String uuid) {
        //航次库存操作日志
        VoyageStockLogDO voyageStockLogDO = new VoyageStockLogDO();
        //航次库存详情操作日志
        List<VoyageStockDetailLogDO> detailLogList = new ArrayList<>();

        Integer type = reqDTO.getType();
        //航次ID
        Long voyageId = reqDTO.getVoyageId();
        //分销商ID
        Long distributorId = reqDTO.getDistributorId();
        //门店ID
        Long storeId = reqDTO.getStoreId();
        //总共使用房间数量
        BigDecimal totalUseNum = reqDTO.getUseRoomNum();
        Long orderId = reqDTO.getOrderId();
        Integer orderStatus = reqDTO.getOrderStatus();

        voyageStockLogDO.setVoyageId(voyageId);
        //标识减少
        voyageStockLogDO.setType(2);
        voyageStockLogDO.setOrderId(orderId);
        voyageStockLogDO.setOrderStatus(orderStatus);
        voyageStockLogDO.setOperateType(VoyageStockLogTypeEnum.ORDER_SUB.getValue());
        voyageStockLogDO.setDistributorId(distributorId);
        voyageStockLogDO.setStoreId(storeId);
        // 获取航次总库存
        VoyageStockDO stockDO = productRedisUtils.get(ProductRedisKeyConstants.STOCK_TOTAL_REDIS_KEY_PREFIX + voyageId + "_" + uuid, VoyageStockDO.class, 1);
        if (stockDO == null) {
            stockDO = voyageStockMapper.selectById(voyageId);
        }
        if (stockDO == null) {
            throw exception(VOYAGE_NO_STOCK);
        }
        voyageStockLogDO.setTenantId(stockDO.getTenantId());
        //共享库存
        BigDecimal shareNum = stockDO.getShareNum();

        //航次库存详情
        //航次库存详情
        List<VoyageStockDetailDO> stockDetailList = productRedisUtils.getList(ProductRedisKeyConstants.STOCK_DETAIL_REDIS_KEY_PREFIX + voyageId + "_" + uuid, VoyageStockDetailDO.class, 1);
        if (CollectionUtils.isAnyEmpty(stockDetailList)) {
            stockDetailList = voyageStockDetailMapper.selectListByVoyageId(voyageId);
        }
        //判断分销商库存是否存在
        VoyageStockDistributeNewDetailReqVO detailReqVO = new VoyageStockDistributeNewDetailReqVO();
        detailReqVO.setVoyageId(voyageId);
        detailReqVO.setType(type);
        detailReqVO.setDistributorId(distributorId);
        //先获取非共享库存（分销商库存）
        detailReqVO.setEnableShare(YesOrNoEnum.NO.getType());
        List<VoyageStockDistributeNewRespVO> distributeNewResps = productRedisUtils.getList(ProductRedisKeyConstants.STOCK_DISTRIBUTOR_REDIS_KEY_PREFIX + voyageId + "_" + distributorId + "_" + uuid, VoyageStockDistributeNewRespVO.class, 1);
        if (CollectionUtils.isAnyEmpty(distributeNewResps)) {
            distributeNewResps = voyageStockDistributeNewService.getDetail(detailReqVO);
        }
        //订单使用房间详情
        List<OrderRoomUseDTO> orderRoomList = reqDTO.getOrderRoomList();
        Map<String, BigDecimal> roomModelFloorNumMap = orderRoomList.stream()
                .collect(Collectors.groupingBy(
                        OrderRoomUseDTO::getKey,
                        // 直接使用BigDecimal的reduce操作进行求和
                        Collectors.mapping(OrderRoomUseDTO::getNum, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))
                ));
        //分销商未分配库存，扣共享库存
        if (CollectionUtils.isAnyEmpty(distributeNewResps)) {
            //1共享库存
            voyageStockLogDO.setStockType(1);
            //判断共享库存是否充足
            if (shareNum.compareTo(totalUseNum) < 0) {
                log.error("{}", String.format(VOYAGE_SHARE_STOCK_NOT_ENOUGH.getMsg(), shareNum, totalUseNum));
                throw exception0(VOYAGE_SHARE_STOCK_NOT_ENOUGH.getCode(), String.format(VOYAGE_SHARE_STOCK_NOT_ENOUGH.getMsg(), shareNum, totalUseNum));
            }
            //判断航次房型楼层库存是否充足
            // 判断库存是否充足

            stockDetailList.forEach(item -> {
                BigDecimal detailShareNum = item.getShareNum();
                BigDecimal useNum = roomModelFloorNumMap.get(item.getRoomModelId() + "_" + item.getFloor());
                if (useNum == null) {
                    useNum = BigDecimal.ZERO;
                }
                if (detailShareNum.compareTo(useNum) < 0) {
                    log.error("{}", String.format(VOYAGE_SHARE_ROOM_NOT_ENOUGH.getMsg(), item.getRoomModelName(), item.getFloor(), detailShareNum, useNum));
                    throw exception0(VOYAGE_SHARE_ROOM_NOT_ENOUGH.getCode(), String.format(VOYAGE_SHARE_ROOM_NOT_ENOUGH.getMsg(), item.getRoomModelName(), item.getFloor(), detailShareNum, useNum));
                }
            });
            // 库存充足，扣库存详情
            //超卖库存
            List<BigDecimal> overSoldNum = new ArrayList<>();
            //使用的实际库存
            List<BigDecimal> useRealNum = new ArrayList<>();
            //使用的虚拟库存
            List<BigDecimal> useVirtualNum = new ArrayList<>();
            stockDetailList.forEach(item -> {
                BigDecimal useNum = roomModelFloorNumMap.get(item.getRoomModelId() + "_" + item.getFloor());
                if (useNum == null) {
                    useNum = BigDecimal.ZERO;
                }
                //航次库存详情操作日志
                VoyageStockDetailLogDO voyageStockDetailLogDO = new VoyageStockDetailLogDO();
                voyageStockDetailLogDO.setVoyageId(voyageId);
                voyageStockDetailLogDO.setType(2);//标识减少
                voyageStockDetailLogDO.setOrderId(orderId);
                voyageStockDetailLogDO.setOrderStatus(orderStatus);
                voyageStockDetailLogDO.setOperateType(VoyageStockLogTypeEnum.ORDER_SUB.getValue());
                voyageStockDetailLogDO.setRoomModelId(item.getRoomModelId());
                voyageStockDetailLogDO.setFloor(item.getFloor());
                voyageStockDetailLogDO.setDistributorId(distributorId);
                voyageStockDetailLogDO.setStoreId(storeId);
                voyageStockDetailLogDO.setStockType(1); //1共享库存


                // 减可售房间数
                item.setCanSellNum(item.getCanSellNum().subtract(useNum));
                item.setShareNum(item.getShareNum().subtract(useNum));
                // 减实际房间数，此处确定，先扣实际库存，实际库存不足再扣细虚拟库存
                if (item.getRealTotalNum().compareTo(useNum) >= 0) {
                    useRealNum.add(useNum);
                    voyageStockDetailLogDO.setVirtualNum(BigDecimal.ZERO);
                    voyageStockDetailLogDO.setRealNum(useNum);
                    item.setRealTotalNum(item.getRealTotalNum().subtract(useNum));
                } else {
                    useRealNum.add(item.getRealTotalNum().add(BigDecimal.ZERO));
                    useVirtualNum.add(useNum.subtract(item.getRealTotalNum()));
                    overSoldNum.add(useNum.subtract(item.getRealTotalNum()));
                    // 加超卖房间数
                    item.setOversoldNum(item.getOversoldNum().add(useNum.subtract(item.getRealTotalNum())));
                    voyageStockDetailLogDO.setVirtualNum(useNum.subtract(item.getRealTotalNum()));
                    voyageStockDetailLogDO.setRealNum(item.getRealTotalNum());
                    // 扣实际房间数
                    item.setVirtualNum(item.getVirtualNum().subtract(useNum.subtract(item.getRealTotalNum())));
                    item.setRealTotalNum(BigDecimal.ZERO);
                }
                // 加预定房间数
                if (item.getBookNum() != null) {
                    item.setBookNum(item.getBookNum().add(useNum));
                } else {
                    item.setBookNum(useNum);
                }

                detailLogList.add(voyageStockDetailLogDO);


            });
            voyageStockDetailMapper.updateBatch(stockDetailList);

            // 扣总库存
            // 减可售房间数
            stockDO.setCanSellNum(stockDO.getCanSellNum().subtract(totalUseNum));
            // 减实际房间数，此处确定，先扣实际库存，实际库存不足再扣虚拟库存
//            if (stockDO.getRealTotalNum().compareTo(totalUseNum) >= 0) {
//                stockDO.setRealTotalNum(stockDO.getRealTotalNum().subtract(totalUseNum));
//                voyageStockLogDO.setVirtualNum(BigDecimal.ZERO);
//                voyageStockLogDO.setRealNum(totalUseNum);
//            } else {
//                voyageStockLogDO.setRealNum(stockDO.getRealTotalNum());
//                voyageStockLogDO.setVirtualNum(totalUseNum.subtract(voyageStockLogDO.getRealNum()));
//                // 扣虚拟房间数
//                stockDO.setVirtualNum(stockDO.getVirtualNum().subtract(totalUseNum.subtract(stockDO.getRealTotalNum())));
//                stockDO.setRealTotalNum(BigDecimal.ZERO);
//            }
            //减虚拟库存
            BigDecimal totalUseVirtualNum = useVirtualNum.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            stockDO.setVirtualNum(stockDO.getVirtualNum().subtract(totalUseVirtualNum));
            voyageStockLogDO.setVirtualNum(totalUseVirtualNum);
            // 减实际库存
            BigDecimal totalUseRealNum = useRealNum.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            stockDO.setRealTotalNum(stockDO.getRealTotalNum().subtract(totalUseRealNum));
            voyageStockLogDO.setRealNum(totalUseRealNum);
            //加超卖房间数
            BigDecimal totalOverSoldNum = overSoldNum.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            stockDO.setOversoldNum(stockDO.getOversoldNum().add(totalOverSoldNum));
            // 加预定房间数
            stockDO.setBookNum(stockDO.getBookNum().add(totalUseNum));
            // 扣共享库存
            stockDO.setShareNum(stockDO.getShareNum().subtract(totalUseNum));
            voyageStockLogDO.setShareNum(totalUseNum);
            voyageStockMapper.updateById(stockDO);
        } else {
            //2分销商库存
            voyageStockLogDO.setStockType(2);

            //分销商已分配库存，扣自身库存

            //判断航次房型楼层库存是否充足
            distributeNewResps.forEach(item -> {
                BigDecimal canSellNum = item.getNum();
                BigDecimal useNum = roomModelFloorNumMap.get(item.getRoomModelId() + "_" + item.getFloor());
                if (useNum == null) {
                    useNum = BigDecimal.ZERO;
                }
                if (canSellNum.compareTo(useNum) < 0) {
                    log.error("{}", String.format(VOYAGE_DISTRIBUTOR_ROOM_NOT_ENOUGH.getMsg(), item.getRoomModelName(), item.getFloor(), canSellNum, useNum));
                    throw exception0(VOYAGE_DISTRIBUTOR_ROOM_NOT_ENOUGH.getCode(), String.format(VOYAGE_DISTRIBUTOR_ROOM_NOT_ENOUGH.getMsg(), item.getRoomModelName(), item.getFloor(), canSellNum, useNum));
                }
            });
            // 扣分销商库存
            // 库存充足，扣库存详情
            List<VoyageStockDistributeNewDO> list = BeanUtils.toBean(distributeNewResps, VoyageStockDistributeNewDO.class);
            list.forEach(item -> {
                BigDecimal useNum = roomModelFloorNumMap.get(item.getRoomModelId() + "_" + item.getFloor());
                if (useNum == null) {
                    useNum = BigDecimal.ZERO;
                }
                // 减可售房间数
                item.setNum(item.getNum().subtract(useNum));
                // 加预定房间数
                if (item.getBookNum() != null) {
                    item.setBookNum(item.getBookNum().add(useNum));
                } else {
                    item.setBookNum(useNum);
                }
            });

            voyageStockDistributeNewMapper.updateBatch(list);

            // 库存充足，扣库存详情
            //超卖库存
            List<BigDecimal> overSoldNum = new ArrayList<>();
            //使用的实际库存
            List<BigDecimal> useRealNum = new ArrayList<>();
            //使用的虚拟库存
            List<BigDecimal> useVirtualNum = new ArrayList<>();
            stockDetailList.forEach(item -> {
                BigDecimal useNum = roomModelFloorNumMap.get(item.getRoomModelId() + "_" + item.getFloor());
                if (useNum == null) {
                    useNum = BigDecimal.ZERO;
                }

                //航次库存详情操作日志
                VoyageStockDetailLogDO voyageStockDetailLogDO = new VoyageStockDetailLogDO();
                voyageStockDetailLogDO.setVoyageId(voyageId);
                voyageStockDetailLogDO.setType(2);//标识减少
                voyageStockDetailLogDO.setOrderId(orderId);
                voyageStockDetailLogDO.setOrderStatus(orderStatus);
                voyageStockDetailLogDO.setOperateType(VoyageStockLogTypeEnum.ORDER_SUB.getValue());
                voyageStockDetailLogDO.setRoomModelId(item.getRoomModelId());
                voyageStockDetailLogDO.setFloor(item.getFloor());
                voyageStockDetailLogDO.setDistributorId(distributorId);
                voyageStockDetailLogDO.setStoreId(storeId);
                voyageStockDetailLogDO.setStockType(2); //2分销商库存

                // 减可售房间数
                item.setCanSellNum(item.getCanSellNum().subtract(useNum));
                // 减实际房间数，此处确定，先扣实际库存，实际库存不足再扣虚拟库存
                if (item.getRealTotalNum().compareTo(useNum) >= 0) {
                    useRealNum.add(useNum);
                    voyageStockDetailLogDO.setRealNum(useNum);
                    voyageStockDetailLogDO.setVirtualNum(BigDecimal.ZERO);
                    item.setRealTotalNum(item.getRealTotalNum().subtract(useNum));
                } else {
                    useVirtualNum.add(useNum.subtract(item.getRealTotalNum()));
                    useRealNum.add(item.getRealTotalNum().add(BigDecimal.ZERO));
                    overSoldNum.add(useNum.subtract(item.getRealTotalNum()));
                    voyageStockDetailLogDO.setRealNum(item.getRealTotalNum());
                    voyageStockDetailLogDO.setVirtualNum(useNum.subtract(item.getRealTotalNum()));
                    // 扣虚拟房间数
                    item.setVirtualNum(item.getVirtualNum().subtract(useNum.subtract(item.getRealTotalNum())));
                    item.setRealTotalNum(BigDecimal.ZERO);

                }
                // 加预定房间数
                if (item.getBookNum() != null) {
                    item.setBookNum(item.getBookNum().add(useNum));
                } else {
                    item.setBookNum(useNum);
                }

                detailLogList.add(voyageStockDetailLogDO);

            });
            voyageStockDetailMapper.updateBatch(stockDetailList);

            // 扣总库存
            // 减可售房间数
            stockDO.setCanSellNum(stockDO.getCanSellNum().subtract(totalUseNum));
            // 减剩余房间数
//            stockDO.setSurplusNum(stockDO.getSurplusNum().subtract(totalUseNum));
            // 减实际房间数，此处确定，先扣实际库存，实际库存不足再扣虚拟库存
//            if (stockDO.getRealTotalNum().compareTo(totalUseNum) >= 0) {
//                stockDO.setRealTotalNum(stockDO.getRealTotalNum().subtract(totalUseNum));
//                voyageStockLogDO.setRealNum(totalUseNum);
//                voyageStockLogDO.setVirtualNum(BigDecimal.ZERO);
//            } else {
//                voyageStockLogDO.setRealNum(stockDO.getRealTotalNum());
//                voyageStockLogDO.setVirtualNum(totalUseNum.subtract(voyageStockLogDO.getRealNum()));
//                stockDO.setRealTotalNum(BigDecimal.ZERO);
//                // 扣虚拟房间数
//                stockDO.setVirtualNum(stockDO.getVirtualNum().subtract(totalUseNum.subtract(stockDO.getRealTotalNum())));
//            }
            //减实际库存
            BigDecimal totalUseRealNum = useRealNum.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            stockDO.setRealTotalNum(stockDO.getRealTotalNum().subtract(totalUseRealNum));
            voyageStockLogDO.setRealNum(totalUseRealNum);
            //减虚拟库存
            BigDecimal totalUseVirtualNum = useVirtualNum.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            stockDO.setVirtualNum(stockDO.getVirtualNum().subtract(totalUseVirtualNum));
            voyageStockLogDO.setVirtualNum(totalUseVirtualNum);
            //加超卖数量
            BigDecimal totalOverSoldNum = overSoldNum.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            stockDO.setOversoldNum(stockDO.getOversoldNum().add(totalOverSoldNum));
            // 加预定房间数
            stockDO.setBookNum(stockDO.getBookNum().add(totalUseNum));
            // 扣共享库存,此处为分销商库存，不扣共享库存
            voyageStockLogDO.setShareNum(BigDecimal.ZERO);
            voyageStockMapper.updateById(stockDO);
        }
        // 添加房间使用记录
        List<VoyageStockRoomUsedDO> roomUsedList = new ArrayList<>();
        Map<Long, OrderRoomUseDTO> roomIdMap = CollectionUtils.convertMap(orderRoomList, OrderRoomUseDTO::getRoomId);
        orderRoomList.forEach(item -> {
            if (item.getRoomId() == null) {
                return;
            }
            VoyageStockRoomUsedDO roomUsedDO = new VoyageStockRoomUsedDO();
            roomUsedDO.setOrderId(orderId);
            roomUsedDO.setVoyageId(voyageId);
            OrderRoomUseDTO roomRespDTO = roomIdMap.get(item.getRoomId());
            if(roomRespDTO!=null) {
                roomUsedDO.setRoomModelId(roomRespDTO.getRoomModelId());
                roomUsedDO.setFloor(roomRespDTO.getFloor());
            }
            roomUsedDO.setRoomId(item.getRoomId());
            roomUsedDO.setNum(item.getNum());
            roomUsedDO.setStatus(orderStatus);
            roomUsedList.add(roomUsedDO);
        });
        //先删除当前订单已被使用的房间
        voyageStockRoomUsedMapper.deleteByOrderId(orderId);
        if (!roomUsedList.isEmpty()) {
            voyageStockRoomUsedMapper.insertBatch(roomUsedList);
        }

        // 添加库存日志
        voyageStockLogMapper.insert(voyageStockLogDO);
        // 添加库存详情日志
        if (!detailLogList.isEmpty()) {
            voyageStockDetailLogMapper.insertBatch(detailLogList);
        }
    }

    /**
     * 初定取消还分销商库存
     */
    private void preCancelReduceStockDistributor(Long orderId, Integer type,List<OrderRoomUseDTO> orderRoomUseDTOList, String uuid) {
        if (orderId == null) {
            return;
        }
        //退还航次总库存
        //找到初定时扣库存的记录
        VoyageStockLogDO voyageStockLogDO = voyageStockLogMapper.selectByOrder(orderId);
        log.info("进入初定还库存操作-orderId：{}", orderId);
        if (voyageStockLogDO != null) {
            log.info("进入初定还总库存操作-voyageStockLogDO：{}", JSONObject.toJSONString(voyageStockLogDO));
            //删除已使用房间记录
            voyageStockRoomUsedMapper.deleteByOrderId(orderId);
            Long voyageId = voyageStockLogDO.getVoyageId();
            // 获取航次总库存
            VoyageStockDO stockDO = voyageStockMapper.selectById(voyageId);
            //还航次总库存
            BigDecimal totalNum = voyageStockLogDO.getVirtualNum().add(voyageStockLogDO.getRealNum());
            //退回共享库存
            if (voyageStockLogDO.getStockType() != null && voyageStockLogDO.getStockType() == 1) {
                stockDO.setShareNum(stockDO.getShareNum().add(voyageStockLogDO.getShareNum()));
            }
            //退回虚拟库存
            stockDO.setVirtualNum(stockDO.getVirtualNum().add(voyageStockLogDO.getVirtualNum()));
            //退回真实库存
            stockDO.setRealTotalNum(stockDO.getRealTotalNum().add(voyageStockLogDO.getRealNum()));
            //退回可售库存
            stockDO.setCanSellNum(stockDO.getCanSellNum().add(totalNum));
            // 减去已预订数量
            stockDO.setBookNum(stockDO.getBookNum().subtract(totalNum));
            //更新航次总库存
            voyageStockMapper.updateById(stockDO);
            productRedisUtils.set(ProductRedisKeyConstants.STOCK_TOTAL_REDIS_KEY_PREFIX + voyageId + "_" + uuid, stockDO);
            //删除航次库存操作记录
            voyageStockLogMapper.deleteById(voyageStockLogDO);
        } else {
            log.error("订单取消时1，未找到对应的航次库存操作记录，订单ID：{}", orderId);
            return;
        }
        Long voyageId = voyageStockLogDO.getVoyageId();
        Long distributorId = voyageStockLogDO.getDistributorId();
        //找到初定时扣库存详情的记录
        List<VoyageStockDetailLogDO> detailLogList = voyageStockDetailLogMapper.selectListByOrder(orderId);
        if (detailLogList.isEmpty()) {
            log.error("订单取消时，未找到对应的航次库存详情操作记录，订单ID：{}", orderId);
            return;
        }
        Integer stockType = detailLogList.get(0).getStockType();
        log.info("进入初定还库存详情操作,使用库存的记录-detailLogList：{}", JSONArray.toJSONString(detailLogList));
        //退还航次库存详情
        List<VoyageStockDetailDO> stockDetailList = voyageStockDetailMapper.selectListByVoyageId(voyageId);
        Map<String, BigDecimal> realNumMap = CollectionUtils.convertMap(detailLogList, item -> item.getRoomModelId() + "_" + item.getFloor(), VoyageStockDetailLogDO::getRealNum);
        Map<String, BigDecimal> virtualNumMap = CollectionUtils.convertMap(detailLogList, item -> item.getRoomModelId() + "_" + item.getFloor(), VoyageStockDetailLogDO::getVirtualNum);
//            Map<String, BigDecimal> shareNumMap = CollectionUtils.convertMap(detailLogList, item -> item.getRoomModelId() + "_" + item.getFloor(), VoyageStockDetailLogDO::getShareNum);
        Map<String, BigDecimal> totalNumMap = CollectionUtils.convertMap(detailLogList, item -> item.getRoomModelId() + "_" + item.getFloor(), item -> item.getRealNum().add(item.getVirtualNum()));

        stockDetailList.forEach(item -> {
            String key = item.getRoomModelId() + "_" + item.getFloor();
            BigDecimal totalNum = MapUtils.getBigDecimal(totalNumMap, key);
            BigDecimal realNum = MapUtils.getBigDecimal(realNumMap, key);
            BigDecimal virtualNum = MapUtils.getBigDecimal(virtualNumMap, key);
            item.setBookNum(item.getBookNum().subtract(totalNum));
            item.setCanSellNum(item.getCanSellNum().add(totalNum));
            item.setRealTotalNum(item.getRealTotalNum().add(realNum));
            item.setVirtualNum(item.getVirtualNum().add(virtualNum));
            if (stockType == 1) {
                //共享库存要还回库存详情
                item.setShareNum(item.getShareNum().add(totalNum));
            }
        });
        voyageStockDetailMapper.updateBatch(stockDetailList);
        productRedisUtils.set(ProductRedisKeyConstants.STOCK_DETAIL_REDIS_KEY_PREFIX + voyageId + "_" + uuid, stockDetailList);


        //2：还分销商库存
        if (stockType == 2) {
            //判断分销商库存是否存在
            VoyageStockDistributeNewDetailReqVO detailReqVO = new VoyageStockDistributeNewDetailReqVO();
            detailReqVO.setVoyageId(voyageId);
            detailReqVO.setType(type);
            detailReqVO.setDistributorId(distributorId);
            List<VoyageStockDistributeNewRespVO> distributeNewRespList = voyageStockDistributeNewService.getDetail(detailReqVO);
            List<VoyageStockDistributeNewDO> list = BeanUtils.toBean(distributeNewRespList, VoyageStockDistributeNewDO.class);
            log.info("进入初定还分销商库存详情操作,分销商库存还之前详情-distributeNewRespList：{}", JSONArray.toJSONString(distributeNewRespList));
            if (list != null && !list.isEmpty()) {
                list.forEach(item -> {
                    String key = item.getRoomModelId() + "_" + item.getFloor();
                    if (item.getBookNum() == null) {
                        item.setBookNum(BigDecimal.ZERO);
                    }
                    if (item.getNum() == null) {
                        item.setNum(BigDecimal.ZERO);
                    }
                    BigDecimal totalNum = MapUtils.getBigDecimal(totalNumMap, key);
                    item.setNum(item.getNum().add(totalNum));
                    item.setBookNum(item.getBookNum().subtract(totalNum));
                    if (item.getBookNum().compareTo(BigDecimal.ZERO) < 0) {
                        item.setBookNum(BigDecimal.ZERO);
                    }
                });
                log.info("进入初定还分销商库存详情操作,分销商库存还之后详情-distributeNewRespList：{}", JSONArray.toJSONString(distributeNewRespList));
                voyageStockDistributeNewMapper.updateBatch(list);
                productRedisUtils.set(ProductRedisKeyConstants.STOCK_DISTRIBUTOR_REDIS_KEY_PREFIX + voyageId + "_" + distributorId + "_" + uuid, list);
            }
        }
        // 删除库存详情初定记录
        voyageStockDetailLogMapper.deleteByOrder(orderId);


    }

    /**
     * 初定扣分销商库存
     */
    private void preReduceStockDistributor(ReduceStockReqDTO reqDTO, String uuid) {
        log.info("进入初定扣库存操作-orderId：{}", reqDTO.getOrderId());
        //航次库存操作日志
        VoyageStockLogDO voyageStockLogDO = new VoyageStockLogDO();
        //航次库存详情操作日志
        List<VoyageStockDetailLogDO> detailLogList = new ArrayList<>();

        Integer type = reqDTO.getType();
        //航次ID
        Long voyageId = reqDTO.getVoyageId();
        //分销商ID
        Long distributorId = reqDTO.getDistributorId();
        //门店ID
        Long storeId = reqDTO.getStoreId();
        //总共使用房间数量
        BigDecimal totalUseNum = reqDTO.getUseRoomNum()==null?BigDecimal.ZERO:reqDTO.getUseRoomNum();
        Long orderId = reqDTO.getOrderId();
        Integer orderStatus = reqDTO.getOrderStatus();

        voyageStockLogDO.setVoyageId(voyageId);
        //标识减少
        voyageStockLogDO.setType(2);
        voyageStockLogDO.setOrderId(orderId);
        voyageStockLogDO.setOrderStatus(orderStatus);
        voyageStockLogDO.setOperateType(VoyageStockLogTypeEnum.ORDER_PRE_SUB.getValue());
        voyageStockLogDO.setDistributorId(distributorId);
        voyageStockLogDO.setStoreId(storeId);
        // 获取航次总库存
        VoyageStockDO stockDO = productRedisUtils.get(ProductRedisKeyConstants.STOCK_TOTAL_REDIS_KEY_PREFIX + voyageId + "_" + uuid, VoyageStockDO.class, 1);
        if (stockDO == null) {
            stockDO = voyageStockMapper.selectById(voyageId);
        }
        if (stockDO == null) {
            throw exception(VOYAGE_NO_STOCK);
        }
        //共享库存
        BigDecimal shareNum = stockDO.getShareNum();

        //航次库存详情
        List<VoyageStockDetailDO> stockDetailList = productRedisUtils.getList(ProductRedisKeyConstants.STOCK_DETAIL_REDIS_KEY_PREFIX + voyageId + "_" + uuid, VoyageStockDetailDO.class, 1);
        if (CollectionUtils.isAnyEmpty(stockDetailList)) {
            stockDetailList = voyageStockDetailMapper.selectListByVoyageId(voyageId);
        }
        //判断分销商库存是否存在
        VoyageStockDistributeNewDetailReqVO detailReqVO = new VoyageStockDistributeNewDetailReqVO();
        detailReqVO.setVoyageId(voyageId);
        detailReqVO.setType(type);
        detailReqVO.setDistributorId(distributorId);
        //先获取非共享库存（分销商库存）
        detailReqVO.setEnableShare(YesOrNoEnum.NO.getType());
        List<VoyageStockDistributeNewRespVO> distributeNewRespList = productRedisUtils.getList(ProductRedisKeyConstants.STOCK_DISTRIBUTOR_REDIS_KEY_PREFIX + voyageId + "_" + distributorId + "_" + uuid, VoyageStockDistributeNewRespVO.class, 1);
        if (CollectionUtils.isAnyEmpty(distributeNewRespList)) {
            distributeNewRespList = voyageStockDistributeNewService.getDetail(detailReqVO);
        }
        //订单使用房间详情
        List<OrderRoomUseDTO> orderRoomList = reqDTO.getOrderRoomList();
        Map<String, BigDecimal> roomModelFloorNumMap = orderRoomList.stream()
                .collect(Collectors.groupingBy(
                        OrderRoomUseDTO::getKey,
                        // 直接使用BigDecimal的reduce操作进行求和
                        Collectors.mapping(OrderRoomUseDTO::getNum, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))
                ));
        //分销商未分配库存，扣共享库存
        if (CollectionUtils.isAnyEmpty(distributeNewRespList)) {
            //1共享库存
            voyageStockLogDO.setStockType(1);
            //判断共享库存是否充足
            if (shareNum.compareTo(totalUseNum) < 0) {
                log.error("{}", String.format(VOYAGE_SHARE_STOCK_NOT_ENOUGH.getMsg(), shareNum, totalUseNum));
                throw exception0(VOYAGE_SHARE_STOCK_NOT_ENOUGH.getCode(), String.format(VOYAGE_SHARE_STOCK_NOT_ENOUGH.getMsg(), shareNum, totalUseNum));
            }
            //判断航次房型楼层库存是否充足
            // 判断库存是否充足
            //使用的实际库存
            List<BigDecimal> useRealNum = new ArrayList<>();
            //使用的虚拟库存
            List<BigDecimal> useVirtualNum = new ArrayList<>();
            stockDetailList.forEach(item -> {
                //这个地方使用共享库存，不使用可销售数
//                BigDecimal canSellNum = item.getCanSellNum();
                BigDecimal detailShareNum = item.getShareNum();
                BigDecimal useNum = roomModelFloorNumMap.get(item.getRoomModelId() + "_" + item.getFloor());
                if (useNum == null) {
                    useNum = BigDecimal.ZERO;
                }
                if (detailShareNum.compareTo(useNum) < 0) {
                    log.error("{}", String.format(VOYAGE_SHARE_ROOM_NOT_ENOUGH.getMsg(), item.getRoomModelName(), item.getFloor(), detailShareNum, useNum));
                    throw exception0(VOYAGE_SHARE_ROOM_NOT_ENOUGH.getCode(), String.format(VOYAGE_SHARE_ROOM_NOT_ENOUGH.getMsg(), item.getRoomModelName(), item.getFloor(), detailShareNum, useNum));
                }
            });
            // 库存充足，扣库存详情
            stockDetailList.forEach(item -> {
                BigDecimal useNum = roomModelFloorNumMap.get(item.getRoomModelId() + "_" + item.getFloor());
                if (useNum == null) {
                    useNum = BigDecimal.ZERO;
                }
                //航次库存详情操作日志
                VoyageStockDetailLogDO voyageStockDetailLogDO = new VoyageStockDetailLogDO();
                voyageStockDetailLogDO.setVoyageId(voyageId);
                //标识减少
                voyageStockDetailLogDO.setType(2);
                voyageStockDetailLogDO.setOrderId(orderId);
                voyageStockDetailLogDO.setOrderStatus(orderStatus);
                voyageStockDetailLogDO.setOperateType(VoyageStockLogTypeEnum.ORDER_PRE_SUB.getValue());
                voyageStockDetailLogDO.setRoomModelId(item.getRoomModelId());
                voyageStockDetailLogDO.setFloor(item.getFloor());
                voyageStockDetailLogDO.setDistributorId(distributorId);
                voyageStockDetailLogDO.setStoreId(storeId);
                //1共享库存
                voyageStockDetailLogDO.setStockType(1);


                // 减可售房间数
                item.setCanSellNum(item.getCanSellNum().subtract(useNum));
                // 减共享房间数
                item.setShareNum(item.getShareNum().subtract(useNum));
                // 减虚拟房间数，此处初定，先扣虚拟库存，虚拟库存不足再扣实际库存
                if (item.getVirtualNum().compareTo(useNum) >= 0) {
                    useVirtualNum.add(useNum);
                    voyageStockDetailLogDO.setVirtualNum(useNum);
                    voyageStockDetailLogDO.setRealNum(BigDecimal.ZERO);
                    item.setVirtualNum(item.getVirtualNum().subtract(useNum));
                } else {
                    useRealNum.add(useNum.subtract(item.getVirtualNum()));
                    useVirtualNum.add(item.getVirtualNum().add(BigDecimal.ZERO));
                    voyageStockDetailLogDO.setVirtualNum(item.getVirtualNum());
                    voyageStockDetailLogDO.setRealNum(useNum.subtract(item.getVirtualNum()));
                    // 扣实际房间数
                    item.setRealTotalNum(item.getRealTotalNum().subtract(useNum.subtract(item.getVirtualNum())));
                    item.setVirtualNum(BigDecimal.ZERO);

                }
                // 加预定房间数
                if (item.getBookNum() != null) {
                    item.setBookNum(item.getBookNum().add(useNum));
                } else {
                    item.setBookNum(useNum);
                }

                detailLogList.add(voyageStockDetailLogDO);

            });
            voyageStockDetailMapper.updateBatch(stockDetailList);

            // 扣总库存
            // 减可售房间数
            stockDO.setCanSellNum(stockDO.getCanSellNum().subtract(totalUseNum));
            // 减虚拟房间数，此处初定，先扣虚拟库存，虚拟库存不足再扣实际库存
            //减实际库存
            BigDecimal totalUseRealNum = useRealNum.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            stockDO.setRealTotalNum(stockDO.getRealTotalNum().subtract(totalUseRealNum));
            voyageStockLogDO.setRealNum(totalUseRealNum);
            // 减虚拟库存
            BigDecimal totalUseVirtualNum = useVirtualNum.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            stockDO.setVirtualNum(stockDO.getVirtualNum().subtract(totalUseVirtualNum));
            voyageStockLogDO.setVirtualNum(totalUseVirtualNum);
//            if (stockDO.getVirtualNum().compareTo(totalUseNum) >= 0) {
//                stockDO.setVirtualNum(stockDO.getVirtualNum().subtract(totalUseNum));
//                voyageStockLogDO.setVirtualNum(totalUseNum);
//                voyageStockLogDO.setRealNum(BigDecimal.ZERO);
//            } else {
//                voyageStockLogDO.setVirtualNum(stockDO.getVirtualNum());
//                voyageStockLogDO.setRealNum(totalUseNum.subtract(voyageStockLogDO.getVirtualNum()));
//                // 扣实际房间数
//                stockDO.setRealTotalNum(stockDO.getRealTotalNum().subtract(totalUseNum.subtract(stockDO.getVirtualNum())));
//                stockDO.setVirtualNum(BigDecimal.ZERO);
//            }
            // 加预定房间数
            stockDO.setBookNum(stockDO.getBookNum().add(totalUseNum));
            // 扣共享库存
            stockDO.setShareNum(stockDO.getShareNum().subtract(totalUseNum));
            voyageStockLogDO.setShareNum(totalUseNum);
            voyageStockMapper.updateById(stockDO);
        } else {
            //2分销商库存
            voyageStockLogDO.setStockType(2);
            //分销商已分配库存，扣自身库存

            //判断航次房型楼层库存是否充足
            distributeNewRespList.forEach(item -> {
                BigDecimal canSellNum = item.getNum();
                BigDecimal useNum = roomModelFloorNumMap.get(item.getRoomModelId() + "_" + item.getFloor());
                if (useNum == null) {
                    useNum = BigDecimal.ZERO;
                }
                if (canSellNum.compareTo(useNum) < 0) {
                    log.error("{}", String.format(VOYAGE_DISTRIBUTOR_ROOM_NOT_ENOUGH.getMsg(), item.getRoomModelName(), item.getFloor(), canSellNum, useNum));
                    throw exception0(VOYAGE_DISTRIBUTOR_ROOM_NOT_ENOUGH.getCode(), String.format(VOYAGE_DISTRIBUTOR_ROOM_NOT_ENOUGH.getMsg(), item.getRoomModelName(), item.getFloor(), canSellNum, useNum));
                }
            });
            // 扣分销商库存
            // 库存充足，扣库存详情
            List<VoyageStockDistributeNewDO> list = BeanUtils.toBean(distributeNewRespList, VoyageStockDistributeNewDO.class);
            list.forEach(item -> {
                BigDecimal useNum = roomModelFloorNumMap.get(item.getRoomModelId() + "_" + item.getFloor());
                if (useNum == null) {
                    useNum = BigDecimal.ZERO;
                }
                // 减可售房间数
                item.setNum(item.getNum().subtract(useNum));
                // 加预定房间数
                if (item.getBookNum() != null) {
                    item.setBookNum(item.getBookNum().add(useNum));
                } else {
                    item.setBookNum(useNum);
                }
            });

            voyageStockDistributeNewMapper.updateBatch(list);

            // 库存充足，扣库存详情
            //使用的实际库存
            List<BigDecimal> useRealNum = new ArrayList<>();
            //使用的虚拟库存
            List<BigDecimal> useVirtualNum = new ArrayList<>();
            stockDetailList.forEach(item -> {
                BigDecimal useNum = roomModelFloorNumMap.get(item.getRoomModelId() + "_" + item.getFloor());
                if (useNum == null) {
                    useNum = BigDecimal.ZERO;
                }

                //航次库存详情操作日志
                VoyageStockDetailLogDO voyageStockDetailLogDO = new VoyageStockDetailLogDO();
                voyageStockDetailLogDO.setVoyageId(voyageId);
                voyageStockDetailLogDO.setType(2);//标识减少
                voyageStockDetailLogDO.setOrderId(orderId);
                voyageStockDetailLogDO.setOrderStatus(orderStatus);
                voyageStockDetailLogDO.setOperateType(VoyageStockLogTypeEnum.ORDER_PRE_SUB.getValue());
                voyageStockDetailLogDO.setRoomModelId(item.getRoomModelId());
                voyageStockDetailLogDO.setFloor(item.getFloor());
                voyageStockDetailLogDO.setDistributorId(distributorId);
                voyageStockDetailLogDO.setStoreId(storeId);
                //2分销商库存
                voyageStockDetailLogDO.setStockType(2);

                // 减可售房间数
                item.setCanSellNum(item.getCanSellNum().subtract(useNum));
                // 减虚拟房间数，此处初定，先扣虚拟库存，虚拟库存不足再扣实际库存
                if (item.getVirtualNum().compareTo(useNum) >= 0) {
                    useVirtualNum.add(useNum);
                    voyageStockDetailLogDO.setVirtualNum(useNum);
                    voyageStockDetailLogDO.setRealNum(BigDecimal.ZERO);
                    item.setVirtualNum(item.getVirtualNum().subtract(useNum));
                } else {
                    useRealNum.add(useNum.subtract(item.getVirtualNum()));
                    useVirtualNum.add(item.getVirtualNum().add(BigDecimal.ZERO));
                    voyageStockDetailLogDO.setVirtualNum(item.getVirtualNum());
                    voyageStockDetailLogDO.setRealNum(useNum.subtract(item.getVirtualNum()));
                    // 扣实际房间数
                    item.setRealTotalNum(item.getRealTotalNum().subtract(useNum.subtract(item.getVirtualNum())));
                    item.setVirtualNum(BigDecimal.ZERO);
                }
                // 加预定房间数
                if (item.getBookNum() != null) {
                    item.setBookNum(item.getBookNum().add(useNum));
                } else {
                    item.setBookNum(useNum);
                }

                detailLogList.add(voyageStockDetailLogDO);

            });
            voyageStockDetailMapper.updateBatch(stockDetailList);

            // 扣总库存
            // 减可售房间数
            stockDO.setCanSellNum(stockDO.getCanSellNum().subtract(totalUseNum));
            // 减剩余房间数
//            stockDO.setSurplusNum(stockDO.getSurplusNum().subtract(totalUseNum));
            // 减虚拟房间数，此处初定，先扣虚拟库存，虚拟库存不足再扣实际库存
            //减实际库存
            BigDecimal totalUseRealNum = useRealNum.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            stockDO.setRealTotalNum(stockDO.getRealTotalNum().subtract(totalUseRealNum));
            voyageStockLogDO.setRealNum(totalUseRealNum);
            // 减虚拟库存
            BigDecimal totalUseVirtualNum = useVirtualNum.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            stockDO.setVirtualNum(stockDO.getVirtualNum().subtract(totalUseVirtualNum));
            voyageStockLogDO.setVirtualNum(totalUseVirtualNum);
//            if (stockDO.getVirtualNum().compareTo(totalUseNum) >= 0) {
//                stockDO.setVirtualNum(stockDO.getVirtualNum().subtract(totalUseNum));
//                voyageStockLogDO.setVirtualNum(totalUseNum);
//                voyageStockLogDO.setRealNum(BigDecimal.ZERO);
//            } else {
//                voyageStockLogDO.setVirtualNum(stockDO.getVirtualNum());
//                voyageStockLogDO.setRealNum(totalUseNum.subtract(voyageStockLogDO.getVirtualNum()));
//                stockDO.setVirtualNum(BigDecimal.ZERO);
//                // 扣实际房间数
//                stockDO.setRealTotalNum(stockDO.getRealTotalNum().subtract(totalUseNum.subtract(stockDO.getVirtualNum())));
//            }
            // 加预定房间数
            stockDO.setBookNum(stockDO.getBookNum().add(totalUseNum));
            // 扣共享库存,此处为分销商库存，不扣共享库存
            voyageStockLogDO.setShareNum(BigDecimal.ZERO);
            voyageStockMapper.updateById(stockDO);
        }
        // 添加房间使用记录
        List<VoyageStockRoomUsedDO> roomUsedList = new ArrayList<>();
        Map<Long, OrderRoomUseDTO> roomIdMap = CollectionUtils.convertMap(orderRoomList, OrderRoomUseDTO::getRoomId);
        orderRoomList.forEach(item -> {
            if (item.getRoomId() == null) {
                return;
            }
            VoyageStockRoomUsedDO roomUsedDO = new VoyageStockRoomUsedDO();
            roomUsedDO.setOrderId(orderId);
            roomUsedDO.setVoyageId(voyageId);
            OrderRoomUseDTO roomRespDTO = roomIdMap.get(item.getRoomId());
            if(roomRespDTO!=null) {
                roomUsedDO.setRoomModelId(roomRespDTO.getRoomModelId());
                roomUsedDO.setFloor(roomRespDTO.getFloor());
            }
            roomUsedDO.setRoomId(item.getRoomId());
            roomUsedDO.setNum(item.getNum());
            roomUsedDO.setStatus(orderStatus);
            roomUsedList.add(roomUsedDO);
        });
        //先删除当前订单已被使用的房间
        voyageStockRoomUsedMapper.deleteByOrderId(orderId);
        if (!roomUsedList.isEmpty()) {
            voyageStockRoomUsedMapper.insertBatch(roomUsedList);
        }
        voyageStockLogDO.setTenantId(stockDO.getTenantId());
        // 添加库存日志
        voyageStockLogMapper.insert(voyageStockLogDO);
        // 添加库存详情日志
        if (!detailLogList.isEmpty()) {
            voyageStockDetailLogMapper.insertBatch(detailLogList);
        }
    }
}
