package cn.iocoder.yudao.module.order.service.orderWarehouseIn;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.apollo.core.event.BoxCheckOrderSchedulingEvent;
import cn.iocoder.yudao.framework.apollo.core.event.QueryChannelInfoEvent;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO;
import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
import cn.iocoder.yudao.framework.i18n.core.I18nMessage;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService;
import cn.iocoder.yudao.framework.mybatis.core.vo.PageVO;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.module.bpm.enums.WorkFlowEmus;
import cn.iocoder.yudao.module.customer.dal.dataobject.customer.CustomerDO;
import cn.iocoder.yudao.module.customer.dal.dataobject.customerContacts.CustomerContactsDO;
import cn.iocoder.yudao.module.customer.dal.mysql.customer.CustomerMapper;
import cn.iocoder.yudao.module.customer.service.customer.CustomerService;
import cn.iocoder.yudao.module.customer.service.customerContacts.CustomerContactsService;
import cn.iocoder.yudao.module.customer.service.zhongPao.ZhongPaoService;
import cn.iocoder.yudao.module.customer.vo.zhongPao.CustomerZhongPaoQueryVO;
import cn.iocoder.yudao.module.customer.vo.zhongPao.ZhongPaoBestVO;
import cn.iocoder.yudao.module.depository.dal.dataobject.lineChannelPackaging.LineChannelPackagingDO;
import cn.iocoder.yudao.module.depository.dal.dataobject.warehouse.WarehouseAreaDO;
import cn.iocoder.yudao.module.depository.dal.dataobject.warehouse.WarehouseAreaPositionDO;
import cn.iocoder.yudao.module.depository.dal.mysql.warehouse.WarehouseAreaMapper;
import cn.iocoder.yudao.module.depository.dal.mysql.warehouse.WarehouseAreaPositionMapper;
import cn.iocoder.yudao.module.depository.dal.mysql.warehouse.WarehouseLineMapper;
import cn.iocoder.yudao.module.depository.dto.LogisticsInfoDto;
import cn.iocoder.yudao.module.depository.service.lineChannelPackaging.LineChannelPackagingService;
import cn.iocoder.yudao.module.depository.service.warehouse.WarehouseService;
import cn.iocoder.yudao.module.ecw.api.currency.CurrencyApi;
import cn.iocoder.yudao.module.ecw.api.currency.dto.CurrencyRespDTO;
import cn.iocoder.yudao.module.ecw.api.internalMessage.ClientInternalMessageApi;
import cn.iocoder.yudao.module.ecw.api.internalMessage.dto.InternalMessageCreateDto;
import cn.iocoder.yudao.module.ecw.enums.CustomerStatusEnum;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO;
import cn.iocoder.yudao.module.order.convert.orderItem.OrderItemConvert;
import cn.iocoder.yudao.module.order.convert.orderLocation.OrderLocationConvert;
import cn.iocoder.yudao.module.order.convert.orderWarehouseIn.OrderWarehouseInConvert;
import cn.iocoder.yudao.module.order.dal.dataobject.order.OrderDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderCargoControl.OrderCargoControlDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderConsignee.OrderConsigneeDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderConsignor.OrderConsignorDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderException.OrderExceptionDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderExceptionResult.OrderExceptionResultDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderItem.OrderItemDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderItemPackLog.OrderItemPackLogDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderLabel.OrderLabelDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderLocation.OrderLocationDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderSpecialNeed.OrderSpecialNeedDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderWarehouseApproval.OrderWarehouseApprovalDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderWarehouseIn.OrderWarehouseInDO;
import cn.iocoder.yudao.module.order.dal.mysql.orderWarehouseIn.OrderWarehouseInMapper;
import cn.iocoder.yudao.module.order.enums.*;
import cn.iocoder.yudao.module.order.service.order.*;
import cn.iocoder.yudao.module.order.service.orderCargoControl.OrderCargoControlService;
import cn.iocoder.yudao.module.order.service.orderException.OrderExceptionService;
import cn.iocoder.yudao.module.order.service.orderExceptionResult.OrderExceptionResultService;
import cn.iocoder.yudao.module.order.service.orderItemPackLog.OrderItemPackLogService;
import cn.iocoder.yudao.module.order.service.orderLabel.OrderLabelService;
import cn.iocoder.yudao.module.order.service.orderWarehouseApproval.OrderWarehouseApprovalService;
import cn.iocoder.yudao.module.order.service.orderWarehousePicture.OrderWarehousePictureService;
import cn.iocoder.yudao.module.order.vo.order.*;
import cn.iocoder.yudao.module.order.vo.orderException.OrderExceptionCreateReqVO;
import cn.iocoder.yudao.module.order.vo.orderException.OrderExceptionDescVO;
import cn.iocoder.yudao.module.order.vo.orderException.additional.ChannelPackagingOverWeightAdditionalBo;
import cn.iocoder.yudao.module.order.vo.orderException.additional.GoodsLineOverWeightAdditionalBo;
import cn.iocoder.yudao.module.order.vo.orderItem.OrderItemBackVO;
import cn.iocoder.yudao.module.order.vo.orderItem.OrderItemInWarehouseVO;
import cn.iocoder.yudao.module.order.vo.orderItemPackLog.OrderItemPackLogCreateReqVO;
import cn.iocoder.yudao.module.order.vo.orderLabel.OrderLabelBackVO;
import cn.iocoder.yudao.module.order.vo.orderLabel.OrderLabelDto;
import cn.iocoder.yudao.module.order.vo.orderLabel.OrderLabelQueryVO;
import cn.iocoder.yudao.module.order.vo.orderLabel.SaveOrUpdateOrderLabelDto;
import cn.iocoder.yudao.module.order.vo.orderLocation.OrderLocationBackVO;
import cn.iocoder.yudao.module.order.vo.orderLocation.OrderLocationCreateReqVO;
import cn.iocoder.yudao.module.order.vo.orderLocation.OrderLocationMergeVO;
import cn.iocoder.yudao.module.order.vo.orderSpecialNeed.OrderSpecialNeedReceivableReqVo;
import cn.iocoder.yudao.module.order.vo.orderWarehouseIn.*;
import cn.iocoder.yudao.module.product.dal.dataobject.product.ProductAttrDO;
import cn.iocoder.yudao.module.product.dal.dataobject.product.ProductDO;
import cn.iocoder.yudao.module.product.dal.dataobject.product.ProductPriceDO;
import cn.iocoder.yudao.module.product.dal.dataobject.productbrank.ProductBrankDO;
import cn.iocoder.yudao.module.product.dal.mysql.product.ProductAttrMapper;
import cn.iocoder.yudao.module.product.dal.mysql.productbrank.ProductBrankMapper;
import cn.iocoder.yudao.module.product.service.product.ProductAttrService;
import cn.iocoder.yudao.module.product.service.product.ProductPriceService;
import cn.iocoder.yudao.module.product.service.product.ProductService;
import cn.iocoder.yudao.module.product.service.productbrandempower.ProductBrandEmpowerService;
import cn.iocoder.yudao.module.product.service.productbrank.ProductBrankService;
import cn.iocoder.yudao.module.product.vo.productbrandempower.GetFeeTypeProductBrandByOrderEmpowerReqVO;
import cn.iocoder.yudao.module.product.vo.productbrandempower.GetFeeTypeProductBrandEmpowerRespVO;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.sms.SmsSendApi;
import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import cn.iocoder.yudao.module.wealth.dal.dataobject.receivable.ReceivableDO;
import cn.iocoder.yudao.module.wealth.service.receivable.ReceivableService;
import cn.iocoder.yudao.module.wealth.vo.receivable.ReceivableQueryVO;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.apollo.core.constants.Constants.NOT_ACCEPTED_PROD_CODE;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.order.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.wealth.enums.ErrorCodeConstants.RECEIVABLE_WRITE_OFF_ING_NO_NEED_TO_PACK;

/**
 * 入仓货物详情 Service 实现类
 *
 * @author yanghao
 */
@Slf4j
@Service
@Validated
public class OrderWarehouseInServiceImpl extends AbstractService<OrderWarehouseInMapper, OrderWarehouseInDO> implements OrderWarehouseInService {

    @Resource
    private OrderWarehouseInMapper orderWarehouseInMapper;
    @Resource
    private ProductBrankMapper productBrankMapper;
    @Resource
    private OrderWarehouseApprovalService orderWarehouseApprovalService;

    @Resource
    private OrderExceptionService orderExceptionService;

    @Resource
    private OrderExceptionResultService orderExceptionResultService;

    @Resource
    private ProductAttrService productAttrService;

    @Resource
    private ZhongPaoService zhongPaoService;

    @Resource
    private WarehouseLineMapper warehouseLineMapper;

    @Resource
    private CustomerMapper customerMapper;

    @Resource
    private CustomerService customerService;

    @Resource
    @Lazy
    private OrderService orderService;
    @Resource
    @Lazy
    private OrderQueryService orderQueryService;

    @Resource
    private OrderConsignorService orderConsignorService;

    @Resource
    private OrderConsigneeService orderConsigneeService;

    @Resource
    private OrderItemService orderItemService;

    @Resource
    @Lazy
    private OrderAirService orderAirService;

    @Resource
    @Lazy
    private OrderLocationService orderLocationService;

    @Resource
    private WarehouseAreaMapper warehouseAreaMapper;

    @Resource
    private WarehouseAreaPositionMapper warehouseAreaPositionMapper;

    @Resource
    private OrderSpecialNeedService orderSpecialNeedService;

    @Resource
    @Lazy
    private OrderWarehousePictureService orderWarehousePictureService;
    @Resource
    @Lazy
    private OrderBusinessService orderBusinessService;

    @Resource
    @Lazy
    private OrderLabelService orderLabelService;

    @Resource
    private SmsSendApi smsSendApi;

    @Resource
    private CurrencyApi currencyApi;

    @Resource
    @Lazy
    private OrderCargoControlService orderCargoControlService;

    @Resource
    private ClientInternalMessageApi clientInternalMessageApi;

    @Resource
    private CustomerContactsService customerContactsService;

    @Resource
    private MemberUserApi memberUserApi;

    @Resource
    private ReceivableService receivableService;

    @Resource
    private WarehouseService warehouseService;

    @Resource
    private ProductBrandEmpowerService productBrandEmpowerService;

    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private ProductAttrMapper productAttrMapper;

    @Resource
    private ProductService productService;

    @Resource
    private ProductPriceService productPriceService;

    @Resource
    private ProductBrankService productBrankService;

    @Resource
    private DictDataApi dictDataApi;

    @Resource
    private OrderItemPackLogService orderItemPackLogService;

    @Resource
    private LineChannelPackagingService lineChannelPackagingService;

    /**
     * 验证商品属性是否包含“不接受货物”
     *
     * @param prodId
     * @param orderNo
     */
    private void validateProdAttrAccess(Long prodId, String orderNo) {
        ProductDO productDO = productService.info(prodId);
        if (productDO == null) {
            throw exception(PROD_NOT_EXISTS);
        }
        if (CollectionUtil.isNotEmpty(productDO.getAttrList())) {
            long count = productDO.getAttrList().stream().map(ProductAttrDO::getAttrCode).filter(code -> StringUtils.equals(code, NOT_ACCEPTED_PROD_CODE)).count();
            if (count > 0) {

                if (StringUtils.isNotBlank(orderNo)) {
                    // 订单【{}】包含不接受货物【{}】，请检查
                    throw exception(ORDER_NO_CONTAIN_NOT_ACCEPTED_PROD, orderNo, I18nMessage.getLang() == 0 ? productDO.getTitleZh() : productDO.getTitleEn());
                } else {
                    // 订单包含不接受货物，请检查
                    throw exception(ORDER_CONTAIN_NOT_ACCEPTED_PROD);
                }
            }
        }
    }

    private void throwProcessingApproval(OrderDO orderDO) {
        // 费用申请中可以入仓和完成入仓。 详见字典order_approval_type
        if (orderDO.getAuditType() != 0 && orderDO.getAuditType() > 5 && orderDO.getAuditType() != 12) {
            throw exception(ORDER_HAS_PROCESSING_APPROVAL, orderDO.getOrderNo());
        }
    }

    /*
     创建入仓记录
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createOrderWarehouseIn(@Valid OrderWarehouseInCreateReqVO
                                                  createReqVO) {

        Long orderId = createReqVO.getOrderId();
        Long brand = createReqVO.getBrand();
        Long orderItemId = createReqVO.getOrderItemId();
        List<OrderWarehouseInItemDto> orderWarehouseInItemDoList =
                createReqVO.getOrderWarehouseInItemDoList();

        // 非下单货物，请求中包含
        String prodTitleZh = createReqVO.getProdTitleZh();
        String prodTitleEn = createReqVO.getProdTitleEn();

        OrderItemDO orderItemDO = null;
        // 下单货物，
        if (orderItemId != null) {
            orderItemDO = orderItemService.selectOne(OrderItemDO::getOrderItemId,
                    orderItemId);

            prodTitleZh = orderItemDO.getProdTitleZh();
            prodTitleEn = orderItemDO.getProdTitleEn();
        }
        OrderDO orderDO = orderService.getById(orderId);
        if (orderDO == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_NOT_EXISTS);
        }
        if (OrderStatusEnum.DRAFT.getValue().equals(orderDO.getStatus())) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_DRAFT_STATUS_NOT_ALLOWED_WAREHOUSE_IN);
        }
        if (OrderStatusEnum.WAREHOUSE_ADJUSTMENT.getValue().equals(orderDO.getStatus())) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_WAREHOUSE_ADJUSTMENT_STATUS_NOT_ALLOWED_WAREHOUSE_IN);
        }

        // 判断是否有未处理的审核单
        throwProcessingApproval(orderDO);

        this.validateProdAttrAccess(createReqVO.getProdId(),
                orderDO.getOrderNo());


        validateWarehouseInItem(orderDO,
                brand,
                orderWarehouseInItemDoList,
                prodTitleZh,
                prodTitleEn);
        // 拆单时系统会自动入仓，跳过此判断
        if (!createReqVO.getIsSplitOrderAutoCreate()) {
            if (CollectionUtil.isEmpty(createReqVO.getPictureUrls())) {
                throw exception(ErrorCodeConstants.ORDER_WAREHOUSE_IN_PICTURE_NOT_NULL);
            }

            // 拆单订单不可追加商品和添加新入仓纪录
            if (orderQueryService.isSplitOrderChildren(orderDO)) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.SPLIT_ORDER_CAN_NOT_WAREHOUSE_IN);
            }
            // 订单排单校验
            applicationContext.publishEvent(
                    new BoxCheckOrderSchedulingEvent(orderId));
        }

        // 若已经存在入仓纪录，则就是追加。
        List<OrderWarehouseInDO> orderWarehouseInDOS =
                orderWarehouseInMapper.selectList(new LambdaQueryWrapperX<OrderWarehouseInDO>()
                        .eq(OrderWarehouseInDO::getOrderId, orderId).eq(OrderWarehouseInDO::getOrderItemId, orderItemId));
        boolean isAppend = CollectionUtil.isNotEmpty(orderWarehouseInDOS);


        // 执行入仓
        this.doSaveOrUpdateOrderWarehouseInDo(createReqVO, orderId, orderItemId, orderDO, createReqVO.getPictureUrls(), false, true);

        // 更新订单入仓信息
        OrderWarehouseInVO orderWarehouseInVO = new OrderWarehouseInVO();
        orderWarehouseInVO.setOrderId(orderId);
        orderService.orderInWarehouse(orderWarehouseInVO);

        // 更新订单状态 - 入库中
        orderService.updateStatus(orderId, orderDO.getOrderNo(),
                OrderStatusEnum.WAREHOUSING.getValue(),
                null,
                OrderWarehouseInStatusEnum.warehousing.getValue(), null, null, null, false);

        // 纪录操作日志
        if (createReqVO.getIsAddOrderOperateLog()) {
            List<ApplyInfoVO> applyInfoVOList = new ArrayList<>();
            OrderWarehouseInUpdateApplyReqVO orderWarehouseInUpdateApplyReqVO = BeanUtil.copyProperties(createReqVO, OrderWarehouseInUpdateApplyReqVO.class);
            orderWarehouseInUpdateApplyReqVO.setOrderWarehouseInUpdateItemDoList(createReqVO.getOrderWarehouseInItemDoList());
            if (orderItemDO != null) {
                compareOrderItemField(orderWarehouseInUpdateApplyReqVO, orderItemDO, applyInfoVOList);
            }
            prodTitleZh = createReqVO.getProdTitleZh();
            this.compareOrderWarehouseInField(prodTitleZh, new ArrayList<>(), createReqVO.getOrderWarehouseInItemDoList(), applyInfoVOList);

            String msg = (isAppend ? "追加-" : "") + (createReqVO.getType() == 0 ? "货物入仓" : "添加新品名");
            orderBusinessService.addOrderOperateLog(orderId, "仓库操作", msg, applyInfoVOList);
        }

        // 20230511 订单入仓时，
        // 判断订单是发货人不是同行或代理的web订单收货人没有客户档案且入仓时间-订单创建时间<=14天，
        // 则生成收货人的客户档案，客户经理为发货人客户经理。
        // 同时更新相同收货人的其他订单对应的收货人客户id。
        // （因为同收货人可能有多张订单）
        // 14天内
        if (DateUtil.offsetDay(orderDO.getCreateTime(),
                14).compareTo(new Date()) >= 0) {
            // 发货人信息
            OrderConsignorDO orderConsignorDO =
                    orderConsignorService.getOrderConsignorByOrderId(orderId);
            if (orderConsignorDO != null && orderConsignorDO.getCustomerId() != null) {
                CustomerDO orderConsignorCustomer =
                        customerService.getCustomer(orderConsignorDO.getCustomerId());
                // 发货人不是代理或同行
                if (orderConsignorCustomer != null &&
                        StringUtils.isNotEmpty(orderConsignorCustomer.getRoles())
                        && !orderConsignorCustomer.getRoles().contains("2") &&
                        !orderConsignorCustomer.getRoles().contains("3")) {
                    // 收货人信息
                    OrderConsigneeDO orderConsigneeDO =
                            orderConsigneeService.getOrderConsigneeByOrderId(orderId);
                    if (orderConsigneeDO != null &&
                            (orderConsigneeDO.getCustomerId() == null ||
                                    orderConsigneeDO.getCustomerContactsId() == null
                                    || orderConsigneeDO.getCustomerId() == 0L ||
                                    orderConsigneeDO.getCustomerContactsId() == 0L)) {

                        CustomerContactsDO consigeeCustomer =
                                customerService.getUniqueOneAndValidate(
                                        orderConsigneeDO.getCountryCode(),
                                        orderConsigneeDO.getPhone(),
                                        null);
                        if (consigeeCustomer == null) {
                            // 生成收货人档案
                            consigeeCustomer = customerService.createConsigeeCustomer(
                                    orderConsigneeDO.getName(),
                                    orderConsigneeDO.getCountryCode(),
                                    orderConsigneeDO.getPhone(),
                                    orderConsigneeDO.getCompany(),
                                    orderConsigneeDO.getEmail(),
                                    orderConsignorCustomer, orderDO.getOrderNo());
                        }
                        if (consigeeCustomer != null) {
                            orderConsigneeDO.setCustomerId(consigeeCustomer.getCustomerId());
                            orderConsigneeDO.setCustomerContactsId(consigeeCustomer.getId());
                            orderConsigneeService.updateById(orderConsigneeDO);

                            // 并更新其他收货人
                            List<OrderConsigneeDO> otherConsigneeDOList =
                                    orderConsigneeService.selectList(new LambdaQueryWrapperX<OrderConsigneeDO>()
                                            .eq(OrderConsigneeDO::getCountryCode, orderConsigneeDO.getCountryCode())
                                            .eq(OrderConsigneeDO::getPhone, orderConsigneeDO.getPhone())
                                            .apply("deleted = 0 and order_id != " + orderId + " and (customer_id is null or customer_id = 0 or customer_contacts_id is null or customer_contacts_id = 0)"));
                            if (CollectionUtil.isNotEmpty(otherConsigneeDOList)) {
                                for (OrderConsigneeDO consigneeDO : otherConsigneeDOList) {
                                    consigneeDO.setCustomerId(consigeeCustomer.getCustomerId());
                                    consigneeDO.setCustomerContactsId(consigeeCustomer.getId());
                                    orderConsigneeService.updateById(consigneeDO);
                                }
                            }

                            // 更新订单所属人
                            if (orderDO.getCustomerId() == null || orderDO.getCustomerId() == 0) {
                                orderService.update(new LambdaUpdateWrapper<OrderDO>().set(OrderDO::getCustomerId, consigeeCustomer.getCustomerId()).eq(OrderDO::getOrderId, orderDO.getOrderId()));
                            }

                        }
                    }
                }
            }
        }

        // 返回
        return true;
    }

    /**
     * 入仓
     *
     * @param createReqVO
     * @param orderId
     * @param orderItemId
     * @param orderDO
     * @param pictureUrls
     * @param isDeleteNotInWarehouseIn
     * @param isUpdateWarehouseProdAttrIds
     * @return 返回订单项id
     */
    private Long doSaveOrUpdateOrderWarehouseInDo(
            OrderWarehouseInCreateReqVO createReqVO,
            Long orderId, Long orderItemId, OrderDO orderDO,
            List<String> pictureUrls, boolean isDeleteNotInWarehouseIn,
            boolean isUpdateWarehouseProdAttrIds) {

        //
        boolean isAddNewOrderItem = createReqVO.getType() != 0;
        OrderItemDO orderItemDO;
        String unit = null;

        //查询原有的纪录
        List<OrderWarehouseInDO> orderWarehouseInListOld =
                orderWarehouseInMapper
                        .selectList(new LambdaQueryWrapperX<OrderWarehouseInDO>()
                                .eq(OrderWarehouseInDO::getOrderId, orderId)
                                .eq(OrderWarehouseInDO::getOrderItemId, orderItemId));

        List<OrderWarehouseInItemDto> orderWarehouseInItemDoList = createReqVO.getOrderWarehouseInItemDoList();
        if (CollectionUtil.isNotEmpty(orderWarehouseInItemDoList)) {
            unit = orderWarehouseInItemDoList.stream().findFirst().get().getUnit();
        }
        // 非下单货物，需要保存此信息到orderItem
        if (orderItemId == null && Integer.valueOf(1).equals(createReqVO.getType())) {
            orderItemDO = createNewOrderItem(createReqVO, orderDO, unit);
            orderItemId = orderItemDO.getOrderItemId();
        } else {
            orderItemDO = orderItemService.getById(orderItemId);

            // 修改品名需要判断，然后删除此orderItem对应的未处理的异常和应收
            Boolean changeProd = createReqVO.getProdId() != null && !Objects.equals(createReqVO.getProdId(), orderItemDO.getProdId());
            // 修改了品名 需要删除未处理的预付异常和未处理的应收单
            if (changeProd) {
                orderItemDO.setIsPriced(Boolean.FALSE);
                deletePendingOrderExceptionAfterUpdateProduct(orderId, orderItemId);
            }
            setOrderItemBase(createReqVO, orderItemDO);
        }

        Long orderItemIdFInal = orderItemId;

        ZhongPaoBestVO zhongpaoBest = getZhongPaoBest(orderDO);
        BigDecimal zhongEdge = zhongpaoBest != null ? zhongpaoBest.getZhongEdge() : null;
        BigDecimal paoEdge = zhongpaoBest != null ? zhongpaoBest.getPaoEdge() : null;

        if (CollectionUtil.isNotEmpty(orderWarehouseInItemDoList)) {

            orderWarehouseInItemDoList.stream().
                    forEach(orderWarehouseInItemDto -> {

                        OrderWarehouseInDO orderWarehouseInDo =
                                convertOrderWarehouseInItemDo(orderDO,
                                        orderItemIdFInal, zhongpaoBest,
                                        zhongEdge, paoEdge,
                                        orderWarehouseInItemDto,
                                        createReqVO.getInTime());

                        if (orderWarehouseInItemDto.getId() == null) {
                            // 执行入仓
                            orderWarehouseInMapper.insert(orderWarehouseInDo);
                            Long warehouseInDoId = orderWarehouseInDo.getId();

                            // 储位
                            List<OrderLocationCreateReqVO> orderLocationCreateReqVOList = orderWarehouseInItemDto.getOrderLocationCreateReqVOList();
                            if (CollectionUtil.isNotEmpty(orderLocationCreateReqVOList)) {
                                List<OrderLocationDO> orderLocationDOList = orderLocationCreateReqVOList.stream().map(orderLocationCreateReqVO -> {
                                    OrderLocationDO convert = OrderLocationConvert.INSTANCE.convert(orderLocationCreateReqVO);
                                    convert.setOrderId(orderId);
                                    convert.setOrderItemId(orderItemIdFInal);
                                    convert.setWarehouseInId(warehouseInDoId);
                                    return convert;
                                }).collect(Collectors.toList());
                                orderLocationService.saveBatch(orderLocationDOList);
                            }
                        } else {
                            OrderWarehouseInDO orderWarehouseInDOOld =
                                    orderWarehouseInMapper.selectById(
                                            orderWarehouseInItemDto.getId());

                            // 判断这条数据有没有更新，没有修改则不需要更新
                            List<ApplyInfoVO> applyInfoVOListTmp = new ArrayList<>();
                            compareOrderWarehouseInField("",
                                    Arrays.asList(orderWarehouseInDOOld),
                                    Arrays.asList(orderWarehouseInItemDto),
                                    applyInfoVOListTmp);
                            // 2023-04-20 入仓修改若修改已有入仓记录，有改动（储位或其他信息修改）修改入仓记录的最新操作时间，不修改入仓时间，不修改未发生变化的入仓记录的入仓时间和最新操作时间。
                            if (CollectionUtil.isNotEmpty(applyInfoVOListTmp)) {
                                orderWarehouseInMapper.updateById(orderWarehouseInDo);
                                applyInfoVOListTmp.clear();
                            }
                        }
                    });

            if (isDeleteNotInWarehouseIn && !isAddNewOrderItem) {
                //找到需要删除的纪录
                List<Long> deleteIds =
                        orderWarehouseInListOld.stream().
                                filter(orderWarehouseInOld -> orderWarehouseInItemDoList.stream().noneMatch(t -> orderWarehouseInOld.getId().equals(t.getId())))
                                .map(OrderWarehouseInDO::getId).collect(Collectors.toList());

                if (CollectionUtil.isNotEmpty(deleteIds)) {
                    orderWarehouseInMapper.deleteBatchIds(deleteIds);

                    for (Long orderWarehouseInId : deleteIds) {
                        // 删除老的储位数据
                        orderLocationService.deleteIfPresent(orderId, orderWarehouseInId, orderItemId);
                    }
                }
            }
        } else {
            if (isDeleteNotInWarehouseIn && !isAddNewOrderItem) {
                //删除入仓纪录
                List<Long> deleteIds =
                        orderWarehouseInListOld.stream().
                                map(OrderWarehouseInDO::getId).
                                collect(Collectors.toList());
                orderWarehouseInMapper.deleteBatchIds(deleteIds);

                for (Long orderWarehouseInId : deleteIds) {
                    // 删除老的储位数据
                    orderLocationService.deleteIfPresent(orderId, orderWarehouseInId, orderItemId);
                }
            }
        }

        // 查看所有的入仓数据
        List<OrderWarehouseInDO> orderWarehouseInDoListExists = orderWarehouseInMapper.selectList(new LambdaQueryWrapper<OrderWarehouseInDO>().eq(OrderWarehouseInDO::getOrderId, orderId)
                .eq(OrderWarehouseInDO::getOrderItemId, orderItemIdFInal));

        // 设置orderItem属性
        WarehouseInInfoVO warehouseInInfoVO = this.orderItemSetWarehouseInInfoVO(orderItemDO, orderWarehouseInDoListExists);

        // 入仓中状态下 这时不处理订单的重泡货值 改为处理
        this.setOrderItemZhongPao(zhongpaoBest, orderItemDO, warehouseInInfoVO.getWeight(), warehouseInInfoVO.getVolume());
        orderItemDO.setItemStatus(warehouseInInfoVO.getDiffType());

        // 更新 订单项
        orderItemService.updateById(orderItemDO);

        //入仓特性为空时 需要更新入仓特性为空
        if (isUpdateWarehouseProdAttrIds && StringUtils.isEmpty(createReqVO.getWarehouseInProdAttrIds())) {
            orderItemService.update(null, new LambdaUpdateWrapper<OrderItemDO>()
                    .set(OrderItemDO::getWarehouseInProdAttrIds, null)
                    .eq(OrderItemDO::getOrderItemId, orderItemDO.getOrderItemId()));
        }

        // 标签号. (注意拆单的标签号是在拆单成功后插入的，不在这里处理)
        if (Boolean.FALSE.equals(createReqVO.getIsSplitOrderAutoCreate())) {
            List<OrderWarehouseInDO> orderWarehouseInDOList = orderWarehouseInMapper.selectList(OrderWarehouseInDO::getOrderId, orderDO.getOrderId());
            int numSum2 = orderWarehouseInDOList.stream().filter(t -> t.getCartonsNum() != null).mapToInt(OrderWarehouseInDO::getCartonsNum).sum();
            if (numSum2 > 0) {
                List<OrderLabelDto> labelDtoList = CollectionUtil.newArrayList(new OrderLabelDto(null, 1, numSum2));
                orderLabelService.saveOrUpdateLabel(SaveOrUpdateOrderLabelDto.builder().orderId(orderId).orderLabelDtoList(labelDtoList).isAddLog(false).build());
            }
        }

        // 影像
        if (createReqVO.getIsProcessPicture()) {
            orderWarehousePictureService.createWarehousePictureBatch(pictureUrls, 5, orderItemId);
        }

        return orderItemDO.getOrderItemId();
    }

    private void validateWarehouseInItem(OrderDO orderDO,
                                         Long brand,
                                         List<OrderWarehouseInItemDto> orderWarehouseInItemDoList,
                                         String prodTitleZh,
                                         String prodTitleEn) {
        if (brand == null || brand.equals(0L)) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PROD_BRAND_NOT_NULL);
        }

        if (CollectionUtil.isEmpty(orderWarehouseInItemDoList)) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_WAREHOUSE_IN_NOT_EXISTS);
        }

        boolean quantityRequired =
                warehouseService.quantityRequired(orderDO.getLineId());
        boolean isConcentrateTransport =
                StringUtils.isNotEmpty(orderDO.getType()) &&
                        orderDO.getType().contains("1");

        for (OrderWarehouseInItemDto orderWarehouseInItemDto : orderWarehouseInItemDoList) {

            if (orderWarehouseInItemDto.getCartonsNum() == null || orderWarehouseInItemDto.getCartonsNum().equals(0)) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.WAREHOUSE_IN_PROPERTY_NOT_NULL_AND_ZERO,
                        I18nMessage.getLang() == 0 ? prodTitleZh : prodTitleEn,
                        I18nMessage.getLang() == 0 ? "箱数" : "CNTS NO");
            }
            String boxGauge = orderWarehouseInItemDto.getBoxGauge();
            boolean gaugeError = false;
            if (StringUtils.isNotEmpty(boxGauge)) {
                String[] gauge = boxGauge.split("\\*");
                if (gauge.length != 3) {
                    throw ServiceExceptionUtil.exception(ErrorCodeConstants.BOX_GAUGE_FORMAT_ERROR);
                }
                gaugeError = Arrays.stream(gauge).anyMatch(t -> new BigDecimal(t).compareTo(BigDecimal.ZERO) == 0);
            } else {
                gaugeError = true;
            }
            // 不论是pda还是后台入仓，当订单是集运包裹时，长宽高非必填，默认为0，可以自定义输入体积、重量
            if (isConcentrateTransport) {
                gaugeError = false;
                if (StringUtils.isEmpty(boxGauge)) {
                    boxGauge = "0*0*0";
                    orderWarehouseInItemDto.setBoxGauge(boxGauge);
                }
            }
            if (gaugeError) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.WAREHOUSE_IN_PROPERTY_NOT_NULL_AND_ZERO,
                        I18nMessage.getLang() == 0 ? prodTitleZh : prodTitleEn,
                        I18nMessage.getLang() == 0 ? "长、宽、高" : "Length, Width, Height");
            }

            if (orderWarehouseInItemDto.getWeight() == null) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.PROD_WAREHOUSE_IN_WEIGHT_NOT_NULL, I18nMessage.getLang() == 0 ? prodTitleZh : prodTitleEn);
            }

            if (orderWarehouseInItemDto.getVolume() == null) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.PROD_WAREHOUSE_IN_VOLUME_NOT_NULL, I18nMessage.getLang() == 0 ? prodTitleZh : prodTitleEn);
            }

            if (!isConcentrateTransport) {
                if (BigDecimal.ZERO.compareTo(orderWarehouseInItemDto.getWeight()) == 0) {
                    throw ServiceExceptionUtil.exception(ErrorCodeConstants.PROD_WAREHOUSE_IN_WEIGHT_NOT_ZERO, I18nMessage.getLang() == 0 ? prodTitleZh : prodTitleEn);
                }

                if (BigDecimal.ZERO.compareTo(orderWarehouseInItemDto.getVolume()) == 0) {
                    throw ServiceExceptionUtil.exception(ErrorCodeConstants.PROD_WAREHOUSE_IN_VOLUME_NOT_ZERO, I18nMessage.getLang() == 0 ? prodTitleZh : prodTitleEn);
                }
            }
            if (quantityRequired &&
                    (orderWarehouseInItemDto.getQuantityAll() == null ||
                            orderWarehouseInItemDto.getQuantityAll().equals(0))) {

                throw ServiceExceptionUtil.exception(ErrorCodeConstants.WAREHOUSE_IN_ITEM_QUANTITY_REQUIRED);
            }

            String expressNo = orderWarehouseInItemDto.getExpressNo();
            if (StringUtils.isNotEmpty(expressNo) && expressNo.length() > 1000) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.WAREHOUSE_IN_ITEM_EXPRESS_NO_LIMIT);
            }
        }
    }

    @NotNull
    private OrderWarehouseInDO convertOrderWarehouseInItemDo(OrderDO orderDO, Long orderItemIdFInal, ZhongPaoBestVO zhongpaoBest, BigDecimal zhongEdge, BigDecimal paoEdge, OrderWarehouseInItemDto orderWarehouseInItemDto, Date inTime) {
        OrderWarehouseInDO orderWarehouseInDo = OrderWarehouseInConvert.INSTANCE.convert(orderWarehouseInItemDto);
        orderWarehouseInDo.setOrderId(orderDO.getOrderId());
        orderWarehouseInDo.setOrderNo(orderDO.getOrderNo());
        orderWarehouseInDo.setOrderItemId(orderItemIdFInal);
        orderWarehouseInDo.setBoxGauge(orderWarehouseInItemDto.getBoxGauge());
        // 无id的新淅入仓的数据的首次入仓时间为当前时间 或 前端传入的时间
        if (orderWarehouseInItemDto.getId() == null) {
            orderWarehouseInDo.setInTime(inTime == null ? new Date() : inTime);
        }

        if (orderWarehouseInItemDto.getWeight() != null && orderWarehouseInItemDto.getVolume() != null) {

            BigDecimal weight = orderWarehouseInItemDto.getWeight();
            BigDecimal volume = orderWarehouseInItemDto.getVolume();

            // 计算（入仓时订单总重量大于订单总方数，总重量/750（取自当前用户的重货标准）>总体积） - 海运拼柜/海运整柜
            if (zhongEdge != null && (TransportTypeShortEnum.SEA_CONTAINER.getValue().equals(orderDO.getTransportId())
                    || TransportTypeShortEnum.MARINE_CONTAINER.getValue().equals(orderDO.getTransportId()))) {
                BigDecimal zhong = weight.divide(volume, 2, RoundingMode.HALF_UP);
                if (zhong.compareTo(zhongEdge) > 0) {
                    BigDecimal zhongCbm = weight.multiply(zhongpaoBest.getZhongFormulas());
                    orderWarehouseInDo.setHeavyNumber(zhongCbm);
                }
            }
            // 泡货（超过泡货标准）- 专线空运
            if (paoEdge != null && (TransportTypeShortEnum.AIR_FREIGHT_LINE.getValue().equals(orderDO.getTransportId())
                    || TransportTypeShortEnum.AIR_SEA_COMBINED_TRANSPORT.getValue().equals(orderDO.getTransportId()))) {
                BigDecimal pao = weight.divide(volume, 2, RoundingMode.HALF_UP);
                if (pao.compareTo(paoEdge) < 0) {
                    BigDecimal paoKg = volume.multiply(zhongpaoBest.getPaoFormulas());
                    // 20231215 空运打包后的泡货判断不要做0.5的倍数处理，这里比较的是原始数据
                    // paoKg = BigDecimalUtils.convertWv(paoKg);
                    orderWarehouseInDo.setLightNumber(paoKg);
                }
            }
        }
        return orderWarehouseInDo;
    }

    private ZhongPaoBestVO getZhongPaoBest(OrderDO orderDO) {
        //取最新的OrderDO
        orderDO = orderQueryService.getOrderById(orderDO.getOrderId());

        LogisticsInfoDto logisticsInfoDto = warehouseLineMapper.getStartInfoAndDestInfoByLineId(orderDO.getLineId());
        if (Objects.isNull(logisticsInfoDto)) {
            throw exception(TRANSPORT_LINE_NOT_EXISTS);
        }

        OrderConsignorDO consignorDO = orderConsignorService.getOne(new LambdaQueryWrapper<OrderConsignorDO>().eq(OrderConsignorDO::getOrderId, orderDO.getOrderId()).orderByDesc(OrderConsignorDO::getId).last("limit 1"));
        OrderConsigneeDO consigneeDO = orderConsigneeService.getOne(new LambdaQueryWrapper<OrderConsigneeDO>().eq(OrderConsigneeDO::getOrderId, orderDO.getOrderId()).orderByDesc(OrderConsigneeDO::getId).last("limit 1"));

        CustomerZhongPaoQueryVO customerZhongPaoQueryVO = new CustomerZhongPaoQueryVO();
        if (Objects.nonNull(consignorDO)) {
            customerZhongPaoQueryVO.setConsignorId(consignorDO.getCustomerId());
        }
        if (Objects.nonNull(consigneeDO)) {
            customerZhongPaoQueryVO.setConsigneeId(consigneeDO.getCustomerId());
        }
        customerZhongPaoQueryVO.setDepartureId(logisticsInfoDto.getStartCityId());
        customerZhongPaoQueryVO.setObjectiveId(logisticsInfoDto.getDestCityId());
        customerZhongPaoQueryVO.setStartWarehouseId(logisticsInfoDto.getStartWarehouseId());
        customerZhongPaoQueryVO.setDestWarehouseId(logisticsInfoDto.getDestWarehouseId());
        ZhongPaoBestVO zhongPaoBest = zhongPaoService.getCustomerBestZhongPao(customerZhongPaoQueryVO);

        // 申请的特价标准
        if (Objects.nonNull(orderDO.getWeightUnit()) && orderDO.getWeightUnit().compareTo(BigDecimal.ZERO) > 0) {
            zhongPaoBest.setZhongEdge(orderDO.getWeightUnit());
        }
        if (Objects.nonNull(orderDO.getVolumeUnit()) && orderDO.getVolumeUnit().compareTo(BigDecimal.ZERO) > 0) {
            zhongPaoBest.setPaoEdge(orderDO.getVolumeUnit());
        }
        return zhongPaoBest;
    }

    // @Override
    // @Transactional(rollbackFor = Exception.class)
    // public boolean updateOrderWarehouseIn(OrderWarehouseInUpdateReqVO updateReqVO) {
    //
    //     Long id = updateReqVO.getId();
    //     OrderWarehouseInDO orderWarehouseInDO = orderWarehouseInMapper.selectById(id);
    //     OrderDO orderDO = orderService.getById(orderWarehouseInDO.getOrderId());
    //     Long orderId = orderDO.getOrderId();
    //     Long orderItemId = orderWarehouseInDO.getOrderItemId();
    //
    //     //订单排单校验
    //     applicationContext.publishEvent(new BoxCheckOrderSchedulingEvent(orderId));
    //
    //     //有此填单项的入仓修改审批 不能再次入仓
    //     List<OrderWarehouseApprovalDO> orderWarehouseApprovalDOList = orderWarehouseApprovalMapper.selectList(new LambdaQueryWrapperX<OrderWarehouseApprovalDO>()
    //             .eq(OrderWarehouseApprovalDO::getOrderIds, orderId)
    //             // .eq(OrderWarehouseApprovalDO::getOrderItemId, orderItemId)
    //             .eq(OrderWarehouseApprovalDO::getType, OrderWarehouseApprovalTypeEnum.WAREHOUSE_IN_UPDATE.getValue())
    //             .eq(OrderWarehouseApprovalDO::getStatus, ApprovalResultStatusEnum.processing.getValue()));
    //     if (CollectionUtil.isNotEmpty(orderWarehouseApprovalDOList)) {
    //         throw exception(MODIFY_APPROVAL_NOT_UPDATE_OR_DELETE_WAREHOUSE_IN);
    //     }
    //
    //     //未完成入仓直接更新数据
    //     if (orderDO.getStatus() < OrderStatusEnum.IN_WAREHOUSE.getValue()) {
    //         //复制属性
    //         BeanUtil.copyProperties(updateReqVO, orderWarehouseInDO);
    //         orderWarehouseInDO.setUpdateTime(new Date());
    //
    //         //判断重泡货方数
    //         ZhongPaoBestVO zhongpaoBest = getZhongPaoBest(orderDO);
    //         BigDecimal zhongEdge = zhongpaoBest != null ? zhongpaoBest.getZhongEdge() : null;
    //         BigDecimal paoEdge = zhongpaoBest != null ? zhongpaoBest.getPaoEdge() : null;
    //
    //         if (orderWarehouseInDO.getWeight() != null && orderWarehouseInDO.getVolume() != null) {
    //             // 计算（入仓时订单总重量大于订单总方数，总重量/750（取自当前用户的重货标准）>总体积）
    //             if (zhongEdge != null && (TransportTypeShortEnum.SEA_CONTAINER.getValue().equals(orderDO.getTransportId())
    //                     || TransportTypeShortEnum.MARINE_CONTAINER.getValue().equals(orderDO.getTransportId())
    //                     || TransportTypeShortEnum.AIR_SEA_COMBINED_TRANSPORT.getValue().equals(orderDO.getTransportId()))) {
    //                 BigDecimal zhongCbm = orderWarehouseInDO.getWeight().divide(zhongEdge, 2, RoundingMode.HALF_UP);
    //                 if (zhongCbm.compareTo(orderWarehouseInDO.getVolume()) > 0) {
    //                     orderWarehouseInDO.setHeavyNumber(zhongCbm);
    //                 }
    //             }
    //             // 泡货（超过泡货标准）
    //             if (paoEdge != null && (TransportTypeShortEnum.AIR_FREIGHT_LINE.getValue().equals(orderDO.getTransportId())
    //                     || TransportTypeShortEnum.AIR_SEA_COMBINED_TRANSPORT.getValue().equals(orderDO.getTransportId()))) {
    //                 BigDecimal paoKg = orderWarehouseInDO.getVolume().multiply(paoEdge);
    //                 if (paoKg.compareTo(orderWarehouseInDO.getWeight()) < 0) {
    //                     orderWarehouseInDO.setLightNumber(paoKg);
    //                 }
    //             }
    //         }
    //
    //         //更新入仓纪录
    //         orderWarehouseInMapper.updateById(orderWarehouseInDO);
    //
    //         OrderItemDO orderItemDO = orderItemService.getById(orderWarehouseInDO.getOrderItemId());
    //
    //         //查看所有的入仓数据
    //         List<OrderWarehouseInDO> orderWarehouseInDoListOld = orderWarehouseInMapper.selectList(new LambdaQueryWrapper<OrderWarehouseInDO>()
    //                 .eq(OrderWarehouseInDO::getOrderId, orderWarehouseInDO.getOrderId())
    //                 .eq(OrderWarehouseInDO::getOrderItemId, orderWarehouseInDO.getOrderItemId()));
    //
    //         //更新orderItem
    //         OrderWarehouseInCreateReqVO orderWarehouseInCreateReqVO = BeanUtil.copyProperties(updateReqVO, OrderWarehouseInCreateReqVO.class);
    //         setOrderItemBase(orderWarehouseInCreateReqVO, orderItemDO);
    //         orderItemService.updateById(orderItemDO);
    //
    //         // 设置orderItem属性
    //         WarehouseInInfoVO warehouseInInfoVO = this.orderItemSetWarehouseInInfoVO(orderItemDO, orderWarehouseInDoListOld);
    //
    //         this.setOrderItemZhongPao(zhongpaoBest, orderItemDO, warehouseInInfoVO.getWeight(), warehouseInInfoVO.getVolume());
    //
    //         orderItemDO.setItemStatus(warehouseInInfoVO.getDiffType());
    //         // 更新 订单项
    //         orderItemService.updateById(orderItemDO);
    //
    //         // 更新订单入仓信息
    //         OrderWarehouseInVO orderWarehouseInVO = new OrderWarehouseInVO();
    //         orderWarehouseInVO.setOrderId(orderId);
    //         OrderItemInWarehouseVO orderItemInWarehouseVO = new OrderItemInWarehouseVO();
    //         BeanUtil.copyProperties(orderItemDO, orderItemInWarehouseVO);
    //         BeanUtil.copyProperties(warehouseInInfoVO, orderItemInWarehouseVO);
    //         orderWarehouseInVO.setOrderItemInWarehouseVOList(Collections.singletonList(orderItemInWarehouseVO));
    //         orderService.orderInWarehouse(orderWarehouseInVO);
    //
    //         // 更新订单状态 - 入库中
    //         orderService.updateStatus(orderId, orderDO.getOrderNo(), OrderStatusEnum.WAREHOUSING.getValue(), null, OrderWarehouseInStatusEnum.warehousing.getValue(), null, null, null, null, "仓库操作", null);
    //     }
    //
    //     //已完成入仓，则需要提交申请
    //     else {
    //
    //         OrderItemDO orderItemDO = orderItemService.getById(orderWarehouseInDO.getOrderItemId());
    //
    //         OrderWarehouseInItemDto orderWarehouseInItemDto = new OrderWarehouseInItemDto()
    //                 .setId(updateReqVO.getId())
    //                 .setCartonsNum(updateReqVO.getCartonsNum())
    //                 .setQuantityAll(updateReqVO.getQuantityAll())
    //                 .setSpecificationType(updateReqVO.getSpecificationType())
    //                 .setUnit(updateReqVO.getUnit())
    //                 .setBoxGauge(updateReqVO.getBoxGauge())
    //                 .setVolume(updateReqVO.getVolume())
    //                 .setWeight(updateReqVO.getWeight())
    //                 .setExpressNo(updateReqVO.getExpressNo());
    //
    //
    //         OrderWarehouseInUpdateApplyReqVO updateApplyReqVO = new OrderWarehouseInUpdateApplyReqVO()
    //                 .setOrderId(orderId)
    //                 .setOrderItemId(orderItemId)
    //                 .setProdId(orderItemDO.getProdId())
    //                 .setProdType(orderItemDO.getProdType())
    //                 .setProdTitleZh(orderItemDO.getProdTitleZh())
    //                 .setProdTitleEn(orderItemDO.getProdTitleEn())
    //                 .setBrand(updateReqVO.getBrand() == null ? orderItemDO.getBrand() : Long.parseLong(updateReqVO.getBrand()))
    //                 .setBrandType(updateReqVO.getBrandType() == null ? orderItemDO.getBrandType() : updateReqVO.getBrandType())
    //                 .setFeeType(updateReqVO.getFeeType() == null ? orderItemDO.getFeeType() : updateReqVO.getFeeType())
    //
    //                 // .setNum(updateReqVO.get() == null ? orderItemDO.getFeeType() : updateReqVO.getFeeType())
    //                 // .setVolume(updateReqVO.getFeeType() == null ? orderItemDO.getFeeType() : updateReqVO.getFeeType())
    //                 // .setWeight(updateReqVO.getFeeType() == null ? orderItemDO.getFeeType() : updateReqVO.getFeeType())
    //                 .setMaterial(updateReqVO.getMaterial() == null ? orderItemDO.getMaterial() : updateReqVO.getMaterial())
    //                 .setOrderWarehouseInUpdateItemDoList(CollectionUtil.newArrayList(orderWarehouseInItemDto));
    //
    //         this.updateOrupdateApply(updateApplyReqVO);
    //     }
    //
    //     return false;
    // }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteOrderWarehouseIn(Long orderWarehouseInId, boolean packagingFlag) {

        OrderWarehouseInDO orderWarehouseInDO = orderWarehouseInMapper.selectById(orderWarehouseInId);
        if (orderWarehouseInDO == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_WAREHOUSE_IN_NOT_EXISTS);
        }
        Long orderId = orderWarehouseInDO.getOrderId();
        Long orderItemId = orderWarehouseInDO.getOrderItemId();
        // 检查订单项是否有应收记录或已核销(注：这里只需要判定当前的订单项应收单是否有核销的，所以不传orderId，只传orderItemId)
        receivableService.verificationReceivableIsWriteOff(null, orderItemId);
        // 订单排单校验
        applicationContext.publishEvent(new BoxCheckOrderSchedulingEvent(orderId));

        OrderDO orderDO = orderService.getById(orderId);
        // 核验是否有未处理审批单
        throwProcessingApproval(orderDO);

        // 打包时删除入仓纪录，需要纪录打包历史
        if (packagingFlag) {
            // 更新前一次打包数据
            orderDO = this.updateOrderSumPrevPacked(orderId);

            savePackLog(orderId, orderItemId, false);
        }

        // 查看所有的入仓数据
        List<OrderWarehouseInDO> orderWarehouseInDoListOld = orderWarehouseInMapper.selectList(new LambdaQueryWrapper<OrderWarehouseInDO>().eq(OrderWarehouseInDO::getOrderId, orderId)
                .eq(OrderWarehouseInDO::getOrderItemId, orderItemId));

        // 删除老的入仓数据
        orderWarehouseInMapper.deleteById(orderWarehouseInId);

        // 删除老的储位数据. 此储位数据暂时不删除，方便查询退仓的入仓数据对应的储位。
        // orderLocationService.deleteIfPresent(orderId, orderWarehouseInId, orderItemId);

        // 删除标签
        orderLabelService.deleteLabelByOrderId(orderId);
        // 再重新生成标签
        List<OrderWarehouseInDO> orderWarehouseInDOList = orderWarehouseInMapper.selectList(OrderWarehouseInDO::getOrderId, orderId);
        int numSum2 = orderWarehouseInDOList.stream().filter(t -> t.getCartonsNum() != null).mapToInt(OrderWarehouseInDO::getCartonsNum).sum();
        if (numSum2 > 0) {
            List<OrderLabelDto> labelDtoList = CollectionUtil.newArrayList(new OrderLabelDto(null, 1, numSum2));
            orderLabelService.saveOrUpdateLabel(SaveOrUpdateOrderLabelDto.builder().orderId(orderId).orderLabelDtoList(labelDtoList).isAddLog(false).build());
        }

        if (OrderStatusEnum.WAREHOUSE_ADJUSTMENT.getValue().equals(orderDO.getStatus())) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_WAREHOUSE_ADJUSTMENT_STATUS_NOT_ALLOWED_WAREHOUSE_IN);
        }

        OrderItemDO orderItemDO = orderItemService.getById(orderItemId);

        // 查看所有的入仓数据
        List<OrderWarehouseInDO> orderWarehouseInDoListNew = orderWarehouseInMapper.selectList(new LambdaQueryWrapper<OrderWarehouseInDO>().eq(OrderWarehouseInDO::getOrderId, orderId)
                .eq(OrderWarehouseInDO::getOrderItemId, orderItemId));

        ZhongPaoBestVO zhongPaoBest = getZhongPaoBest(orderDO);
        // 设置orderItem属性
        WarehouseInInfoVO warehouseInInfoVO = this.orderItemSetWarehouseInInfoVO(orderItemDO, orderWarehouseInDoListNew);

        this.setOrderItemZhongPao(zhongPaoBest, orderItemDO, warehouseInInfoVO.getWeight(), warehouseInInfoVO.getVolume());

        orderItemDO.setItemStatus(warehouseInInfoVO.getDiffType());
        // 更新 订单项
        orderItemService.updateById(orderItemDO);

        // 更新订单入仓信息
        OrderWarehouseInVO orderWarehouseInVO = new OrderWarehouseInVO();
        orderWarehouseInVO.setOrderId(orderId);
        OrderItemInWarehouseVO orderItemInWarehouseVO = new OrderItemInWarehouseVO();
        BeanUtil.copyProperties(orderItemDO, orderItemInWarehouseVO);
        BeanUtil.copyProperties(warehouseInInfoVO, orderItemInWarehouseVO);
        orderWarehouseInVO.setOrderItemInWarehouseVOList(Collections.singletonList(orderItemInWarehouseVO));
        orderService.orderInWarehouse(orderWarehouseInVO);

        // 打包删除入仓纪录时不更新订单状态
        if (!packagingFlag) {
            // 更新订单状态 - 入库中
            orderService.updateStatus(orderId, orderDO.getOrderNo(), OrderStatusEnum.WAREHOUSING.getValue(), null, OrderWarehouseInStatusEnum.warehousing.getValue(), null, null, null, false);
        }

        // 若orderItem是非下单货物，且其下没有入仓数据，则删除
        if (CollectionUtil.isEmpty(orderWarehouseInDoListNew)) {
            if (Boolean.TRUE.equals(orderItemDO.getIsWarehouseInAdd())) {
                // 删除orderItem
                orderItemService.removeById(orderItemDO);
            }
            // 删除orderItem应收单
            receivableService.deleteReceivableByOrderItemId(orderItemId);
        }

        // 纪录退仓操作日志
        List<ApplyInfoVO> applyInfoList = new ArrayList<>();
        List<OrderWarehouseInItemDto> orderWarehouseInItemDtoList =
                CollectionUtil.isNotEmpty(orderWarehouseInDoListNew) ? orderWarehouseInDoListNew.stream().map(t -> OrderWarehouseInConvert.INSTANCE.convert(t)).collect(Collectors.toList())
                        : new ArrayList<>();
        compareOrderWarehouseInField(orderItemDO.getProdTitleZh(), orderWarehouseInDoListOld, orderWarehouseInItemDtoList, applyInfoList);
        if (CollectionUtil.isNotEmpty(applyInfoList)) {
            orderBusinessService.addOrderOperateLog(orderId, "仓库操作", "删除入仓记录", applyInfoList);
        }

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean finishWarehouseInWhenChangeTransportType(Long orderId) {

        OrderWarehouseInFinishReqVO finishReqVO = new OrderWarehouseInFinishReqVO();
        finishReqVO.setOrderId(orderId);
        //不需要更新影像
        finishReqVO.setUpdateWarehouseInUrl(false);
        //不需要更新标签
        finishReqVO.setUpdateLabel(false);

        //不需要更新用户的 状态 和下一次掉入公海时间
        finishReqVO.setUpdateCustomer(false);

        //不需要给客户发送入仓短信
        finishReqVO.setSendMsg(false);
        //不需要纪录操作日志
        finishReqVO.setIsAddOrderOperateLog(false);

        return this.finishWarehouseIn(finishReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean finishWarehouseIn(OrderWarehouseInFinishReqVO finishReqVO) {
        String msg = "完成入仓";
        Long orderId = finishReqVO.getOrderId();
        OrderDO orderDO = orderService.getById(orderId);
        if (orderDO == null) {
            throw ServiceExceptionUtil.exception(
                    ErrorCodeConstants.ORDER_NOT_EXISTS);
        }
        if (OrderStatusEnum.WAREHOUSE_ADJUSTMENT.getValue().equals(orderDO.getStatus())) {
            throw ServiceExceptionUtil.exception(
                    ErrorCodeConstants.ORDER_WAREHOUSE_ADJUSTMENT_STATUS_NOT_ALLOWED_WAREHOUSE_IN);
        }
        // 判断是否有未处理的审核单
        throwProcessingApproval(orderDO);

        boolean isSplitOrderChildren =
                orderQueryService.isSplitOrderChildren(orderDO);

        // 没有入仓数据则提示
        Long inCount = orderWarehouseInMapper.selectCount(
                OrderWarehouseInDO::getOrderId, orderId);
        if (inCount == 0) {
            throw ServiceExceptionUtil.exception(
                    ErrorCodeConstants.ORDER_WAREHOUSE_IN_NOT_EXISTS);
        }

        List<OrderItemDO> orderItemDOList =
                orderItemService.list(new LambdaQueryWrapper<OrderItemDO>()
                        .eq(OrderItemDO::getOrderId, orderId)
                        .eq(BaseDO::getDeleted, false));
        if (CollectionUtil.isNotEmpty(orderItemDOList)) {
            for (OrderItemDO orderItemDO : orderItemDOList) {
                this.validateProdAttrAccess(orderItemDO.getProdId(),
                        orderItemDO.getOrderNo());
            }
        }

        // 退场入仓不校验这些、拆单入仓不校验
        boolean isNotRollbackIn =
                Boolean.FALSE.equals(finishReqVO.getIsRollbackIn());
        if (isNotRollbackIn && !finishReqVO.getIsSplitIn()) {
            // 订单排单校验
            applicationContext.publishEvent(
                    new BoxCheckOrderSchedulingEvent(orderId));
            // 校验是否有已核销的应收单，如果有，则不能再次入仓修改
            receivableService.verificationReceivableIsWriteOff(orderDO.getOrderId(), null);
        }

        // 影像
        if (finishReqVO.getUpdateWarehouseInUrl()) {
            orderWarehousePictureService.createWarehousePictureBatch(
                    finishReqVO.getUrls(), 1, orderId);
        }

        // 转异
        String manualExceptionType = finishReqVO.getManualExceptionType();
        if (StringUtils.isNotEmpty(manualExceptionType)) {
            msg = "订单转异";
            // 异常影像
            orderWarehousePictureService.createWarehousePictureBatch(
                    finishReqVO.getExceptionUrls(), 4, orderId);
            // 异常
            String descZh = getOrderOtherExceptionDesc(manualExceptionType,
                    0, finishReqVO.getDescZh(),
                    finishReqVO.getDescEn());
            String descEn = getOrderOtherExceptionDesc(manualExceptionType,
                    1, finishReqVO.getDescZh(),
                    finishReqVO.getDescEn());

            OrderExceptionCreateReqVO orderExceptionCreateReqVO =
                    genOrderException(orderId,
                            null,
                            orderDO,
                            OrderExceptionEnum.ORDER_OTHER_EXCEPTION,
                            descZh,
                            descEn,
                            finishReqVO.getExceptionUrls());
            orderExceptionService.createOrderException(orderExceptionCreateReqVO);
        }

        // List<OrderLocationCreateReqVO> orderLocationCreateReqVOList = finishReqVO.getOrderLocationCreateReqVOList();
        //
        // if (CollectionUtil.isNotEmpty(orderLocationCreateReqVOList)) {
        //     // 储位信息 删除老储位 新增新储位
        //     orderLocationService.batchOrderUpdate(orderLocationCreateReqVOList);
        // }

        // 保存特需 特需应收请求列表
        List<OrderSpecialNeedReceivableReqVo> orderSpecialNeedReceivableReqVoList =
                finishReqVO.getOrderSpecialNeedReceivableReqVoList();
        if (CollectionUtil.isNotEmpty(orderSpecialNeedReceivableReqVoList)) {
            List<Long> specialNeedIds =
                    orderSpecialNeedReceivableReqVoList.stream().map(OrderSpecialNeedReceivableReqVo::getId).collect(Collectors.toList());

            List<OrderSpecialNeedDO> orderSpecialNeedList =
                    orderSpecialNeedService.getOrderSpecialNeedList(specialNeedIds);

            orderSpecialNeedList.forEach(orderSpecialNeedDO -> orderSpecialNeedReceivableReqVoList.stream()
                    .filter(t -> t.getId().equals(orderSpecialNeedDO.getId())).findFirst().ifPresent(orderSpecialNeedReceivableReqVo -> {
                        //receivable_money 应收费
                        BigDecimal money =
                                orderSpecialNeedReceivableReqVo.getReceivableMoney();
                        Integer currency =
                                orderSpecialNeedReceivableReqVo.getReceivableMoneyCurrency();
                        String advanceType =
                                orderSpecialNeedDO.getAdvanceType();
                        //垫付的内陆运输费用
                        orderSpecialNeedDO.setTransFee(money);
                        orderSpecialNeedDO.setTransCurrency(currency);
                    }));

            // 更新
            orderSpecialNeedService.updateBatchById(orderSpecialNeedList);
        } else {

        }

        // 生成特需应收
        orderSpecialNeedService.buildSpecialReceivable(orderId, 1);

        List<OrderWarehouseInDO> orderWarehouseInDOList =
                orderWarehouseInMapper.selectList(OrderWarehouseInDO::getOrderId,
                        orderDO.getOrderId());

        //入仓修改或完成备货，入仓重量、备货重量变化后，按最新入仓或备货重量，
        // 重新计算泡重，按最新入仓重量与订单泡货标准重新计算泡重。
        // 清空之前申请的固定泡重优惠，之前申请泡货标准还原到初始泡货标准。
        resetSpecialVWeightAndWeightUnit(orderId, orderDO,
                finishReqVO.getIsSumWeightNoChange(),
                finishReqVO.getIsSumVolumeNoChange());

        List<ChannelPackagingOverWeightAdditionalBo>
                channelPackagingOverWeightAdditionalBoList = new ArrayList<>();
        if (!isSplitOrderChildren && isNotRollbackIn) {
            channelPackagingOverWeightAdditionalBoList =
                    genChannelPackagingOverweightAdditionalBoList(orderDO,
                            orderWarehouseInDOList);
        }

        // 重泡货配置
        ZhongPaoBestVO zhongPaoBest = getZhongPaoBest(orderDO);

        // 根据订单项产生异常，多箱，少箱，新增商品异常，入仓特性不符异常
        processOrderItemException(orderId, orderDO,
                orderItemDOList,
                isNotRollbackIn, orderWarehouseInDOList,
                zhongPaoBest,
                channelPackagingOverWeightAdditionalBoList, false);

        if (CollectionUtil.isNotEmpty(channelPackagingOverWeightAdditionalBoList)) {
            channelPackagingOverWeightAdditionalBoList =
                    channelPackagingOverWeightAdditionalBoList.stream().filter(t -> !t.isMerged()).collect(Collectors.toList());

            for (ChannelPackagingOverWeightAdditionalBo channelPackagingOverWeightAdditionalBo : channelPackagingOverWeightAdditionalBoList) {
                // 生成渠道包装超限异常
                OrderExceptionCreateReqVO orderExceptionCreateReqVO = genOrderException(orderId, null, orderDO,
                        OrderExceptionEnum.CHANNEL_PACKAGING_OVERWEIGHT_EXCEPTION,
                        channelPackagingOverWeightAdditionalBo.getExceptionDescZh(),
                        channelPackagingOverWeightAdditionalBo.getExceptionDescEn(), null, JSON.toJSONString(channelPackagingOverWeightAdditionalBo));
                orderExceptionService.createOrderException(orderExceptionCreateReqVO);
            }

        } else {
            orderExceptionService.autoProcessException(orderId,
                    null,
                    OrderExceptionEnum.CHANNEL_PACKAGING_OVERWEIGHT_EXCEPTION,
                    "未超过路线渠道包装重量上限，系统已自动处理",
                    OrderExceptionResult.CHANNEL_PACKAGING_OVERWEIGHT_EXCEPTION_RESULT.CONFIRMED_SEND);
        }

        // 入仓总数量、体积、重量
        int numSum = orderWarehouseInDOList.stream().filter(t -> t.getCartonsNum() != null).mapToInt(OrderWarehouseInDO::getCartonsNum).sum();
        int quantitySum = orderWarehouseInDOList.stream().filter(t -> t.getQuantityAll() != null).mapToInt(OrderWarehouseInDO::getQuantityAll).sum();
//        BigDecimal weightSum = finishReqVO.getSumWeight() != null ? finishReqVO.getSumWeight() :
//                orderWarehouseInDOList.stream().map(OrderWarehouseInDO::getWeight).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
//        BigDecimal volumeSum = finishReqVO.getSumVolume() != null ? finishReqVO.getSumVolume() :
//                orderWarehouseInDOList.stream().map(OrderWarehouseInDO::getVolume).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal weightSum =
                orderWarehouseInDOList.stream().map(OrderWarehouseInDO::getWeight).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal volumeSum =
                orderWarehouseInDOList.stream().map(OrderWarehouseInDO::getVolume).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
        orderDO.setSumQuantity(quantitySum);
        orderDO.setSumWeight(weightSum);
        orderDO.setSumVolume(volumeSum);
        orderDO.setSumNum(numSum);


        // 自定义体积
        // orderDO.setCustomSumVolume(finishReqVO.getSumVolume());
        // 自定义重量
        // orderDO.setCustomSumWeight(finishReqVO.getSumWeight());

        // 20230115 拆单子订单入仓不需要产生除转异外的其他异常，
        // 同时也不需要重新计算价格;  退场入仓也不需要产生异常
        if (!isSplitOrderChildren && isNotRollbackIn) {
            //处理重泡货异常
            boolean finishStocked = false;
            if ((Objects.equals(orderDO.getTransportId(), TransportTypeShortEnum.AIR_FREIGHT_LINE.getValue())
                    || Objects.equals(orderDO.getTransportId(), TransportTypeShortEnum.AIR_SEA_COMBINED_TRANSPORT.getValue()))
                    && Objects.nonNull(orderDO.getAirShipment()) && orderDO.getAirShipment() == 4) {
                finishStocked = true;
            }

            if (!finishStocked) {
                Integer sumNumWarehouseIn = orderDO.getSumNum();
                //处理多箱/少箱异常
                processMoreOrLessException(orderId, orderDO, sumNumWarehouseIn);
            }

            // 处理重泡货异常
            processZhongPaoException(orderId, orderDO, zhongPaoBest, weightSum, volumeSum, finishReqVO.getIsUpdateCallback(),
                    finishReqVO.getIsSumVolumeNoChange(), finishReqVO.getIsSumWeightNoChange(), finishStocked);

            // 处理发货人异常
            //需要到仓确认，需要自动生成发货人异常信息
            processConsignorException(finishReqVO, orderId, orderDO);

            // 重新调用计算订单价格, 订单信息和订单项信息需要重新查询，
            // 可能创建异常和修改订单已经对订单信息造成改变
            boolean firstRucang = orderDO.getRucangTime() == null;

            if (firstRucang) {
                //在下面的函数中完成费用计算
                orderService.finishOrderWarehouseIn(orderDO.getOrderId());
            } else {
                orderService.finishOrderWarehouseInUpdate(orderDO.getOrderId());
            }

        }

        // 更新订单状态
        Integer result = orderService.updateStatus(orderId,
                orderDO.getOrderNo(),
                OrderStatusEnum.IN_WAREHOUSE.getValue(),
                null,
                OrderWarehouseInStatusEnum.warehouse_finished.getValue(),
                null,
                null,
                null,
                false);

        if (!isSplitOrderChildren && isNotRollbackIn) {
            // 生成预付异常
            processOrderPayException(orderId, orderDO, result);
        }

        int numSum2 = orderWarehouseInDOList.stream().
                filter(t -> t.getCartonsNum() != null).
                mapToInt(OrderWarehouseInDO::getCartonsNum).sum();

        // 保存箱号
        if (finishReqVO.getUpdateLabel()) {
            List<OrderLabelDto> labelDtoList = finishReqVO.getLabelList();
            if (CollectionUtil.isEmpty(labelDtoList)) {

                // 若没有标签号列表参数，则说明不是更新的，就查一下是否有1~sum的标签号，若有，就不需要再重新生成了。
                List<OrderLabelBackVO> orderLabelBackVOS =
                        orderLabelService.getLabelListByOrder(orderId);
                if (CollectionUtil.isNotEmpty(orderLabelBackVOS)
                        && orderLabelBackVOS.size() == 1
                        && orderLabelBackVOS.get(0).getEnd() == numSum2) {
                    // do nothing
                    labelDtoList = new ArrayList<>();
                } else {
                    labelDtoList = CollectionUtil.newArrayList(new OrderLabelDto(null, 1, numSum2));
                }
            }
            if (CollectionUtil.isNotEmpty(labelDtoList)) {
                orderLabelService.saveOrUpdateLabel(SaveOrUpdateOrderLabelDto.builder().orderId(orderId).orderLabelDtoList(labelDtoList).isAddLog(false).build());
            }
        }

        // 针对未处理的异常，判断异常的orderItemId不在订单的orderItemList中的，
        // 需要删除异常。（说明此订单项已被删除，场景：
        // pda的新品入仓后会生成未报价异常，又删除入仓时未删除异常）
        List<OrderExceptionDO> orderUnProcessExceptionList =
                orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderId, null, null);
        if (CollectionUtil.isNotEmpty(orderUnProcessExceptionList)) {
            orderUnProcessExceptionList.stream().filter(t -> t.getOrderItemId() != null
                            && orderItemDOList.stream().noneMatch(i -> t.getOrderItemId().equals(i.getOrderItemId())))
                    .forEach(orderExceptionDO -> {
                        orderExceptionService.deleteOrderException(orderExceptionDO.getId());
                    });
        }

        // 查询订单异常数量
        orderUnProcessExceptionList =
                orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderId, null, null);

        // 当多次入仓后可能已将少箱异常填补上了，故重置其异常状态
        int exceptionNum = orderUnProcessExceptionList.size();
        if (exceptionNum == 0) {
            orderService.updateStatus(orderId, orderDO.getOrderNo(), null, 0, null, null, null, null, false);
        } else if (exceptionNum == 1) {
            // 由多个异常变成1个异常时，需要更新
            OrderExceptionDO orderExceptionDO = orderUnProcessExceptionList.get(0);
            orderService.updateStatus(orderId, orderDO.getOrderNo(),
                    null, OrderAbnormalStateEnum.keyOf(orderExceptionDO.getOrderExceptionType()).getValue(), null, null, null, null, false);
        }

        // 发送短信通知 - 发给发货人/控货人(拆单子订单不需要发）
        // 1、非拆单子订单  2、未发送短信  3、非退场入仓
        if (!isSplitOrderChildren && finishReqVO.getSendMsg() && isNotRollbackIn) {
            // 当没有异常时，才直接发送入仓短信。 有异常时需要在异常处理完后发送入仓短信。且入仓短信发送后不再次发送
            OrderConsignorDO orderConsignorDO2 =
                    orderConsignorService.getOne(new LambdaQueryWrapper<OrderConsignorDO>().eq(OrderConsignorDO::getOrderId, orderDO.getOrderId())
                    .orderByDesc(OrderConsignorDO::getId)
                    .last("limit 1"));
            orderDO = orderService.getById(orderId);
            String exceptionContent = null;
            if (exceptionNum == 0) {
                Date appendInTime = new Date();
                if (CollectionUtil.isNotEmpty(orderWarehouseInDOList)) {
                    OrderWarehouseInDO orderWarehouseInDO =
                            orderWarehouseInDOList.stream().max(Comparator.comparing(OrderWarehouseInDO::getId)).get();
                    if (orderWarehouseInDO != null) {
                        appendInTime = orderWarehouseInDO.getInTime();
                    }
                }
                warehouseInSendSms(orderDO, finishReqVO.getIsAppend(), appendInTime);
            } else {
                exceptionContent = orderUnProcessExceptionList.stream().map(ex -> OrderExceptionEnum.getEnumByKey(ex.getOrderExceptionType()).getZhValueDesc()).collect(Collectors.joining(StrUtil.COMMA));
            }
            // 发送站内信
            warehouseInSendInternalMessage(finishReqVO, orderDO, orderConsignorDO2, exceptionContent);
        }

        // 完成入仓后更新客户状态(拆单子订单不需要更新）
        if (!isSplitOrderChildren && finishReqVO.getUpdateCustomer()
                && isNotRollbackIn) {

            Set<Long> idSet = new HashSet<>();
            idSet.add(orderDO.getCustomerId());
            //订单发货人
            OrderConsignorDO orderConsignorDO2 =
                    orderConsignorService.getOne(new LambdaQueryWrapper<OrderConsignorDO>().eq(OrderConsignorDO::getOrderId, orderDO.getOrderId())
                            .orderByDesc(OrderConsignorDO::getId).last("limit 1"));

            //订单收货人
            OrderConsigneeDO orderConsigneeDO2 =
                    orderConsigneeService.getOne(new LambdaQueryWrapper<OrderConsigneeDO>().eq(OrderConsigneeDO::getOrderId, orderDO.getOrderId())
                            .orderByDesc(OrderConsigneeDO::getId).last("limit 1"));

            // if (orderConsignorDO2 != null &&
            //         orderConsignorDO2.getCustomerId() != null &&
            //         orderConsigneeDO2 != null &&
            //         orderConsigneeDO2.getCustomerId() != null) {
            //     //获取发货人客户经理
            //     CustomerDO consignorCustomer =
            //             customerService.getById(orderConsignorDO2.getCustomerId());
            //     //获取收货人客户经理
            //     CustomerDO consigneeCustomer =
            //             customerService.getById(orderConsigneeDO2.getCustomerId());
            //     //订单的发货人、收货人同属一个客户经理，则两个客户经理都延期，
            //     // 否则只延期订单中业绩归属方客户
            //     if (consignorCustomer != null && consigneeCustomer != null &&
            //             Objects.nonNull(consignorCustomer.getCustomerService()) &&
            //             Objects.nonNull(consigneeCustomer.getCustomerService()) &&
            //             (consignorCustomer.getCustomerService().equals(consigneeCustomer.getCustomerService()) || consignorCustomer.getCustomerService() == consigneeCustomer.getCustomerService())) {
            //
            //         if (orderConsignorDO2 != null &&
            //                 orderConsignorDO2.getCustomerId() != null) {
            //             idSet.add(orderConsignorDO2.getCustomerId());
            //         }
            //         if (orderConsigneeDO2 != null &&
            //                 orderConsigneeDO2.getCustomerId() != null) {
            //             idSet.add(orderConsigneeDO2.getCustomerId());
            //         }
            //     }
            // }

            // 上面逻辑是2024-05-21修改的， 下面在2024-08-08又恢复成之前的这种业务。
            // zendao #196 当订单入仓完成，订单收发方客户的客户状态均修改为成交
            if (orderConsignorDO2 != null && orderConsignorDO2.getCustomerId() != null) {
                idSet.add(orderConsignorDO2.getCustomerId());
            }

            if (orderConsigneeDO2 != null && orderConsigneeDO2.getCustomerId() != null) {
                idSet.add(orderConsigneeDO2.getCustomerId());
            }
            for (Long id : idSet) {
                customerService.updateCustomerByFinishWarehouseIn(id,
                        orderId, orderDO != null ? orderDO.getOrderNo() : "",
                        orderDO.getRucangTime());
            }
        }

        if (finishReqVO.getIsAddOrderOperateLog()) {
            orderBusinessService.addOrderOperateLog(orderId,
                    "仓库操作", msg, "");
        }

        //入仓完成，计算V值
        /*27号注释掉
        CalculateOrderVValueEvent event=new CalculateOrderVValueEvent();
        event.setOrderId(orderId);
        applicationContext.publishEvent(event);
        */

        // end 入仓完成，计算V值
        // 返回是否包含异常
        return exceptionNum > 0;
    }

    private void processOrderPayException(Long orderId, OrderDO orderDO, Integer result) {
        if (result == 1) {
            List<OrderItemDO> payAdanceOrderItemList = orderItemService.getOrderItemsByOrderId(Arrays.asList(orderId)).stream()
                    .filter(t -> t.getIsPayAdvance() != null && t.getIsPayAdvance() == 1).collect(Collectors.toList());

            // 任意存在<=0.5cbm或<=0.05kg，则必须有1条自动处理预付异常
            boolean anyMatchAutoProcessPayException = isAnyMatchAutoProcessPayException(orderDO, payAdanceOrderItemList);
            // 全部都<=0.5cbm或<=0.05kg，则只能有1条自动处理的预付异常。
            boolean allMatchAutoProcessPayException = isAllMatchAutoProcessPayException(orderDO, payAdanceOrderItemList);

            List<OrderExceptionDO> orderExceptionDOList = orderExceptionService.getOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderId, null, OrderExceptionEnum.ORDER_PAY_EXCEPTION.getKey());
            log.info("订单【{}】生成预付异常数量：{}", orderDO.getOrderNo(), CollectionUtil.isEmpty(orderExceptionDOList) ? 0 : orderExceptionDOList.size());

            // 没有预付异常，则直接创建1条，有需要自动处理的，则自动处理，然后再产生1条。
            if (CollectionUtil.isEmpty(orderExceptionDOList)) {

                log.info("订单【{}】生成预付异常", orderDO.getOrderNo());
                OrderExceptionCreateReqVO orderExceptionCreateReqVO = this.genOrderException(orderId, null, orderDO, OrderExceptionEnum.ORDER_PAY_EXCEPTION,
                        OrderExceptionEnum.ORDER_PAY_EXCEPTION.getZhValueDesc(), OrderExceptionEnum.ORDER_PAY_EXCEPTION.getEnValueDesc(), null);
                orderExceptionService.createOrderException(orderExceptionCreateReqVO);

                if (anyMatchAutoProcessPayException) {
                    String processMsg = "";
                    if (Objects.equals(TransportTypeShortEnum.AIR_FREIGHT_LINE.getValue(), orderDO.getTransportId())
                            || Objects.equals(TransportTypeShortEnum.AIR_SEA_COMBINED_TRANSPORT.getValue(), orderDO.getTransportId())) {
                        processMsg = "品名收费重量小于0.05kg";
                    }
                    // 海运
                    else if (Objects.equals(TransportTypeShortEnum.SEA_CONTAINER.getValue(), orderDO.getTransportId())
                            || Objects.equals(TransportTypeShortEnum.MARINE_CONTAINER.getValue(), orderDO.getTransportId())) {
                        processMsg = "品名收费方数小于0.5CBM";
                    }
                    // 自动处理
                    orderExceptionService.autoProcessException(orderId, null, OrderExceptionEnum.ORDER_PAY_EXCEPTION, processMsg + "，系统自动处理", OrderExceptionResult.ORDER_PAY_EXCEPTION_RESULT.PAY_TOTAL_MIN);

                    if (!allMatchAutoProcessPayException) {
                        // 再生产一条预付异常
                        OrderExceptionCreateReqVO orderExceptionCreateReqVO2 = this.genOrderException(orderId, null, orderDO, OrderExceptionEnum.ORDER_PAY_EXCEPTION,
                                OrderExceptionEnum.ORDER_PAY_EXCEPTION.getZhValueDesc(), OrderExceptionEnum.ORDER_PAY_EXCEPTION.getEnValueDesc(), null);
                        orderExceptionService.createOrderException(orderExceptionCreateReqVO2);
                    }
                }


            } else if (orderExceptionDOList.size() == 1) {
                // 若是有1条
                OrderExceptionDO orderExceptionDO = orderExceptionDOList.get(0);

                OrderExceptionResultDO exceptionResultDO = orderExceptionResultService.getOrderExceptionResultByOrderExceptionId(orderExceptionDO.getId());

                // 判断这1条是否 “系统自动处理”，若是则产生一条预付异常，不需要处理。
                if (orderExceptionDO.getOrderExceptionStatus() == 2
                        && exceptionResultDO != null && exceptionResultDO.getHandlerRemark() != null && exceptionResultDO.getHandlerRemark().endsWith("系统自动处理")
                        && !allMatchAutoProcessPayException
                ) {
                    // 再生产一条预付异常
                    OrderExceptionCreateReqVO orderExceptionCreateReqVO2 = this.genOrderException(orderId, null, orderDO, OrderExceptionEnum.ORDER_PAY_EXCEPTION,
                            OrderExceptionEnum.ORDER_PAY_EXCEPTION.getZhValueDesc(), OrderExceptionEnum.ORDER_PAY_EXCEPTION.getEnValueDesc(), null);
                    orderExceptionService.createOrderException(orderExceptionCreateReqVO2);
                }
                // 若不是系统自动处理的预付异常，则说明 缺少1条系统自动处理的预付异常。则判断这条的处理状态，
                // 				未处理，则先自动处理。 再生成一条普通异常。
                // 				已处理，则 不做任何事。
                else {

                    if (anyMatchAutoProcessPayException) {

                        // 本条已处理，则再生产一条，让其自动处理
                        if (orderExceptionDO.getOrderExceptionStatus() == 2) {
                            OrderExceptionCreateReqVO orderExceptionCreateReqVO2 = this.genOrderException(orderId, null, orderDO, OrderExceptionEnum.ORDER_PAY_EXCEPTION,
                                    OrderExceptionEnum.ORDER_PAY_EXCEPTION.getZhValueDesc(), OrderExceptionEnum.ORDER_PAY_EXCEPTION.getEnValueDesc(), null);
                            orderExceptionService.createOrderException(orderExceptionCreateReqVO2);
                        }

                        // 自动处理
                        String processMsg = "";
                        if (Objects.equals(TransportTypeShortEnum.AIR_FREIGHT_LINE.getValue(), orderDO.getTransportId())
                                || Objects.equals(TransportTypeShortEnum.AIR_SEA_COMBINED_TRANSPORT.getValue(), orderDO.getTransportId())) {
                            processMsg = "品名收费重量小于0.05kg";
                        }
                        // 海运
                        else if (Objects.equals(TransportTypeShortEnum.SEA_CONTAINER.getValue(), orderDO.getTransportId())
                                || Objects.equals(TransportTypeShortEnum.MARINE_CONTAINER.getValue(), orderDO.getTransportId())) {
                            processMsg = "品名收费方数小于0.5CBM";
                        }
                        orderExceptionService.autoProcessException(orderId, null, OrderExceptionEnum.ORDER_PAY_EXCEPTION, processMsg + "，系统自动处理", OrderExceptionResult.ORDER_PAY_EXCEPTION_RESULT.PAY_TOTAL_MIN);

                        // 未处理的 需要在自动处理后 再根据条件判断是否再生成1条。
                        if (orderExceptionDO.getOrderExceptionStatus() != 2) {
                            if (!allMatchAutoProcessPayException) {
                                // 再生产一条预付异常
                                OrderExceptionCreateReqVO orderExceptionCreateReqVO2 = this.genOrderException(orderId, null, orderDO, OrderExceptionEnum.ORDER_PAY_EXCEPTION,
                                        OrderExceptionEnum.ORDER_PAY_EXCEPTION.getZhValueDesc(), OrderExceptionEnum.ORDER_PAY_EXCEPTION.getEnValueDesc(), null);
                                orderExceptionService.createOrderException(orderExceptionCreateReqVO2);
                            }
                        }
                    } else {
                        // do nothing
                    }
                }

            } else if (orderExceptionDOList.size() == 2) {
                // 若是有2条，则不生成了。 （不管处理未处理）
            }

        } else {
            // 不需要生成预付时，要将未处理的预付异常删除
            List<OrderExceptionDO> orderExceptionDOList = orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderId, null, OrderExceptionEnum.ORDER_PAY_EXCEPTION.getKey());
            if (CollectionUtil.isNotEmpty(orderExceptionDOList)) {
                for (OrderExceptionDO orderExceptionDO : orderExceptionDOList) {
                    log.info("删除未处理的预付异常， id={}", orderExceptionDO.getId());
                    orderExceptionService.deleteOrderException(orderExceptionDO.getId());
                }
            }
        }
    }

    private boolean isAnyMatchAutoProcessPayException(OrderDO orderDO, List<OrderItemDO> payAdanceOrderItemList) {
        // 空运
        if (Objects.equals(TransportTypeShortEnum.AIR_FREIGHT_LINE.getValue(), orderDO.getTransportId())
                || Objects.equals(TransportTypeShortEnum.AIR_SEA_COMBINED_TRANSPORT.getValue(), orderDO.getTransportId())) {
            // 有任意预付商品的收费重量在0.05KG内，自动处理。 task:https://zentao.test.jdshangmen.com/task-view-2897.html
            boolean existLessEquals = payAdanceOrderItemList.stream().anyMatch(t -> {
                BigDecimal avaliableChargeWeight = t.getChargeWeight().compareTo(t.getMinMeteringWeight()) == 1 ? t.getChargeWeight() : t.getMinMeteringWeight();
                return avaliableChargeWeight.compareTo(new BigDecimal(0.05)) <= 0;
            });
            return existLessEquals;
        }

        // 海运
        if (Objects.equals(TransportTypeShortEnum.SEA_CONTAINER.getValue(), orderDO.getTransportId())
                || Objects.equals(TransportTypeShortEnum.MARINE_CONTAINER.getValue(), orderDO.getTransportId())) {
            // 有任意预付商品的收费体积在0.5Cbm内，自动处理。 task:https://zentao.test.jdshangmen.com/task-view-2897.html
            boolean existLessEquals = payAdanceOrderItemList.stream().anyMatch(t -> {
                BigDecimal avaliableChargeVolume = t.getChargeVolume().compareTo(t.getMinMeteringVolume()) == 1 ? t.getChargeVolume() : t.getMinMeteringVolume();
                return avaliableChargeVolume.compareTo(new BigDecimal(0.5)) <= 0;
            });
            return existLessEquals;
        }
        return false;
    }

    private boolean isAllMatchAutoProcessPayException(OrderDO orderDO, List<OrderItemDO> payAdanceOrderItemList) {
        // 空运
        if (Objects.equals(TransportTypeShortEnum.AIR_FREIGHT_LINE.getValue(), orderDO.getTransportId())
                || Objects.equals(TransportTypeShortEnum.AIR_SEA_COMBINED_TRANSPORT.getValue(), orderDO.getTransportId())) {
            // 有任意预付商品的收费重量在0.05KG内，自动处理。 task:https://zentao.test.jdshangmen.com/task-view-2897.html
            boolean allLessEquals = payAdanceOrderItemList.stream().allMatch(t -> {
                BigDecimal avaliableChargeWeight = t.getChargeWeight().compareTo(t.getMinMeteringWeight()) == 1 ? t.getChargeWeight() : t.getMinMeteringWeight();
                return avaliableChargeWeight.compareTo(new BigDecimal(0.05)) <= 0;
            });
            return allLessEquals;
        }

        // 海运
        if (Objects.equals(TransportTypeShortEnum.SEA_CONTAINER.getValue(), orderDO.getTransportId())
                || Objects.equals(TransportTypeShortEnum.MARINE_CONTAINER.getValue(), orderDO.getTransportId())) {
            // 有任意预付商品的收费体积在0.5Cbm内，自动处理。 task:https://zentao.test.jdshangmen.com/task-view-2897.html
            boolean allLessEquals = payAdanceOrderItemList.stream().allMatch(t -> {
                BigDecimal avaliableChargeVolume = t.getChargeVolume().compareTo(t.getMinMeteringVolume()) == 1 ? t.getChargeVolume() : t.getMinMeteringVolume();
                return avaliableChargeVolume.compareTo(new BigDecimal(0.5)) <= 0;
            });
            return allLessEquals;
        }
        return false;
    }

    private void processConsignorException(OrderWarehouseInFinishReqVO finishReqVO, Long orderId, OrderDO orderDO) {
        //入仓修改回调的入仓不需要生成单证异常和发货人异常
        if (!Boolean.TRUE.equals(finishReqVO.getIsUpdateCallback())) {
            // 海运要发货人异常，空运不要发货人异常
            if (orderDO.getTransportId() != 3 && orderDO.getTransportId() != 4) {
                // 1.12.发货人异常（客户档案设置了到仓确认，此类客户的货是通知装柜才可装）
                // 发货人
                OrderConsignorDO orderConsignorDO =
                        orderConsignorService.getOne(new LambdaQueryWrapper<OrderConsignorDO>().eq(OrderConsignorDO::getOrderId, orderDO.getOrderId())
                                .orderByDesc(OrderConsignorDO::getId)
                                .last("limit 1"));
                if (orderConsignorDO.getCustomerId() != null) {
                    CustomerDO customerDO =
                            customerMapper.selectById(orderConsignorDO.getCustomerId());

                    if (customerDO != null
                            && customerDO.getArrivalConfirm() != null
                            && customerDO.getArrivalConfirm().equals(1)) {

                        OrderExceptionCreateReqVO orderExceptionCreateReqVO =
                                genOrderException(orderId, null, orderDO,
                                        OrderExceptionEnum.ORDER_CONSIGNOR_EXCEPTION,
                                        OrderExceptionEnum.ORDER_CONSIGNOR_EXCEPTION.getZhValueDesc(),
                                        OrderExceptionEnum.ORDER_CONSIGNOR_EXCEPTION.getEnValueDesc(),
                                        null);


                        List<OrderExceptionDO> listOrderException =
                                orderExceptionService.selectList(
                                        new LambdaQueryWrapper<OrderExceptionDO>().
                                                eq(OrderExceptionDO::getOrderId, orderId).
                                                eq(OrderExceptionDO::getOrderExceptionType, "order_consignor_exception"));
                        //先判断到仓确认记录是否存在，不存在才创建
                        if (CollectionUtil.isEmpty(listOrderException)) {
                            orderExceptionService.createOrderException(orderExceptionCreateReqVO);
                        }
                    }
                }
            }
        }
    }

    private void processZhongPaoException(Long orderId, OrderDO orderDO, ZhongPaoBestVO zhongPaoBest,
                                          BigDecimal weightSum, BigDecimal volumeSum, Boolean isUpdateCallback,
                                          Boolean isSumVolumeNoChange, Boolean isSumWeightNoChange, boolean finishStocked) {
        // 拆单子订单不让其产生重泡货异常
        if (zhongPaoBest != null) {
            //
            BigDecimal zhongEdge = zhongPaoBest.getZhongEdge();
            if (zhongEdge != null && (TransportTypeShortEnum.SEA_CONTAINER.getValue().equals(orderDO.getTransportId()) || TransportTypeShortEnum.MARINE_CONTAINER.getValue().equals(orderDO.getTransportId()))) {
                // 计算（入仓时订单总重量大于订单总方数，总重量/750（取自当前用户的重货标准）>总体积）
                BigDecimal zhongCbm = BigDecimal.ZERO;
                if (weightSum.compareTo(BigDecimal.ZERO) > 0) {
                    zhongCbm = weightSum.divide(zhongEdge, 2, RoundingMode.HALF_UP);
                }
                if (zhongCbm.compareTo(volumeSum) > 0) {
                    if (isUpdateCallback && Boolean.TRUE.equals(isSumVolumeNoChange) && Boolean.TRUE.equals(isSumWeightNoChange)) {
                        // do nothing 当入仓记录修改审批后，订单方数没有改变，无需产生异常
                    } else {
                        ///重货异常
                        String descZh = String.format("该订单是重货订单, 重货方数(总)：%s", zhongCbm);
                        String descEn = String.format("It's heavy order, value(sum)：%s", zhongCbm);

                        OrderExceptionCreateReqVO orderExceptionCreateReqVO = genOrderException(orderId, null, orderDO,
                                OrderExceptionEnum.ORDER_HEAVY_CARGO_EXCEPTION, descZh, descEn, null);
                        orderExceptionService.createOrderException(orderExceptionCreateReqVO);
                        // 更新订单为重货
                        orderService.updateOrderType(orderId, 2);

                        //当产生重货异常，收费方数-实测方数<=0.05CBM,系统自动处理异常，处理结果为设置为普货，备注：重货收费方式与实测方数相差在0.05CBM内，系统自动设置为普货，操作人=admin
                        BigDecimal heavyWeightVolumeThreshold = getHeavyVolumeFloatingThreshold();
                        if ((zhongCbm.subtract(volumeSum)).compareTo(heavyWeightVolumeThreshold) <= 0) {
                            //自动处理异常，处理异常后会自动重新计价
                            orderExceptionService.autoProcessException(orderId, null, OrderExceptionEnum.ORDER_HEAVY_CARGO_EXCEPTION,
                                    String.format("重货收费方数%s与实测方数%s相差在%sCBM内，系统自动设置为普货", zhongCbm, volumeSum, heavyWeightVolumeThreshold), OrderExceptionResult.ORDER_HEAVY_CARGO_EXCEPTION_RESULT.GENERAL_CARGO);
                        }
                    }

                } else {
                    if (isUpdateCallback) {
                        // v2.2 当入仓纪录修改审批后，订单非重货且当前存在重货异常未处理，系统自动处理异常，处理结果设置为普货
                        orderExceptionService.autoProcessException(orderId, null, OrderExceptionEnum.ORDER_HEAVY_CARGO_EXCEPTION, "订单入仓纪录修改，订单非重货，系统自动处理为已处理", OrderExceptionResult.ORDER_HEAVY_CARGO_EXCEPTION_RESULT.GENERAL_CARGO);
                        // 更新订单为普货
                        orderService.updateOrderType(orderId, 1);
                    } else {
                        // 删除重货异常
                        removeException(orderId, null, OrderExceptionEnum.ORDER_HEAVY_CARGO_EXCEPTION.getKey());
                        // 更新订单为普货
                        orderService.updateOrderType(orderId, 1);
                    }
                }
            }

            //入仓不产生泡货异常，只在备货时产生泡货异常
            if (finishStocked) {
                BigDecimal paoEdge = zhongPaoBest.getPaoEdge();
                if (paoEdge != null && (TransportTypeShortEnum.AIR_FREIGHT_LINE.getValue().equals(orderDO.getTransportId()) || TransportTypeShortEnum.AIR_SEA_COMBINED_TRANSPORT.getValue().equals(orderDO.getTransportId()))) {

                    //订单体积/重量没有改变，无需产生异常.  但第一次备货，有可能都是无需打包时体积重量不会变，这时也需要看是否产生异常
                    if ((orderDO.getFirstStockedTime() == null || Boolean.FALSE.equals(isSumVolumeNoChange) || Boolean.FALSE.equals(isSumWeightNoChange))) {
                        // 计算（入仓时订单总重量大于订单总方数，总重量/750（取自当前用户的重货标准）>总体积）
                        BigDecimal paoKg = volumeSum.multiply(paoEdge).setScale(2, RoundingMode.HALF_UP);
                        // paoKg = BigDecimalUtils.convertWv(paoKg);

                        //fix: #4721 【2.0-异常订单】订单备货前，特价申请泡货优惠，完成备货后，重新生产泡货异常 ，异常订单列表仍然显示备货前的泡货数据
                        //当订单申请泡重优惠成功后， 使用泡重优惠的值做为泡货重量。
                        BigDecimal specialVWeight = orderDO.getSpecialVWeight();
                        if (Boolean.TRUE.equals(isSumWeightNoChange) && Boolean.TRUE.equals(isSumVolumeNoChange) && specialVWeight != null && BigDecimal.ZERO.compareTo(specialVWeight) != 0) {
                            paoKg = specialVWeight;
                        }

                        if (paoKg.compareTo(weightSum) > 0) {
                            // 泡货异常
                            String descZh = String.format("该订单是泡货订单, 泡货重量(总)：%sKg", paoKg);
                            String descEn = String.format("It's heavy order, weight(sum)：%s", paoKg);

                            OrderExceptionCreateReqVO orderExceptionCreateReqVO = genOrderException(orderId, null, orderDO,
                                    OrderExceptionEnum.ORDER_BULKY_CARGO_EXCEPTION, descZh, descEn, null);
                            orderExceptionService.createOrderException(orderExceptionCreateReqVO);
                            // 更新订单为泡货
                            orderService.updateOrderType(orderId, 3);

                            // v2.0空运 收费重量-实测重量<=0.05KG（字典值默认0.05）,系统自动处理异常，处理结果为设置为普货，备注：泡货收费重量与实测重量相差在0.05KG内，系统自动设置为普货，操作人=admin
                            BigDecimal bubbleWeightFloatingThreshold = getBubbleWeightFloatingThreshold();
                            if ((paoKg.subtract(weightSum)).compareTo(bubbleWeightFloatingThreshold) <= 0) {
                                orderExceptionService.autoProcessException(orderId, null, OrderExceptionEnum.ORDER_BULKY_CARGO_EXCEPTION,
                                        String.format("泡货收费重量%s与实测重量%s相差在%sKG内，系统自动设置为普货", paoKg, weightSum, bubbleWeightFloatingThreshold), OrderExceptionResult.ORDER_BULKY_CARGO_EXCEPTION_RESULT.GENERAL_CARGO);
                            }

                        } else {
                            // v2.0空运 当入仓备货/理货记录修改审批后，订单非泡货且当前存在泡货异常未处理，系统自动处理异常，处理结果为设置为普货，备注：订单入仓记录修改，订单非泡货，系统自动处理为已处理，操作人=admin
                            orderExceptionService.autoProcessException(orderId, null, OrderExceptionEnum.ORDER_BULKY_CARGO_EXCEPTION, "订单入仓记录修改，订单非泡货，系统自动处理为已处理", OrderExceptionResult.ORDER_BULKY_CARGO_EXCEPTION_RESULT.GENERAL_CARGO);
                            // 更新订单为普货
                            orderService.updateOrderType(orderId, 1);
                        }

                    }
                }
            }
        }
    }

    private void resetSpecialVWeightAndWeightUnit(Long orderId, OrderDO orderDO, Boolean isSumWeightNoChange, Boolean isOrderSumVolumeNoChange) {
        //入仓修改或完成备货，入仓重量、备货重量变化后，按最新入仓或备货重量，重新计算泡重，按最新入仓重量与订单泡货标准重新计算泡重。
        // 清空之前申请的固定泡重优惠，之前申请泡货标准还原到初始泡货标准。
        if (Boolean.FALSE.equals(isSumWeightNoChange) || Boolean.FALSE.equals(isOrderSumVolumeNoChange)) {
            //泡重优惠值
            BigDecimal specialVWeight = orderDO.getSpecialVWeight();
            if (specialVWeight != null && specialVWeight.compareTo(BigDecimal.ZERO) != 0) {
                orderService.update(null, new LambdaUpdateWrapper<OrderDO>()
                        .set(OrderDO::getSpecialVWeight, null)
                        .eq(OrderDO::getOrderId, orderDO.getOrderId()));
                orderBusinessService.addOrderOperateLog(orderId, "仓库操作", String.format("重量/体积改变导致泡重优惠[%s]失效", specialVWeight), "");
            }
            //泡货优惠标准
            BigDecimal weightUnit = orderDO.getWeightUnit();
            if (orderDO.getVolumeUnit() != null && weightUnit.compareTo(BigDecimal.ZERO) != 0) {
                orderService.update(null, new LambdaUpdateWrapper<OrderDO>()
                        .set(OrderDO::getVolumeUnit, 0)
                        .eq(OrderDO::getOrderId, orderDO.getOrderId()));
                orderBusinessService.addOrderOperateLog(orderId, "仓库操作", String.format("重量/体积改变导致泡重标准优惠[%s]失效", weightUnit), "");
            }
        }
    }

    /*
     处理多箱或少箱异常
     2024-06-04 添加注释
     ecw_order_exception_result 异常处理记录表
     */
    private void processMoreOrLessException(Long orderId,
                                            OrderDO orderDO,
                                            Integer sumNumWarehouseIn) {
        Integer totalNum = 0;
        if (StringUtils.isNotBlank(orderDO.getCost())) {
            CostVO costVO = JSONObject.parseObject(orderDO.getCost(), CostVO.class);
            totalNum = costVO.getTotalNum();
        }
        // 非退场入仓
        int diff = sumNumWarehouseIn - totalNum;
        Integer diffType = getDiffType(diff);

        Integer cartonsNumDiff = Math.abs(diff);

        String unit = "1";
        DictDataRespDTO unitData =
                DictFrameworkUtils.getDictDataFromCache("packaging_type", unit);
        String labelEn = unitData != null ? unitData.getLabelEn() : unit;
        String label = unitData != null ? unitData.getLabel() : unit;
        String autoProcessExceptionRemark = "系统自动处理 处理人admin";

        if (OrderItemStatusEnum.more_than.getValue().equals(diffType)) {
            OrderExceptionEnum orderSuperfluousBoxException =
                    OrderExceptionEnum.ORDER_SUPERFLUOUS_BOX_EXCEPTION;

            // 箱数有变化时才更新异常
            boolean noSameCartonsOrderException =
                    isNoSameCartonsOrderException(orderId,
                            cartonsNumDiff,
                            orderSuperfluousBoxException);

            if (noSameCartonsOrderException) {
                // 生成多箱异常
                OrderExceptionCreateReqVO orderExceptionCreateReqVO =
                        genOrderException(orderId, null, orderDO,
                                OrderExceptionEnum.ORDER_SUPERFLUOUS_BOX_EXCEPTION,
                                String.format("超出%d%s", cartonsNumDiff, label),
                                String.format("more than %d %s", cartonsNumDiff, labelEn),
                                null);
                orderExceptionService.createOrderException(orderExceptionCreateReqVO);

                // 自动处理少箱的未处理异常
                orderExceptionService.autoProcessException(orderId, null, OrderExceptionEnum.ORDER_LACK_BOX_EXCEPTION, autoProcessExceptionRemark, OrderExceptionResult.ORDER_LACK_BOX_EXCEPTION_RESULT.CONFIRM_CORRECT);

            }

        } else if (OrderItemStatusEnum.less_than.getValue().equals(diffType)) {

            OrderExceptionEnum orderSuperfluousBoxException =
                    OrderExceptionEnum.ORDER_LACK_BOX_EXCEPTION;

            // 箱数有变化时才更新异常
            boolean noSameCartonsOrderException =
                    isNoSameCartonsOrderException(orderId,
                            cartonsNumDiff,
                            orderSuperfluousBoxException);

            if (noSameCartonsOrderException) {
                // 生成少箱异常
                OrderExceptionCreateReqVO orderExceptionCreateReqVO =
                        genOrderException(orderId, null, orderDO,
                                OrderExceptionEnum.ORDER_LACK_BOX_EXCEPTION,
                                String.format("缺少%d%s", cartonsNumDiff, label),
                                String.format("less than %d %s", cartonsNumDiff, labelEn),
                                null);
                orderExceptionService.createOrderException(orderExceptionCreateReqVO);

                // 删除多箱的未处理异常
                orderExceptionService.autoProcessException(orderId, null, OrderExceptionEnum.ORDER_SUPERFLUOUS_BOX_EXCEPTION, autoProcessExceptionRemark, OrderExceptionResult.ORDER_SUPERFLUOUS_BOX_EXCEPTION_RESULT.CONFIRM_CORRECT);
            }
        } else {
            // 删除少箱的未处理异常
            //少箱异常
            orderExceptionService.autoProcessException(orderId,
                    null,
                    OrderExceptionEnum.ORDER_LACK_BOX_EXCEPTION,
                    autoProcessExceptionRemark,
                    OrderExceptionResult.ORDER_LACK_BOX_EXCEPTION_RESULT.CONFIRM_CORRECT);
            // 删除多箱的未处理异常
            //处理少箱异常的时间问题
            orderExceptionService.autoProcessException(orderId, null,
                    OrderExceptionEnum.ORDER_SUPERFLUOUS_BOX_EXCEPTION,
                    autoProcessExceptionRemark,
                    OrderExceptionResult.ORDER_SUPERFLUOUS_BOX_EXCEPTION_RESULT.CONFIRM_CORRECT);
        }
    }

    private void processOrderItemException(Long orderId, OrderDO orderDO, List<OrderItemDO> orderItemDOList,
                                           boolean isNotRollbackIn, List<OrderWarehouseInDO> orderWarehouseInDOList, ZhongPaoBestVO zhongPaoBest,
                                           List<ChannelPackagingOverWeightAdditionalBo> channelPackagingOverWeightAdditionalBoList, boolean isFinishStocked) {
        // 处理异常
        for (OrderItemDO orderItemDO : orderItemDOList) {

            // 新商品异常
            if (null != orderItemDO.getProdId()) {
                ProductDO productDO = productService.getProduct(orderItemDO.getProdId());
                if (productDO.getStatus() == 1) {
                    // 生成新商品异常
                    OrderExceptionCreateReqVO orderExceptionCreateReqVO = genOrderException(orderId, orderItemDO.getOrderItemId(), orderDO,
                            OrderExceptionEnum.GOODS_ADD_EXCEPTION,
                            String.format("仓库入仓新增商品【%s】", productDO.getTitleZh()),
                            String.format("add new product【%s】", productDO.getTitleEn()), null);
                    orderExceptionService.createOrderException(orderExceptionCreateReqVO);
                } else {
                    // 删除新商品异常
                    removeException(orderId, orderItemDO.getOrderItemId(), OrderExceptionEnum.GOODS_ADD_EXCEPTION.getKey());
                }
            }

            //处理已删除的商品特性
            orderItemDO.setProdAttrIds(productAttrService.delInvalidAttrIds(orderItemDO.getProdAttrIds()));
            orderItemDO.setWarehouseInProdAttrIds(productAttrService.delInvalidAttrIds(orderItemDO.getWarehouseInProdAttrIds()));

            List<OrderWarehouseInDO> orderWarehouseInDOListFilter = orderWarehouseInDOList.stream().filter(t ->
                    t.getOrderItemId().equals(orderItemDO.getOrderItemId())).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(orderWarehouseInDOListFilter)) {

                // orderItem 设置warehouseInInfoVo
                WarehouseInInfoVO warehouseInInfoVO = this.orderItemSetWarehouseInInfoVO(orderItemDO, orderWarehouseInDOListFilter);

                // 处理空运订单 商品重量超限异常 和 商品路线重量超限异常 (完成入仓时才需要，备货完成时不需要处理）
                if (!isFinishStocked) {
                    this.processAirOrderOverWeightException(orderId, orderDO, orderItemDO, warehouseInInfoVO, channelPackagingOverWeightAdditionalBoList);
                }

                this.setOrderItemZhongPao(zhongPaoBest, orderItemDO, warehouseInInfoVO.getWeight(), warehouseInInfoVO.getVolume());

                // 更新orderItem状态
                orderItemDO.setItemStatus(warehouseInInfoVO.getDiffType());

            } else {
                if (isNotRollbackIn) { // 非退场入仓
                    Integer cartonsNumDiff = orderItemDO.getNum();
                    if (cartonsNumDiff != null && cartonsNumDiff != 0) {
                        // 更新orderItem状态
                        orderItemDO.setItemStatus(OrderItemStatusEnum.less_than.getValue());
                    }
                }
            }
        }


        // 更新orderItemDOList
        if (CollectionUtil.isNotEmpty(orderItemDOList)) {
            orderItemService.updateBatch(orderItemDOList);
        }
    }

    private void processAirOrderOverWeightException(Long orderId, OrderDO orderDO, OrderItemDO orderItemDO, WarehouseInInfoVO warehouseInInfoVO,
                                                    List<ChannelPackagingOverWeightAdditionalBo> channelPackagingOverWeightAdditionalBoList) {
        // 空运订单
        if (orderDO.getTransportId() == 3 || orderDO.getTransportId() == 4) {

            if (null != orderItemDO.getProdId()) {
                ProductDO productDO = productService.getProduct(orderItemDO.getProdId());
                if (productDO != null) {
                    BigDecimal weightSum = warehouseInInfoVO.getWeight();

                    Long orderItemId = orderItemDO.getOrderItemId();

                    // 商品空运路线额定重量
                    ProductPriceDO productPriceDo = productPriceService.getProductPriceById(productDO.getId(), orderDO.getLineId(), orderDO.getChannelId());
                    BigDecimal productPriceLineOverWeightLimit = productPriceDo == null ? BigDecimal.ZERO : productPriceDo.getWeightLimit();
                    boolean isProductPriceLineOverweight = productPriceLineOverWeightLimit != null && productPriceLineOverWeightLimit.compareTo(BigDecimal.ZERO) == 1
                            && productPriceLineOverWeightLimit.compareTo(weightSum) < 0;

                    GoodsLineOverWeightAdditionalBo goodsLineOverWeightAdditionalBo = null;
                    if (isProductPriceLineOverweight) {

                        // 获取渠道名称
                        QueryChannelInfoEvent queryChannelInfoEvent = new QueryChannelInfoEvent();
                        queryChannelInfoEvent.setChannelId(orderDO.getChannelId());
                        applicationContext.publishEvent(queryChannelInfoEvent);
                        String channelNameZh = queryChannelInfoEvent.getNameZh();
                        String channelNameEn = queryChannelInfoEvent.getNameEn();

                        LogisticsInfoDto startInfoAndDestInfoByLineId = warehouseLineMapper.getStartInfoAndDestInfoByLineId(orderDO.getLineId());
                        String startTitleZh = startInfoAndDestInfoByLineId.getStartTitleZh();
                        String startTitleEn = startInfoAndDestInfoByLineId.getStartTitleEn();
                        String destTitleZh = startInfoAndDestInfoByLineId.getDestTitleZh();
                        String destTitleEn = startInfoAndDestInfoByLineId.getDestTitleEn();

                        // 生成商品路线超重异常
                        String goodsLineWeightExceptionDescZh = String.format("商品【%s】在路线【%s】到【%s】【%s】渠道下的空运订单重量上限为【%s】kg，该订单中此商品的入仓重量为【%s】kg, 超过了此商品在此线路此渠道下的空运订单重量上限。",
                                productDO.getTitleZh(), startTitleZh, destTitleZh, channelNameZh, productPriceLineOverWeightLimit, weightSum);
                        String goodsLineWeightExceptionDescEn = String.format("The weight [%s]kg of item [%s] in the order channel [%s] line [%s] to [%s] exceeds the order item upper limit [%s] kg. ",
                                weightSum, productDO.getTitleEn(), channelNameEn, startTitleEn, destTitleEn, productPriceLineOverWeightLimit);

                        goodsLineOverWeightAdditionalBo = new GoodsLineOverWeightAdditionalBo(
                                productDO.getId(), productDO.getTitleZh(), productDO.getTitleEn(),
                                orderDO.getLineId(), startTitleZh, startTitleEn, destTitleZh, destTitleEn,
                                orderDO.getChannelId(), channelNameZh, channelNameEn,
                                weightSum, productPriceLineOverWeightLimit, goodsLineWeightExceptionDescZh, goodsLineWeightExceptionDescEn);
                    }

                    // 线路渠道包装额定重量
                    ChannelPackagingOverWeightAdditionalBo channelPackagingOverWeightAdditionalBo = channelPackagingOverWeightAdditionalBoList.stream()
                            .filter(t -> CollectionUtil.isNotEmpty(t.getOrderItemIdList()) && t.getOrderItemIdList().size() == 1 && t.getOrderItemIdList().get(0).equals(orderItemId)).findFirst().orElse(null);

                    // 商品路线超重异常
                    String goodsLineWeightExceptionDescZh = goodsLineOverWeightAdditionalBo == null ? "" : goodsLineOverWeightAdditionalBo.getGoodsLineWeightExceptionDescZh();
                    String goodsLineWeightExceptionDescEn = goodsLineOverWeightAdditionalBo == null ? "" : goodsLineOverWeightAdditionalBo.getGoodsLineWeightExceptionDescEn();
                    // 路线渠道超重异常
                    String channelPackagingOverWeightExceptionDescZh = channelPackagingOverWeightAdditionalBo == null ? "" : channelPackagingOverWeightAdditionalBo.getExceptionDescZh();
                    String channelPackagingOverWeightExceptionDescEn = channelPackagingOverWeightAdditionalBo == null ? "" : channelPackagingOverWeightAdditionalBo.getExceptionDescEn();


                    boolean isCreateProductPriceOverweightException = false;

                    if (isProductPriceLineOverweight && channelPackagingOverWeightAdditionalBo != null) {
                        // 要合并的情况
                        // 1、渠道包装重量上限 大于 空运路线重量上限，则生成渠道包装重量超限异常
                        if (channelPackagingOverWeightAdditionalBo.getOverWeightLimit().compareTo(productPriceLineOverWeightLimit) == 1) {

                            channelPackagingOverWeightExceptionDescZh = channelPackagingOverWeightExceptionDescZh + "另外，" + goodsLineWeightExceptionDescZh;
                            channelPackagingOverWeightExceptionDescEn = channelPackagingOverWeightExceptionDescEn + "In addition, " + goodsLineWeightExceptionDescEn;
                            channelPackagingOverWeightAdditionalBo.setExceptionDescZh(channelPackagingOverWeightExceptionDescZh);
                            channelPackagingOverWeightAdditionalBo.setExceptionDescEn(channelPackagingOverWeightExceptionDescEn);
                        }
                        // 2、渠道包装重量上限 小于等于 空运路线重量上限，则生成空运路线重量上限异常。描述得加上渠道包装异常的描述。
                        else {
                            goodsLineWeightExceptionDescZh = goodsLineWeightExceptionDescZh + "另外，" + channelPackagingOverWeightExceptionDescZh;
                            goodsLineWeightExceptionDescEn = goodsLineWeightExceptionDescEn + "In addition, " + channelPackagingOverWeightExceptionDescEn;
                            goodsLineOverWeightAdditionalBo.setGoodsLineWeightExceptionDescZh(goodsLineWeightExceptionDescZh);
                            goodsLineOverWeightAdditionalBo.setGoodsLineWeightExceptionDescEn(goodsLineWeightExceptionDescEn);

                            isCreateProductPriceOverweightException = true;
                            channelPackagingOverWeightAdditionalBo.setMerged(true);
                        }
                    } else if (!isProductPriceLineOverweight && channelPackagingOverWeightAdditionalBo != null) {
                        // 需要生成渠道包装超重异常，但这个放在外面去生成，故这里只需要自动处理空运线路重量超限异常即可
                        orderExceptionService.autoProcessException(orderId, orderItemId, OrderExceptionEnum.LINE_WEIGHT_EXCEPTION, "未超过商品空运路线重量上限，系统已自动处理", OrderExceptionResult.LINE_WEIGHT_EXCEPTION_RESULT.CONFIRMED_SEND);
                    } else if (isProductPriceLineOverweight && channelPackagingOverWeightAdditionalBo == null) {
                        isCreateProductPriceOverweightException = true;
                    } else if (!isProductPriceLineOverweight && channelPackagingOverWeightAdditionalBo == null) {
                        // 自动处理掉商品空运线路重量超限异常
                        orderExceptionService.autoProcessException(orderId, orderItemId, OrderExceptionEnum.LINE_WEIGHT_EXCEPTION, "未超过商品空运路线重量上限，系统已自动处理", OrderExceptionResult.LINE_WEIGHT_EXCEPTION_RESULT.CONFIRMED_SEND);
                    }

                    if (isCreateProductPriceOverweightException) {
                        // 生成商品空运路线重量超限异常， 并且自动处理掉商品重量超限异常
                        boolean isNoSame = isNoSameOrderException(orderId, orderItemId, goodsLineWeightExceptionDescZh, goodsLineWeightExceptionDescEn, OrderExceptionEnum.LINE_WEIGHT_EXCEPTION);
                        if (isNoSame) {
                            OrderExceptionCreateReqVO orderExceptionCreateReqVO = genOrderException(orderId, orderItemId, orderDO,
                                    OrderExceptionEnum.LINE_WEIGHT_EXCEPTION, goodsLineWeightExceptionDescZh, goodsLineWeightExceptionDescEn, null, JSON.toJSONString(goodsLineOverWeightAdditionalBo));
                            orderExceptionService.createOrderException(orderExceptionCreateReqVO);

                            // 自动处理清关费未报价异常
                            orderExceptionService.autoProcessException(orderId, orderItemId, OrderExceptionEnum.CUSTOMS_FEE_NOT_QUOTE_EXCEPTION, "因处理商品路线重量超限异常，自动取消。", OrderExceptionResult.CUSTOMS_FEE_NOT_QUOTE_EXCEPTION_RESULT.PROCESSED);
                            orderExceptionService.autoProcessException(orderId, orderItemId, OrderExceptionEnum.ORDER_NO_QUOTE_EXCEPTION, "因处理商品路线重量超限异常，自动取消。", OrderExceptionResult.CUSTOMS_FEE_NOT_QUOTE_EXCEPTION_RESULT.PROCESSED);
                        }
                    }
                }
            }
        }
    }


    private List<ChannelPackagingOverWeightAdditionalBo> genChannelPackagingOverweightAdditionalBoList(OrderDO orderDO, List<OrderWarehouseInDO> orderWarehouseInDOList) {

        List<ChannelPackagingOverWeightAdditionalBo> resultList = new ArrayList<>();
        // 空运订单，渠道包装重量超限异常
        if (orderDO.getTransportId() == 3 || orderDO.getTransportId() == 4) {
            Long orderId = orderDO.getOrderId();

            Map<String, List<OrderWarehouseInDO>> packagingOrderWarehouseInMap = orderWarehouseInDOList.stream().collect(Collectors.groupingBy(OrderWarehouseInDO::getUnit));

            packagingOrderWarehouseInMap.forEach((packaging, packageOrderWarehouseInList) -> {
                // 渠道重量超限异常
                BigDecimal packagingWeightSum = packageOrderWarehouseInList.stream().map(OrderWarehouseInDO::getWeight).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
                List<Long> orderItemIdList = packageOrderWarehouseInList.stream().map(OrderWarehouseInDO::getOrderItemId).distinct().collect(Collectors.toList());

                Long lineId = orderDO.getLineId();
                Long channelId = orderDO.getChannelId();
                if (StringUtils.isNotEmpty(packaging) && channelId != null) {

                    List<LineChannelPackagingDO> lineChannelPackagingDOList = lineChannelPackagingService.queryAirClearancePrice(CollectionUtil.newArrayList(packaging), channelId, lineId);
                    if (CollectionUtil.isNotEmpty(lineChannelPackagingDOList)) {
                        LineChannelPackagingDO lineChannelPackagingDO = lineChannelPackagingDOList.get(0);

                        BigDecimal channelPackagingAirWeightLimit = lineChannelPackagingDO.getAirWeightLimit();
                        // 此品名的入仓包装重量和 > 渠道包装重量上限
                        if (channelPackagingAirWeightLimit != null && packagingWeightSum.compareTo(channelPackagingAirWeightLimit) == 1) {
                            // 获取渠道名称
                            QueryChannelInfoEvent queryChannelInfoEvent = new QueryChannelInfoEvent();
                            queryChannelInfoEvent.setChannelId(orderDO.getChannelId());
                            applicationContext.publishEvent(queryChannelInfoEvent);
                            String channelNameZh = queryChannelInfoEvent.getNameZh();
                            String channelNameEn = queryChannelInfoEvent.getNameEn();

                            DictDataRespDTO packagingTypeDict = DictFrameworkUtils.getDictDataFromCache("packaging_type", packaging);
                            String packagingLabelZh = packagingTypeDict.getLabel();
                            String packagingLabelEn = packagingTypeDict.getLabelEn();

                            LogisticsInfoDto startInfoAndDestInfoByLineId = warehouseLineMapper.getStartInfoAndDestInfoByLineId(lineId);
                            String startTitleZh = startInfoAndDestInfoByLineId.getStartTitleZh();
                            String startTitleEn = startInfoAndDestInfoByLineId.getStartTitleEn();
                            String destTitleZh = startInfoAndDestInfoByLineId.getDestTitleZh();
                            String destTitleEn = startInfoAndDestInfoByLineId.getDestTitleEn();


                            String exceptionDescZh = String.format("当前渠道【%s】包装【%s】的上限为【%s】Kg, 该包装类型的入仓重量【%s】kg大于渠道包装重量上限",
                                    channelNameZh, packagingLabelZh, channelPackagingAirWeightLimit, packagingWeightSum);
                            String exceptionDescEn = String.format("Channel [%s] packaging [%s] weight limit [%s] kg, the warehouse-in weight [%s] is exceed the limit",
                                    channelNameEn, packagingLabelEn, channelPackagingAirWeightLimit, packagingWeightSum);

                            ChannelPackagingOverWeightAdditionalBo additionalBo = new ChannelPackagingOverWeightAdditionalBo(lineId,
                                    startTitleZh, startTitleEn, destTitleZh, destTitleEn, channelId, channelNameZh, channelNameEn,
                                    packagingWeightSum, channelPackagingAirWeightLimit, packaging, packagingLabelZh, packagingLabelEn,
                                    orderItemIdList, exceptionDescZh, exceptionDescEn, false);

                            resultList.add(additionalBo);
                        }
                    }
                }
            });
        }

        return resultList;
    }

    private boolean isNoSameOrderException(Long orderId, Long orderItemId, String descZh, String descEn, OrderExceptionEnum orderExceptionEnum) {
        boolean noSameException = true;
        List<OrderExceptionDO> heavyExceptionList = orderExceptionService.getOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderId, orderItemId, orderExceptionEnum.getKey());
        if (CollectionUtil.isNotEmpty(heavyExceptionList)) {
            OrderExceptionDO orderExceptionDO = heavyExceptionList.get(0);
            if (StringUtils.isNotEmpty(orderExceptionDO.getOrderExceptionRemark())) {
                try {
                    OrderExceptionDescVO orderExceptionDescVO = JSON.parseObject(orderExceptionDO.getOrderExceptionRemark(), OrderExceptionDescVO.class);
                    if (descZh.equals(orderExceptionDescVO.getDescZh()) && descEn.equals(orderExceptionDescVO.getDescEn())) {
                        noSameException = false;
                    }
                } catch (Exception e) {
                    noSameException = true;
                }
            }
        }
        return noSameException;
    }

    private boolean isNoSameCartonsOrderException(Long orderId,
                                                  int cartonsNumDiff,
                                                  OrderExceptionEnum orderSuperfluousBoxException) {
        boolean noSameProcessedException = true;

        List<OrderExceptionDO> orderExceptionList =
                orderExceptionService.getOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderId, null, orderSuperfluousBoxException.getKey());
        if (CollectionUtil.isNotEmpty(orderExceptionList)) {
            try {
                OrderExceptionDO orderExceptionDO = orderExceptionList.get(0);
                // 已处理且箱数不变，则不需要生成新的多箱异常
                if (cartonsNumDiff == Integer.parseInt(JSON.parseObject(orderExceptionDO.getOrderExceptionRemark(), OrderExceptionDescVO.class).getDescEn().split(" ")[2])) {
                    noSameProcessedException = false;
                }
            } catch (NumberFormatException e) {
                return noSameProcessedException;
            }
        }
        return noSameProcessedException;
    }

    private void removeException(Long orderId, Long orderItemId, String exceptionKey) {
        List<OrderExceptionDO> pendHeavyExceptionList = orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderId, orderItemId, exceptionKey);
        if (CollectionUtil.isNotEmpty(pendHeavyExceptionList)) {
            pendHeavyExceptionList.stream().forEach(orderExceptionDO -> orderExceptionService.deleteOrderException(orderExceptionDO.getId()));
        }
    }


    private void setOrderItemZhongPao(ZhongPaoBestVO zhongPaoBest, OrderItemDO orderItemDO, BigDecimal sumWeight, BigDecimal sumVolume) {
        // 设置重泡货
        if (zhongPaoBest != null) {
            if (zhongPaoBest.getPaoFormulas() != null) {
                BigDecimal paoKg = sumVolume.multiply(zhongPaoBest.getPaoFormulas());
                // paoKg = BigDecimalUtils.convertWv(paoKg);
                orderItemDO.setVWeight(paoKg);
            }
            if (zhongPaoBest.getZhongFormulas() != null) {
                BigDecimal zhongCbm = sumWeight.multiply(zhongPaoBest.getZhongFormulas());
                orderItemDO.setWVolume(zhongCbm);
            }
        }
    }

    private String getOrderOtherExceptionDesc(String manualExceptionType, Integer lang, String descZhInput, String descEnInput) {
        StringBuffer stringBuffer = new StringBuffer();
        for (String value : manualExceptionType.split(",")) {
            DictDataRespDTO data = DictFrameworkUtils.getDictDataFromCache("manual_exception_type", value);
            if (data != null) {
                if (StringUtils.isNotEmpty(stringBuffer)) {
                    stringBuffer.append(",");
                }
                stringBuffer.append(lang == 0 ? data.getLabel() : data.getLabelEn());
            }
        }
        if (StringUtils.isNotEmpty(stringBuffer)) {
            stringBuffer.append(": ");
        }
        stringBuffer.append(lang == 0 ? (StringUtils.isNotEmpty(descZhInput) ? descZhInput : "") : (StringUtils.isNotEmpty(descEnInput) ? descEnInput : ""));
        return stringBuffer.toString();
    }

    private String getStockUpExceptionDesc(String manualExceptionType, Integer lang, String descZhInput, String descEnInput) {
        StringBuffer stringBuffer = new StringBuffer();
        for (String value : manualExceptionType.split(",")) {
            DictDataRespDTO data = DictFrameworkUtils.getDictDataFromCache("stock_up_exception_type", value);
            if (data != null) {
                if (StringUtils.isNotEmpty(stringBuffer)) {
                    stringBuffer.append(",");
                }
                stringBuffer.append(lang == 0 ? data.getLabel() : data.getLabelEn());
            }
        }
        if (StringUtils.isNotEmpty(stringBuffer)) {
            stringBuffer.append(": ");
        }
        stringBuffer.append(lang == 0 ? (StringUtils.isNotEmpty(descZhInput) ? descZhInput : "") : (StringUtils.isNotEmpty(descEnInput) ? descEnInput : ""));
        return stringBuffer.toString();
    }

    public Long getUserId(Long customerId) {
        List<CustomerContactsDO> customerContactsList = customerContactsService.getCustomerContactsListByCustomerId(customerId);
        if (CollectionUtil.isNotEmpty(customerContactsList)) {
            return customerContactsList.stream().filter(t -> t.getIsDefault().equals(1))
                    .map(CustomerContactsDO::getUserid).filter(Objects::nonNull).findFirst().orElse(null);
        }
        return null;
    }

    /*
     发送入仓短信提醒
     处理异常添加注释
     */
    public void warehouseInSendSms(OrderDO orderDO, boolean isAppend, Date appendInTime) {
        if (Boolean.TRUE.equals(orderDO.getHasSendRucangSms()) && !isAppend) {
            log.info("warehouseInSendSms入仓短信已发送过，不需要再次发送短信, orderId={}, orderNo={}", orderDO.getOrderId(), orderDO.getOrderNo());
            return;
        }
        List<OrderItemDO> orderItemDOList = orderItemService.getOrderItemsByOrderId(Collections.singletonList(orderDO.getOrderId()));
        // 订单的实际收费数据需要对比最小收费值
        BigDecimal chargeVolume = BigDecimal.ZERO;
        BigDecimal chargeWeight = BigDecimal.ZERO;
        BigDecimal chargeQuantity = BigDecimal.ZERO;
        for (OrderItemDO item : orderItemDOList) {
            // 添加短信发送体积数异常问题分析注释
            //计价体积和最小计量体积做对比
            chargeVolume = chargeVolume.add((Objects.nonNull(item.getChargeVolume()) && item.getChargeVolume().compareTo(item.getMinMeteringVolume()) > 0)
                    || item.getChargeVolume().compareTo(BigDecimal.ZERO) == 0 ? item.getChargeVolume() : item.getMinMeteringVolume());
            chargeWeight = chargeWeight.add(Objects.nonNull(item.getChargeWeight()) && item.getChargeWeight().compareTo(item.getMinMeteringWeight()) > 0
                    || item.getChargeWeight().compareTo(BigDecimal.ZERO) == 0 ? item.getChargeWeight() : item.getMinMeteringWeight());
            chargeQuantity = chargeQuantity.add(Objects.nonNull(item.getChargeQuantity()) && item.getChargeQuantity().compareTo(item.getMinMeteringQuantity()) > 0
                    || item.getChargeQuantity().compareTo(BigDecimal.ZERO) == 0 ? item.getChargeQuantity() : item.getMinMeteringQuantity());
        }
        OrderConsignorDO orderConsignorDO = orderConsignorService.getOne(new LambdaQueryWrapper<OrderConsignorDO>().eq(OrderConsignorDO::getOrderId, orderDO.getOrderId())
                .orderByDesc(OrderConsignorDO::getId)
                .last("limit 1"));
        // 发货人 短信发送信息
        String consignorCountryCode = orderConsignorDO.getCountryCode();
        String consignorPhone = orderConsignorDO.getPhone();
        Long consignorCustomerId = orderConsignorDO.getCustomerId();

        // 查询仓库
        LogisticsInfoDto logisticsInfoDto = warehouseLineMapper.getStartInfoAndDestInfoByLineId(orderDO.getLineId());

        String consignorStartWarehouseName = consignorCountryCode.equals("86") ? logisticsInfoDto.getStartTitleZh() : logisticsInfoDto.getStartTitleEn();
        String consignorDestWearehouseName = consignorCountryCode.equals("86") ? logisticsInfoDto.getDestTitleZh() : logisticsInfoDto.getDestTitleEn();

        DateTime ruchang = DateTime.of(orderDO.getRucangTime());

        // 追加短信
        // fix: 这里添加Boolean.TRUE.equals(orderDO.getHasSendRucangSms())判断是因为在pda入仓后未完成入仓，然后在web管理端是入仓中，只能入仓补充，但事实上未发送入仓短信
        if (isAppend && Boolean.TRUE.equals(orderDO.getHasSendRucangSms())) {
            Map<String, Object> paramMap = new HashMap<>();
            // 入仓通知
            paramMap.put("order", orderDO.getOrderNo());
            String marks = orderDO.getMarks();
            if (StringUtils.isNotBlank(marks) && marks.length() > 15)
                marks = marks.replaceAll(marks.substring(12), "...");
            paramMap.put("marks", marks);
            paramMap.put("date", DateUtils.formatDateTime(appendInTime));
            paramMap.put("warehouse", consignorStartWarehouseName); //入仓名
            paramMap.put("num", orderDO.getSumNum()); //多少箱
            paramMap.put("cnts", orderDO.getSumNum()); //多少箱
            paramMap.put("cmb", chargeVolume);
            paramMap.put("mark", orderDO.getMarks());
            paramMap.put("cbm", chargeWeight);


            String templateCode = SmsSceneEnum.WAREHOUSE_IN_APPEND.getTemplateCode();

            log.info("warehouseInSendSms追加入仓短信 orderNo={}", orderDO.getOrderNo());

            SmsSendSingleToUserReqDTO reqDTO = new SmsSendSingleToUserReqDTO();
            reqDTO.setTemplateParams(paramMap);
            reqDTO.setTemplateCode(templateCode);
            reqDTO.setUserId(consignorCustomerId);
            reqDTO.setMobile(consignorPhone);
            reqDTO.setAreaCode(consignorCountryCode);
            // 发送追加通知短信
            this.smsSendNotice(consignorCountryCode, consignorPhone, consignorCustomerId, templateCode, paramMap);
        } else {
            // 入仓短信 发送给发货人与收货人
            String templateCode = SmsSceneEnum.WAREHOUSE_IN.getTemplateCode();
            if (orderDO.getTransportId() == 3) {
                templateCode = SmsSceneEnum.AIR_WAREHOUSE_IN.getTemplateCode();
            }
            log.info("warehouseInSendSms入仓短信 orderNo={}", orderDO.getOrderNo());
            try {
                // 控货 就发给控货人， 非控货就发给发件人和收件人
                if (orderDO.getIsCargoControl()) {
                    OrderCargoControlDO orderCargoControlDO = orderCargoControlService.getActualOrderCargoControlByOrderId(orderDO.getOrderId());
                    // 根据订单查询控货人
                    if (orderCargoControlDO != null && StringUtils.isNotEmpty(orderCargoControlDO.getPhone())) {
                        String cargoControlCode = orderCargoControlDO.getDialCode().toString();
                        String cargoControlPhone = orderCargoControlDO.getPhone();
                        Long cargoControlCustomerId = orderCargoControlDO.getCustomerId();

                        String cargoControlStartWarehouseName = StringUtils.equals(cargoControlCode, "86") ? logisticsInfoDto.getStartTitleZh() : logisticsInfoDto.getStartTitleEn();
                        String cargoControlDestWearehouseName = StringUtils.equals(cargoControlCode, "86") ? logisticsInfoDto.getDestTitleZh() : logisticsInfoDto.getDestTitleEn();

                        Map<String, Object> cargoControlParamMap = new HashMap<>();
                        cargoControlParamMap.put("date", DateUtils.formatDateTime(orderDO.getRucangTime()));
                        cargoControlParamMap.put("cnts", orderDO.getSumNum()); // 多少箱

                        cargoControlParamMap.put("warehouse", cargoControlStartWarehouseName); // 入仓名
                        cargoControlParamMap.put("year", ruchang.year());
                        cargoControlParamMap.put("month", ruchang.month() + 1);
                        cargoControlParamMap.put("day", ruchang.dayOfMonth());
                        cargoControlParamMap.put("order", orderDO.getOrderNo()); // orderNo
                        cargoControlParamMap.put("branch", cargoControlDestWearehouseName); // 提货点
                        cargoControlParamMap.put("box", orderDO.getSumNum()); // 多少箱
                        String marks = orderDO.getMarks();
                        if (StringUtils.isNotBlank(marks) && marks.length() > 15)
                            marks = marks.replaceAll(marks.substring(12), "...");
                        cargoControlParamMap.put("marks", marks);
                        cargoControlParamMap.put("cmb", chargeVolume);
                        cargoControlParamMap.put("kg", chargeWeight);
//                        if (orderDO.getIsCollection()) {
//                            Map<Integer, CurrencyRespDTO> currencyRespDTOMap = currencyApi.getAllCurrency();
//                            CurrencyRespDTO respDTO = currencyRespDTOMap.get(orderDO.getCollectionProxyCurrency());
//                            String currencyName = Objects.isNull(respDTO) ? "RMB" : respDTO.getTitleEn();
//                            cargoControlParamMap.put("collectofgoods", orderDO.getCollectionProxy() + currencyName);
//                            templateCode = SmsSceneEnum.WAREHOUSE_IN_CONTROL_COLLECT_OF_GOODS.getTemplateCode();
//                        } else {
                        if (orderDO.getTransportId() == 3) {
                            templateCode = SmsSceneEnum.AIR_WAREHOUSE_IN_CONTROL.getTemplateCode();
                        } else {
                            templateCode = SmsSceneEnum.WAREHOUSE_IN_CONTROL.getTemplateCode();
                        }
//                        }
                        // 给控货人发送入仓控货成功短信
                        this.smsSendNotice(cargoControlCode, cargoControlPhone, cargoControlCustomerId, templateCode, cargoControlParamMap);
                    }
                } else {
                    Map<String, Object> consignorParamMap = new HashMap<>();
                    String marks = orderDO.getMarks();
                    if (StringUtils.isNotBlank(marks) && marks.length() > 15)
                        marks = marks.replaceAll(marks.substring(12), "...");
                    consignorParamMap.put("date", DateUtils.formatDateTime(orderDO.getRucangTime()));
                    consignorParamMap.put("cnts", orderDO.getSumNum()); // 多少箱

                    consignorParamMap.put("warehouse", consignorStartWarehouseName); // 入仓名
                    consignorParamMap.put("year", ruchang.year());
                    consignorParamMap.put("month", ruchang.month() + 1);
                    consignorParamMap.put("day", ruchang.dayOfMonth());
                    consignorParamMap.put("order", orderDO.getOrderNo()); // orderNo
                    consignorParamMap.put("branch", consignorDestWearehouseName); // 提货点
                    consignorParamMap.put("box", orderDO.getSumNum()); // 多少箱

                    consignorParamMap.put("marks", marks);
                    consignorParamMap.put("cmb", chargeVolume);
                    consignorParamMap.put("kg", chargeWeight);


                    Map<String, Object> consigneeParamMap = new HashMap<>();

                    if (orderDO.getIsCollection()) {
                        Map<Integer, CurrencyRespDTO> currencyRespDTOMap = currencyApi.getAllCurrency();
                        CurrencyRespDTO respDTO = currencyRespDTOMap.get(orderDO.getCollectionProxyCurrency());
                        String currencyName = Objects.isNull(respDTO) ? "RMB" : respDTO.getTitleEn();
                        consignorParamMap.put("collectofgoods", orderDO.getCollectionProxy() + currencyName);
                        consigneeParamMap.put("collectofgoods", orderDO.getCollectionProxy() + currencyName);
                        // 入仓通知
                        if (orderDO.getTransportId() == 3) {
                            templateCode = SmsSceneEnum.AIR_WAREHOUSE_IN_COLLECT_OF_GOODS.getTemplateCode();
                        } else {
                            templateCode = SmsSceneEnum.WAREHOUSE_IN_COLLECT_OF_GOODS.getTemplateCode();
                        }

                        log.info("warehouseInSendSms非控货代收货款入仓短信 orderNo={}", orderDO.getOrderNo());
                    }
                    // 给发货人发送短信
                    this.smsSendNotice(consignorCountryCode, consignorPhone, consignorCustomerId, templateCode, consignorParamMap);

                    // 收货人 短信发送信息
                    OrderConsigneeDO orderConsigneeDO = orderConsigneeService.getOne(new LambdaQueryWrapper<OrderConsigneeDO>().eq(OrderConsigneeDO::getOrderId, orderDO.getOrderId())
                            .orderByDesc(OrderConsigneeDO::getId)
                            .last("limit 1"));

                    if (orderConsigneeDO != null) {
                        String consigneeCountryCode = orderConsigneeDO.getCountryCode();
                        String consigneePhone = orderConsigneeDO.getPhone();
                        Long consigneeCustomerId = orderConsigneeDO.getCustomerId();

                        String consigneeStartWarehouseName = consigneeCountryCode.equals("86") ? logisticsInfoDto.getStartTitleZh() : logisticsInfoDto.getStartTitleEn();
                        String consigneeDestWearehouseName = consigneeCountryCode.equals("86") ? logisticsInfoDto.getDestTitleZh() : logisticsInfoDto.getDestTitleEn();

                        if (!StringUtils.equals(consignorCountryCode.concat(consignorPhone), consigneeCountryCode.concat(consigneePhone))) {
                            consigneeParamMap.put("date", DateUtils.formatDateTime(orderDO.getRucangTime()));
                            consigneeParamMap.put("cnts", orderDO.getSumNum()); // 多少箱

                            consigneeParamMap.put("warehouse", consigneeStartWarehouseName); // 入仓名
                            consigneeParamMap.put("year", ruchang.year());
                            consigneeParamMap.put("month", ruchang.month() + 1);
                            consigneeParamMap.put("day", ruchang.dayOfMonth());
                            consigneeParamMap.put("order", orderDO.getOrderNo()); // orderNo
                            consigneeParamMap.put("branch", consigneeDestWearehouseName); // 提货点
                            consigneeParamMap.put("box", orderDO.getSumNum()); // 多少箱
                            consigneeParamMap.put("marks", marks);
                            consigneeParamMap.put("cmb", chargeVolume);
                            consigneeParamMap.put("kg", chargeWeight);
                        }
                        if (!StringUtils.equals(consignorCountryCode.concat(consignorPhone), consigneeCountryCode.concat(consigneePhone))) {
                            // 给收货人发送短信
                            this.smsSendNotice(consigneeCountryCode, consigneePhone, consigneeCustomerId, templateCode, consigneeParamMap);
                        }
                    }
                }

                // 更新订单入仓短信已发送
                orderService.update(null, new LambdaUpdateWrapper<OrderDO>()
                        .set(OrderDO::getHasSendRucangSms, true)
                        .eq(OrderDO::getOrderId, orderDO.getOrderId()));
            } catch (Exception e) {
                log.error("入仓发送短信出现异常", e);
            }
        }
    }

    private void smsSendNotice(String countryCode, String phone, Long customerId, String templateCode, Map<String, Object> paramMap) {
        SmsSendSingleToUserReqDTO reqDTO = new SmsSendSingleToUserReqDTO();
        reqDTO.setTemplateParams(paramMap);
        reqDTO.setTemplateCode(templateCode);
        reqDTO.setUserId(customerId);
        reqDTO.setMobile(phone);
        reqDTO.setAreaCode(countryCode);
        // 给发货人发送短信
        smsSendApi.sendSingleSmsToAdmin(reqDTO);
    }

    private void warehouseInSendInternalMessage(OrderWarehouseInFinishReqVO finishReqVO, OrderDO orderDO, OrderConsignorDO orderConsignorDO, String exceptionContent) {
        if (orderDO.getHasSendWarehouseInNotice()) {
            log.info("warehouseInSendNotice入仓已发送过，不需要再次发送通知, orderId={}, orderNo={}", orderDO.getOrderId(), orderDO.getOrderNo());
            return;
        }
        try {
            // 1.非控货-收件人、发货人手机号对应会员
            // 2.控货：控货方和收货方
            String phone = orderConsignorDO.getCountryCode() + orderConsignorDO.getPhone();
            Long customerId = orderConsignorDO.getCustomerId();

            Set<Long> internalMsgUserIdSet = new HashSet<>();
            if (orderDO.getUserId() != null) {
                internalMsgUserIdSet.add(orderDO.getUserId());
            }

            // 发货人
            Long consignorUserId = getUserId(orderConsignorDO.getCustomerId());
            if (consignorUserId != null) {
                internalMsgUserIdSet.add(consignorUserId);
            }

            // 收货人
            OrderConsigneeDO orderConsigneeDO = orderConsigneeService.getOne(new LambdaQueryWrapper<OrderConsigneeDO>().eq(OrderConsigneeDO::getOrderId, orderDO.getOrderId())
                    .orderByDesc(OrderConsigneeDO::getId).last("limit 1"));
            if (orderConsigneeDO != null && orderConsigneeDO.getCustomerId() != null) {
                Long consigneeUserId = getUserId(orderConsigneeDO.getCustomerId());
                if (consigneeUserId != null) {
                    internalMsgUserIdSet.add(consigneeUserId);
                }
            }

            // 控货 就发给控货人
            if (orderDO.getIsCargoControl()) {
                OrderCargoControlDO orderCargoControlDO = orderCargoControlService.getActualOrderCargoControlByOrderId(orderDO.getOrderId());
                Long cargoControlUserId = getUserId(orderCargoControlDO.getCustomerId());
                if (cargoControlUserId != null) {
                    internalMsgUserIdSet.add(cargoControlUserId);
                }
            }

            Map<String, Object> paramMap = new HashMap<>();

            // 查询仓库
            LogisticsInfoDto logisticsInfoDto = warehouseLineMapper.getStartInfoAndDestInfoByLineId(orderDO.getLineId());
            String startWarehouseName = I18nMessage.getLang() == 0 ? logisticsInfoDto.getStartTitleZh() : logisticsInfoDto.getStartTitleEn();
            String destWearehouseName = I18nMessage.getLang() == 0 ? logisticsInfoDto.getDestTitleZh() : logisticsInfoDto.getDestTitleEn();

            DateTime ruchang = DateTime.of(orderDO.getRucangTime());
            String marks = orderDO.getMarks();
            if (StringUtils.isNotBlank(marks) && marks.length() > 15)
                marks = marks.replaceAll(marks.substring(12), "...");
            paramMap.put("warehouse", startWarehouseName); // 入仓名
            paramMap.put("year", ruchang.year());
            paramMap.put("month", ruchang.month() + 1);
            paramMap.put("day", ruchang.dayOfMonth());
            paramMap.put("order", orderDO.getOrderNo()); // orderNo
            paramMap.put("branch", destWearehouseName); // 提货点
            paramMap.put("box", orderDO.getSumNum()); // 多少箱
            paramMap.put("marks", marks);
            paramMap.put("cmb", orderDO.getSumVolume());
            paramMap.put("kg", orderDO.getSumWeight());


            if (CollectionUtil.isNotEmpty(internalMsgUserIdSet)) {
                for (Long userId : internalMsgUserIdSet) {
                    UserRespDTO user = memberUserApi.getUser(userId);
                    if (user != null && StringUtils.isNotEmpty(user.getNickname())) {
                        String title = "";
                        String content = "";
                        if (orderDO.getTransportId() == 3) {
                            if (StringUtils.isNotBlank(exceptionContent)) {
                                // 空运有异常入仓
                                title = String.format(I18nMessage.getMessage("app.message.air.exception.warehousein.title"), orderDO.getOrderNo());
                                // 订单号：%s（唛头：%s）已入仓，存在异常：%s 请联系售前客服协助处理。如有疑问请于工作时间内（9:00--18:00）与我司客服联系：400-900-9962
                                content = String.format(I18nMessage.getMessage("app.message.air.exception.warehousein.content"),
                                        orderDO.getOrderNo(), orderDO.getMarks(), exceptionContent);
                            } else {
                                // 空运无异常入仓
                                title = String.format(I18nMessage.getMessage("app.message.air.warehousein.title"), orderDO.getOrderNo());
                                // 尊敬的 %s（先生/女士），捷道货运通知您：您的唛头为%s，%s箱, %sCBM, %sKg, 入仓号为%s的货物已于%s 送到%s（起运港仓库），如有疑问请于工作时间内（9:00--18:00）与我司客服联系：400-900-9962
                                content = String.format(I18nMessage.getMessage("app.message.air.warehousein.content"),
                                        user.getNickname(), orderDO.getMarks(), orderDO.getSumNum(), orderDO.getSumVolume().toPlainString(),
                                        orderDO.getSumWeight().toPlainString(), orderDO.getOrderNo(), DateUtil.format(ruchang, "yyyy年MM月dd日"),
                                        startWarehouseName);
                            }
                        } else {
                            title = String.format(I18nMessage.getMessage("app.message.warehousein.title"), orderDO.getOrderNo());
                            content = String.format(I18nMessage.getMessage("app.message.warehousein.content"),
                                    user.getNickname(), orderDO.getMarks(), orderDO.getSumNum(), orderDO.getSumVolume().toPlainString(),
                                    orderDO.getSumWeight().toPlainString(), orderDO.getOrderNo(), DateUtil.format(ruchang, "yyyy年MM月dd日"),
                                    startWarehouseName);
                        }
                        // 发送站内信
                        InternalMessageCreateDto dto = InternalMessageCreateDto.builder().toIdList(Arrays.asList(userId))
                                .fromId("")
                                .sendTime(new Date())
                                .title(title)
                                .content(content)
                                .type(3).build();
                        clientInternalMessageApi.createInternalMessage(dto);

                        // 更新订单入仓短信已发送
                        orderService.update(null, new LambdaUpdateWrapper<OrderDO>()
                                .set(OrderDO::getHasSendWarehouseInNotice, true)
                                .eq(OrderDO::getOrderId, orderDO.getOrderId()));
                    } else {
                        log.info("入仓站内信查询用户id={}为空", userId);
                    }
                }
            } else {
                log.info("入仓站内信用户获取为空");
            }


        } catch (Exception e) {
            log.error("入仓发送短信出现异常", e);
        }
    }

    @NotNull
    private WarehouseInInfoVO orderItemSetWarehouseInInfoVO(OrderItemDO orderItemDO, List<OrderWarehouseInDO> orderWarehouseInDOListExist) {

        WarehouseInInfoVO warehouseInInfoVO = orderItemSetWarehouseInInfoVO(orderItemDO.getOrderId(),
                orderItemDO.getOrderItemId(), orderItemDO.getNum(), orderItemDO.getBoxGauge(), orderWarehouseInDOListExist);
        if (warehouseInInfoVO != null) {
            String warehouseInInfoVoJson = JSON.toJSONString(warehouseInInfoVO);
            orderItemDO.setWarehouseInInfo(warehouseInInfoVoJson);
        }
        return warehouseInInfoVO;
    }

    @Override
    public WarehouseInInfoVO orderItemSetWarehouseInInfoVO(OrderItemBackVO orderItemBackVO, List<OrderWarehouseInDO> orderWarehouseInDODeletedList) {

        WarehouseInInfoVO warehouseInInfoVO = orderItemSetWarehouseInInfoVO(orderItemBackVO.getOrderId(),
                orderItemBackVO.getOrderItemId(), orderItemBackVO.getNum(), orderItemBackVO.getBoxGauge(), orderWarehouseInDODeletedList);
        if (warehouseInInfoVO != null) {

            // 设置入仓影像
            List<String> pictureUrls = orderWarehousePictureService.getWarehousePictureUrlList(5, orderItemBackVO.getOrderItemId());
            if (CollectionUtil.isNotEmpty(pictureUrls)) {
                warehouseInInfoVO.setPictureUrls(pictureUrls);
            }

            String warehouseInInfoVoJson = JSON.toJSONString(warehouseInInfoVO);
            orderItemBackVO.setWarehouseInInfo(warehouseInInfoVoJson);
        }
        return warehouseInInfoVO;
    }

    private WarehouseInInfoVO orderItemSetWarehouseInInfoVO(Long orderId, Long orderItemId, Integer orderItemNum,
                                                            String orderItemBoxGauge, List<OrderWarehouseInDO> orderWarehouseInDOListExist) {
        // 订单箱数 可判断多箱少箱异常

        Integer quantitySum = 0;
        BigDecimal weightSum = BigDecimal.ZERO;
        BigDecimal volumeSum = BigDecimal.ZERO;
        List<String> expressNoList = new ArrayList<>();
        List<String> remarkList = new ArrayList<>();

        Date firstInTime = null;
        String unit = null;
        String units = null;
        Integer specificationType = null;
        String boxGauge = null;
        Integer totalRecords = 0;
        Boolean isMultiSpecification = false;
        Integer mixStatus = 0;

        int cartonsNumSum = 0;
        if (CollectionUtil.isNotEmpty(orderWarehouseInDOListExist)) {

            totalRecords = orderWarehouseInDOListExist.size();
            isMultiSpecification = orderWarehouseInDOListExist.stream().map(OrderWarehouseInDO::getSpecificationType).filter(Objects::nonNull).distinct().count() > 1;
            cartonsNumSum = orderWarehouseInDOListExist.stream().filter(t -> t.getCartonsNum() != null).mapToInt(OrderWarehouseInDO::getCartonsNum).sum();
            quantitySum = orderWarehouseInDOListExist.stream().map(OrderWarehouseInDO::getQuantityAll).filter(Objects::nonNull).reduce(Integer::sum).orElse(null);
            weightSum = orderWarehouseInDOListExist.stream().map(OrderWarehouseInDO::getWeight).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
            volumeSum = orderWarehouseInDOListExist.stream().map(OrderWarehouseInDO::getVolume).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
            expressNoList = orderWarehouseInDOListExist.stream().map(OrderWarehouseInDO::getExpressNo).filter(StringUtils::isNotEmpty).collect(Collectors.toList());
            remarkList = orderWarehouseInDOListExist.stream().map(OrderWarehouseInDO::getRemark).filter(StringUtils::isNotEmpty).collect(Collectors.toList());
            unit = orderWarehouseInDOListExist.stream().map(OrderWarehouseInDO::getUnit).filter(Objects::nonNull).sorted().findFirst().orElse(null);
            specificationType = orderWarehouseInDOListExist.stream().map(OrderWarehouseInDO::getSpecificationType).filter(Objects::nonNull).sorted().findFirst().orElse(null);
            units = orderWarehouseInDOListExist.stream().map(OrderWarehouseInDO::getUnit).filter(Objects::nonNull).sorted().distinct().collect(Collectors.joining(","));
            firstInTime = orderWarehouseInDOListExist.stream().map(OrderWarehouseInDO::getInTime).filter(Objects::nonNull).sorted().findFirst().orElse(null);
            boxGauge = orderWarehouseInDOListExist.stream().map(OrderWarehouseInDO::getBoxGauge).filter(Objects::nonNull).sorted().findFirst().orElse(null);
            if (StringUtils.isBlank(boxGauge)) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.BOX_GAUGE_FORMAT_ERROR);
            }
            String[] gauge = boxGauge.split("\\*");
            if (gauge.length != 3) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.BOX_GAUGE_FORMAT_ERROR);
            }
            mixStatus = orderWarehouseInDOListExist.stream().anyMatch(t -> CollectionUtil.isNotEmpty(t.getOrderWarehouseInDetailsVOList())) ? 1 : 0;
        }

        Integer diffType;
        int diff = cartonsNumSum - orderItemNum;
        diffType = getDiffType(diff);


        // WarehouseInInfoVO
        WarehouseInInfoVO warehouseInInfoVO = new WarehouseInInfoVO();
        warehouseInInfoVO.setTotalRecords(totalRecords);
        warehouseInInfoVO.setIsMultiSpecification(isMultiSpecification);
        warehouseInInfoVO.setCartonsNum(cartonsNumSum);
        warehouseInInfoVO.setDiffType(diffType);
        warehouseInInfoVO.setCartonsNumDiff(Math.abs(diff));
        warehouseInInfoVO.setQuantityAll(quantitySum);
        warehouseInInfoVO.setUnit(unit);
        warehouseInInfoVO.setSpecificationType(specificationType);
        warehouseInInfoVO.setUnits(units);
        warehouseInInfoVO.setBoxGauge(orderItemBoxGauge);
        warehouseInInfoVO.setVolume(volumeSum);
        warehouseInInfoVO.setWeight(weightSum);
        warehouseInInfoVO.setBoxGauge(boxGauge);
        warehouseInInfoVO.setExpressNo(CollectionUtil.isNotEmpty(expressNoList) ? String.join(",", expressNoList) : "");
        warehouseInInfoVO.setRemark(CollectionUtil.isNotEmpty(remarkList) ? String.join(",", remarkList) : "");
        warehouseInInfoVO.setMixStatus(mixStatus);
        warehouseInInfoVO.setFirstInTime(firstInTime);

        // 设置储位

        List<OrderLocationBackVO> orderLocationBackVOList = orderLocationService.getOrderLocationBackVO(orderId, orderWarehouseInDOListExist);
        if (CollectionUtil.isNotEmpty(orderLocationBackVOList)) {
            warehouseInInfoVO.setOrderLocationBackVOList(orderLocationBackVOList);

            Map<Long, WarehouseAreaDO> wareMap = warehouseAreaMapper.selectList().stream().collect(Collectors.toMap(WarehouseAreaDO::getId, v -> v));
            Map<Long, WarehouseAreaPositionDO> positionMap = warehouseAreaPositionMapper.selectList().stream().collect(Collectors.toMap(WarehouseAreaPositionDO::getId, v -> v));

            List<OrderLocationMergeVO> orderLocationMergeVOSet = null;
            // 合并 并设置名称
            if (CollectionUtil.isNotEmpty(orderLocationBackVOList)) {
                orderLocationMergeVOSet = new ArrayList<>();
                List<OrderLocationMergeVO> mergeList = orderLocationBackVOList.stream().map(orderLocationBackVO ->
                        new OrderLocationMergeVO(orderLocationBackVO.getWareId(), orderLocationBackVO.getAreaId(), orderLocationBackVO.getLocationId())).collect(Collectors.toList());

                for (OrderLocationMergeVO orderLocation : mergeList) {
                    // 过滤
                    if (orderLocationMergeVOSet.stream().noneMatch(t -> t.equals(orderLocation))) {

                        this.setLocationName(orderLocation, wareMap, positionMap);

                        orderLocationMergeVOSet.add(orderLocation);
                    }
                }
            }

            warehouseInInfoVO.setOrderLocationMergeVOSet(orderLocationMergeVOSet);
        }

        return warehouseInInfoVO;
    }

    private Integer getDiffType(int diff) {
        Integer diffType = OrderItemStatusEnum.correct.getValue();
        if (diff > 0) {
            diffType = OrderItemStatusEnum.more_than.getValue();
        } else if (diff < 0) {
            diffType = OrderItemStatusEnum.less_than.getValue();
        }
        return diffType;
    }

    @Override
    public void orderLocation(OrderWarehouseInOrderLocationReqVO orderLocationReqVO) {

        Long orderId = orderLocationReqVO.getOrderId();
        OrderDO orderDO = orderService.getById(orderId);
        if (orderDO == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_NOT_EXISTS);
        }
        if (OrderStatusEnum.WAREHOUSE_ADJUSTMENT.getValue().equals(orderDO.getStatus())) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_WAREHOUSE_ADJUSTMENT_STATUS_NOT_ALLOWED_WAREHOUSE_IN);
        }
        List<OrderLocationCreateReqVO> orderLocationCreateReqVOList = orderLocationReqVO.getOrderLocationCreateReqVOList();

        // 储位信息 删除老储位
        orderLocationService.batchOrderUpdate(orderLocationCreateReqVOList);
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public String updateOrUpdateApply(@Valid OrderWarehouseInUpdateApplyReqVO updateReqVO) {
        // 处理删除记录失效的问题
        Long orderId = updateReqVO.getOrderId();
        Long orderItemId = updateReqVO.getOrderItemId();
        Long prodId = updateReqVO.getProdId();
        Long brand = updateReqVO.getBrand();

        // 设置是否备案和收费模式
        GetFeeTypeProductBrandEmpowerRespVO feeTypeByOrder =
                getGetFeeTypeProductBrandEmpowerRespVO(orderId, prodId, brand);
        if (feeTypeByOrder != null) {
            // //当订单项的brandType为null时才设置。（说明是新品入仓）
            // if (StringUtils.isNotEmpty(feeTypeByOrder.getRecordMode())) {
            //     updateReqVO.setBrandType(Integer.parseInt(feeTypeByOrder.getRecordMode()));
            // }
            if (StringUtils.isNotEmpty(feeTypeByOrder.getFeeType())) {
                updateReqVO.setFeeType(Integer.parseInt(feeTypeByOrder.getFeeType()));
            }
        }

        //如仓记录项
        List<OrderWarehouseInItemDto> orderWarehouseInUpdateItemDoList =
                updateReqVO.getOrderWarehouseInUpdateItemDoList();

        ProductDO productDO = productService.getProduct(prodId);
        if (productDO == null) {
            throw exception(PROD_NOT_EXISTS);
        }
        OrderDO orderDO = orderService.getById(orderId);
        if (orderDO == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_NOT_EXISTS);
        }
        if (OrderStatusEnum.WAREHOUSE_ADJUSTMENT.getValue().equals(orderDO.getStatus())) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_WAREHOUSE_ADJUSTMENT_STATUS_NOT_ALLOWED_WAREHOUSE_IN);
        }

        this.validateProdAttrAccess(prodId, orderDO.getOrderNo());

        String prodTitleZh = productDO.getTitleZh();
        String prodTitleEn = productDO.getTitleEn();

        // 校验是否有已核销的应收单，如果有，则不能再次入仓修改
        receivableService.verificationReceivableIsWriteOff(orderId, null);

        if (!Objects.equals(OrderStatusEnum.INSTALLED_CABINET.getValue(), orderDO.getStatus())
                && !Objects.equals(OrderStatusEnum.CLEARED.getValue(), orderDO.getStatus())
                && !Objects.equals(OrderStatusEnum.TWP_WAY_ARRIVAL.getValue(), orderDO.getStatus())
                && !Objects.equals(OrderStatusEnum.SHIPMENT.getValue(), orderDO.getStatus())) {

            // 订单排单校验
            applicationContext.publishEvent(new BoxCheckOrderSchedulingEvent(orderId));
        }

        // 入仓修改审批提交不允许在出货阶段进行
        if (orderDO.getStatus() > 10 && orderDO.getStatus() < 19
                && orderDO.getStatus() != OrderStatusEnum.INSTALLED_CABINET.getValue()
                && orderDO.getStatus() != OrderStatusEnum.CLEARED.getValue()
                && orderDO.getStatus() != OrderStatusEnum.TWP_WAY_ARRIVAL.getValue()) {
            throw exception(WAREHOUSE_IN_UPDATE_APPROVAL_MUST_BE_WAREHOUSE_IN);
        }
        // 拆单订单不可修改
        if (orderQueryService.isSplitOrderChildren(orderDO)) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.SPLIT_ORDER_CAN_NOT_UPDATE);
        }

        validateWarehouseInItem(orderDO, brand,
                orderWarehouseInUpdateItemDoList, prodTitleZh, prodTitleEn);

        if (CollectionUtil.isEmpty(updateReqVO.getPictureUrls())) {
            throw exception(ErrorCodeConstants.ORDER_WAREHOUSE_IN_PICTURE_NOT_NULL);
        }

        // 添加订单仓库操作日志
        OrderItemDO orderItemOld = orderItemService.selectOne(OrderItemDO::getOrderItemId, orderItemId);
        // 通过orderItemId查询db中的 orderWarehouseInDO
        List<OrderWarehouseInDO> orderWarehouseInListOld = orderWarehouseInMapper
                .selectList(new LambdaQueryWrapperX<OrderWarehouseInDO>().eq(OrderWarehouseInDO::getOrderId, orderId)
                        .eq(OrderWarehouseInDO::getOrderItemId, orderItemId));


        // 未完成入仓直接更新数据
        if (orderDO.getStatus() < OrderStatusEnum.IN_WAREHOUSE.getValue()) {
            // 除费用申请等相关审批外，其他审批都不可以操作
            throwProcessingApproval(orderDO);

            // 对象转换
            OrderWarehouseInCreateReqVO orderWarehouseInCreateReqVO = BeanUtil.copyProperties(updateReqVO, OrderWarehouseInCreateReqVO.class);
            if (CollectionUtil.isNotEmpty(orderWarehouseInUpdateItemDoList)) {
                orderWarehouseInCreateReqVO.setOrderWarehouseInItemDoList(orderWarehouseInUpdateItemDoList);
            }

            /*  修改此处,isDeleteNotInWarehouseIn 改为true
            this.doSaveOrUpdateOrderWarehouseInDo(orderWarehouseInCreateReqVO,
                    orderId, orderItemId, orderDO,
                    updateReqVO.getPictureUrls(),
                    false,
                    true);*/
            //对明细做修改
            this.doSaveOrUpdateOrderWarehouseInDo(orderWarehouseInCreateReqVO,
                    orderId, orderItemId, orderDO,
                    updateReqVO.getPictureUrls(),
                    true,
                    true);

            // 更新订单入仓信息
            OrderWarehouseInVO orderWarehouseInVO = new OrderWarehouseInVO();
            orderWarehouseInVO.setOrderId(orderId);
            orderService.orderInWarehouse(orderWarehouseInVO);

            // 更新订单状态 - 入库中
            orderService.updateStatus(orderId, orderDO.getOrderNo(),
                    OrderStatusEnum.WAREHOUSING.getValue(), null, OrderWarehouseInStatusEnum.warehousing.getValue(), null, null, null, false);


            List<ApplyInfoVO> applyInfoList = new ArrayList<>();

            compareOrderItemField(updateReqVO, orderItemOld, applyInfoList);

            compareOrderWarehouseInField(orderItemOld.getProdTitleZh(), orderWarehouseInListOld, orderWarehouseInUpdateItemDoList, applyInfoList);

            if (CollectionUtil.isNotEmpty(applyInfoList)) {
                orderBusinessService.addOrderOperateLog(orderId, "仓库操作", "入仓中货物直接修改", applyInfoList);
            }

            return I18nMessage.getMessage("order.warehousein.update.finished");
        }

        // 已完成入仓，则需要提交申请
        else {
            //完成入仓之后修改信息才发起审批流程
            // 需要提交审批，则不能有其他任何审批
            orderQueryService.throwProcessingApproval(orderId);

            if (orderQueryService.isSplitOrderChildren(orderDO)) {
                int sumOld = orderWarehouseInListOld.stream().mapToInt(OrderWarehouseInDO::getCartonsNum).sum();
                int sumNew = orderWarehouseInUpdateItemDoList.stream().mapToInt(OrderWarehouseInItemDto::getCartonsNum).sum();
                if (sumOld != sumNew) {
                    throw ServiceExceptionUtil.exception(ErrorCodeConstants.SPLIT_ORDER_CAN_NOT_CHANGE_CARTON_NUMS);
                }
            }

            List<ApplyInfoVO> applyInfoList = new ArrayList<>();
            // 处理每一个属性

            compareOrderItemField(updateReqVO, orderItemOld, applyInfoList);

            // 开始处理入仓纪录
            compareOrderWarehouseInField(orderItemOld.getProdTitleZh(),
                    orderWarehouseInListOld,
                    orderWarehouseInUpdateItemDoList,
                    applyInfoList);

            if (CollectionUtil.isNotEmpty(applyInfoList)) {

                // 仅有入仓明细直接更新，不提交审批
                if (applyInfoList.size() == 1 &&
                        applyInfoList.get(0).getName().endsWith("入仓明细")) {

                    updateOrderWarehouseInDetails(orderItemId, orderWarehouseInUpdateItemDoList, orderWarehouseInListOld);

                    orderBusinessService.addOrderOperateLog(orderId, "仓库操作", "货物入仓明细单独修改", "");

                    return I18nMessage.getMessage("order.warehousein.details.update.finished");
                }

                // 仅有入仓影像直接更新，不提交审批
                else if (applyInfoList.size() == 1 &&
                        applyInfoList.get(0).getName().endsWith("入仓影像")) {
                    // 影像
                    orderWarehousePictureService.createWarehousePictureBatch(updateReqVO.getPictureUrls(), 5, orderItemId);

                    orderBusinessService.addOrderOperateLog(orderId, "仓库操作", "货物入仓影像单独修改", applyInfoList);

                    return I18nMessage.getMessage("order.warehousein.image.update.finished");

                }

                // 仅有入仓明细和入仓影像直接更新，不提交审批
                else if (applyInfoList.size() == 2 &&
                        applyInfoList.get(0).getName().endsWith("入仓影像") && applyInfoList.get(1).getName().endsWith("入仓明细")) {
                    // 影像
                    orderWarehousePictureService.createWarehousePictureBatch(updateReqVO.getPictureUrls(), 5, orderItemId);
                    orderBusinessService.addOrderOperateLog(orderId, "仓库操作", "货物入仓影像修改", applyInfoList);

                    // 入仓明细更新
                    updateOrderWarehouseInDetails(orderItemId, orderWarehouseInUpdateItemDoList, orderWarehouseInListOld);
                    orderBusinessService.addOrderOperateLog(orderId, "仓库操作", "货物入仓明细修改", "");

                    return I18nMessage.getMessage("order.warehousein.image.and.details.update.finished");
                }

                // 包含其他更新 发起审核流程
                else {
                    // 删除入仓明细的比较，因为纪录的值会很长，没意义。
                    applyInfoList.removeIf(t -> t.getName().endsWith("入仓明细"));
                    // 设置差异对象
                    updateReqVO.setApplyInfoVOList(applyInfoList);
                    String details = JSON.toJSONString(updateReqVO);
                    log.info("入仓修改json = {}", details);

                    OrderWarehouseApprovalDO orderWarehouseApprovalDO =
                            OrderWarehouseApprovalDO.builder()
                                    .orderIds(orderId.toString())
                                    .orderItemId(updateReqVO.getOrderItemId())
                                    .type(OrderWarehouseApprovalTypeEnum.WAREHOUSE_IN_UPDATE.getValue())
                                    .followUpAdminId(WebFrameworkUtils.getLoginUserId())
                                    .details(details).build();
                    // 创建审核单，发起审批流程
                    orderWarehouseApprovalService.applyAndCreate(orderWarehouseApprovalDO,
                            WorkFlowEmus.ORDER_WAREHOUSING_MODIFICATION,
                            updateReqVO.getCopyUserId());

                    // 更新订单状态
                    Integer auditType = OrderApprovalTypeResultEnum.warehouse_update_processing.getType();
                    orderService.updateStatus(orderId, null, null, null,
                            null, null, auditType, OrderApprovalTypeResultEnum.typeAndResultOf(auditType, 1).getDesc(), false);

                    orderBusinessService.addOrderOperateLog(orderId, "仓库操作",
                            "提交货物入仓修改", applyInfoList);
                }
                return I18nMessage.getMessage("order.warehousein.update.apply.success");
            } else {
                return I18nMessage.getMessage("order.warehousein.update.nothing");
            }
        }
    }

    private void updateOrderWarehouseInDetails(Long orderItemId, List<OrderWarehouseInItemDto> orderWarehouseInUpdateItemDoList, List<OrderWarehouseInDO> orderWarehouseInDoListOld) {
        boolean updateFlag = false;
        for (OrderWarehouseInItemDto inNew : orderWarehouseInUpdateItemDoList) {
            OrderWarehouseInDO inOld = orderWarehouseInDoListOld.stream().filter(t -> t.getId().equals(inNew.getId())).findFirst().orElse(null);
            if (inOld != null) {
                List<OrderWarehouseInDetailsVO> orderWarehouseInDetailsOld = inOld.getOrderWarehouseInDetailsVOList();
                List<OrderWarehouseInDetailsVO> orderWarehouseInDetailsNew = inNew.getOrderWarehouseInDetailsVOList();

                inOld.setOrderWarehouseInDetailsVOList(orderWarehouseInDetailsNew);
                orderWarehouseInMapper.updateById(inOld);

                updateFlag = true;
            }
        }
        if (updateFlag) {

            //更新orderItem
            OrderItemDO orderItemDO = orderItemService.getOrderItem(orderItemId);
            this.orderItemSetWarehouseInInfoVO(orderItemDO, orderWarehouseInDoListOld);
            orderItemService.update(null, new LambdaUpdateWrapper<OrderItemDO>()
                    .set(OrderItemDO::getWarehouseInInfo, orderItemDO.getWarehouseInInfo())
                    .eq(OrderItemDO::getOrderItemId, orderItemId));
        }
    }

    private void compareOrderWarehouseInField(String prodTitleZhOld,
                                              List<OrderWarehouseInDO> orderWarehouseInListOld, List<OrderWarehouseInItemDto> orderWarehouseInItemDtoList,
                                              List<ApplyInfoVO> applyInfoList) {
        if (CollectionUtil.isNotEmpty(orderWarehouseInItemDtoList)) {
            ApplyInfoVO infoVO;

            // 新增入仓
            List<OrderWarehouseInItemDto> addList =
                    orderWarehouseInItemDtoList.stream().
                            filter(t -> t.getId() == null).
                            collect(Collectors.toList());

            for (OrderWarehouseInItemDto inNew : addList) {

                DictDataRespDTO unitData =
                        DictFrameworkUtils.getDictDataFromCache("packaging_type", inNew.getUnit());
                DictDataRespDTO specificationTypeData =
                        DictFrameworkUtils.getDictDataFromCache("warehousing_specification_type", inNew.getSpecificationType().toString());

                // 不在老的里面，说明是新增的
                infoVO = new ApplyInfoVO();
                infoVO.setName("新增入仓");
                infoVO.setNewValue(String.format("商品：%s %d%s，入仓规格类型：%s, 箱规：%s, 体积：%sm³, 重量：%sKg, 总数量：%d, 快递单号：%s",
                        prodTitleZhOld,
                        inNew.getCartonsNum(),
                        unitData != null ? (I18nMessage.getLang() == 0 ? unitData.getLabel() : unitData.getLabelEn()) : "空",
                        specificationTypeData != null ? (I18nMessage.getLang() == 0 ? specificationTypeData.getLabel() : specificationTypeData.getLabelEn()) : "空",
                        inNew.getBoxGauge(), inNew.getVolume().toPlainString(),
                        inNew.getWeight().toPlainString(), inNew.getQuantityAll() != null ? inNew.getQuantityAll() : 0,
                        StringUtils.isNotEmpty(inNew.getExpressNo()) ? inNew.getExpressNo() : ""));
                applyInfoList.add(infoVO);
            }

            // 删除入仓
            List<OrderWarehouseInDO> deleteList = orderWarehouseInListOld.stream().filter(old ->
                    orderWarehouseInItemDtoList.stream().noneMatch(n -> old.getId().equals(n.getId()))).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(deleteList)) {
                for (OrderWarehouseInDO old : deleteList) {

                    DictDataRespDTO unitData = DictFrameworkUtils.getDictDataFromCache("packaging_type", old.getUnit());
                    DictDataRespDTO specificationTypeData = DictFrameworkUtils.getDictDataFromCache("warehousing_specification_type", old.getSpecificationType().toString());

                    // 不在老的里面，说明是新增的
                    infoVO = new ApplyInfoVO();
                    infoVO.setName("删除入仓");
                    infoVO.setOrgValue(String.format("商品：%s, %d%s，入仓规格类型：%s, 箱规：%s, 体积：%s m³, 重量：%s Kg, 总数量：%d, 快递单号：%s",
                            prodTitleZhOld,
                            old.getCartonsNum(),
                            unitData != null ? (I18nMessage.getLang() == 0 ? unitData.getLabel() : unitData.getLabelEn()) : "空",
                            specificationTypeData != null ? (I18nMessage.getLang() == 0 ? specificationTypeData.getLabel() : specificationTypeData.getLabelEn()) : "空",
                            old.getBoxGauge(), old.getVolume().toPlainString(),
                            old.getWeight().toPlainString(), old.getQuantityAll() != null ? old.getQuantityAll() : 0,
                            StringUtils.isNotEmpty(old.getExpressNo()) ? old.getExpressNo() : ""));
                    applyInfoList.add(infoVO);

                    //删除储位
                    orderLocationService.deleteIfPresent(old.getOrderId(),
                            old.getOrderItemId(), old.getId());
                }
            }


            // 更新入仓
            for (OrderWarehouseInItemDto inNew : orderWarehouseInItemDtoList) {
                OrderWarehouseInDO inOld =
                        orderWarehouseInListOld.stream().
                                filter(t -> t.getId().equals(inNew.getId())).
                                findFirst().orElse(null);

                if (inOld != null) {

                    String prodName = String.format("商品：%s - ", prodTitleZhOld);
                    Integer cartonsNumOld = inOld.getCartonsNum();
                    Integer cartonsNumNew = inNew.getCartonsNum();
                    if (!Objects.equals(cartonsNumOld, cartonsNumNew)) {
                        infoVO = new ApplyInfoVO();
                        infoVO.setName(prodName + "入仓箱数");
                        infoVO.setOrgValue(cartonsNumOld != null ? cartonsNumOld.toString() : "0");
                        infoVO.setNewValue(cartonsNumNew != null ? cartonsNumNew.toString() : "0");
                        applyInfoList.add(infoVO);
                    }
                    Integer specificationTypeOld = inOld.getSpecificationType();
                    Integer specificationTypeNew = inNew.getSpecificationType();
                    if (!Objects.equals(specificationTypeOld, specificationTypeNew)) {

                        DictDataRespDTO specificationTypeDataOld = DictFrameworkUtils.getDictDataFromCache("warehousing_specification_type", specificationTypeOld.toString());
                        DictDataRespDTO specificationTypeDataNew = DictFrameworkUtils.getDictDataFromCache("warehousing_specification_type", specificationTypeNew.toString());

                        infoVO = new ApplyInfoVO();
                        infoVO.setName(prodName + "入仓规格类型");
                        infoVO.setOrgValue(specificationTypeDataOld != null ? (I18nMessage.getLang() == 0 ? specificationTypeDataOld.getLabel() : specificationTypeDataOld.getLabelEn()) : "空");
                        infoVO.setNewValue(specificationTypeDataNew != null ? (I18nMessage.getLang() == 0 ? specificationTypeDataNew.getLabel() : specificationTypeDataNew.getLabelEn()) : "空");
                        applyInfoList.add(infoVO);
                    }
                    String unitOld = inOld.getUnit();
                    String unitNew = inNew.getUnit();
                    if (!Objects.equals(unitOld, unitNew)) {

                        DictDataRespDTO unitDataOld = DictFrameworkUtils.getDictDataFromCache("packaging_type", unitOld);
                        DictDataRespDTO unitDataNew = DictFrameworkUtils.getDictDataFromCache("packaging_type", unitNew);

                        infoVO = new ApplyInfoVO();
                        infoVO.setName(prodName + "包装类型");
                        infoVO.setOrgValue(unitDataOld != null ? (I18nMessage.getLang() == 0 ? unitDataOld.getLabel() : unitDataOld.getLabelEn()) : "空");
                        infoVO.setNewValue(unitDataNew != null ? (I18nMessage.getLang() == 0 ? unitDataNew.getLabel() : unitDataNew.getLabelEn()) : "空");
                        applyInfoList.add(infoVO);
                    }
                    String boxGaugeOld = inOld.getBoxGauge();
                    String boxGaugeNew = inNew.getBoxGauge();
                    if (!Objects.equals(boxGaugeOld, boxGaugeNew)) {
                        infoVO = new ApplyInfoVO();
                        infoVO.setName(prodName + "入仓箱规");
                        infoVO.setOrgValue(StringUtils.isNotEmpty(boxGaugeOld) ? boxGaugeOld : "空");
                        infoVO.setNewValue(StringUtils.isNotEmpty(boxGaugeNew) ? boxGaugeNew : "空");
                        applyInfoList.add(infoVO);
                    }

                    BigDecimal volumeOld = inOld.getVolume();
                    BigDecimal volumeNew = inNew.getVolume();
                    if (volumeNew != null && volumeNew.compareTo(volumeOld) != 0) {
                        infoVO = new ApplyInfoVO();
                        infoVO.setName(prodName + "入仓体积");
                        infoVO.setOrgValue(volumeOld != null ? volumeOld.toPlainString() : "0");
                        infoVO.setNewValue(volumeNew.toPlainString());
                        applyInfoList.add(infoVO);
                    }

                    BigDecimal weightOld = inOld.getWeight();
                    BigDecimal weightNew = inNew.getWeight();
                    if (weightNew != null && weightNew.compareTo(weightOld) != 0) {
                        infoVO = new ApplyInfoVO();
                        infoVO.setName(prodName + "入仓重量");
                        infoVO.setOrgValue(weightOld != null ? weightOld.toPlainString() : "0");
                        infoVO.setNewValue(weightNew.toPlainString());
                        applyInfoList.add(infoVO);
                    }

                    Integer quantityAllOld = inOld.getQuantityAll();
                    Integer quantityAllNew = inNew.getQuantityAll();
                    if (quantityAllNew != null && !Objects.equals(quantityAllOld, quantityAllNew)) {
                        infoVO = new ApplyInfoVO();
                        infoVO.setName(prodName + "入仓数量");
                        infoVO.setOrgValue(quantityAllOld != null ? quantityAllOld.toString() : "0");
                        infoVO.setNewValue(quantityAllNew.toString());
                        applyInfoList.add(infoVO);
                    }
                    String expressNoOld = inOld.getExpressNo();
                    String expressNoNew = inNew.getExpressNo();
                    if (!Objects.equals(expressNoOld, expressNoNew)) {
                        infoVO = new ApplyInfoVO();
                        infoVO.setName(prodName + "快递单号");
                        infoVO.setOrgValue(StringUtils.isNotEmpty(expressNoOld) ? expressNoOld : "空");
                        infoVO.setNewValue(StringUtils.isNotEmpty(expressNoNew) ? expressNoNew : "空");
                        applyInfoList.add(infoVO);
                    }
                    String remarkOld = inOld.getRemark();
                    String remarkNew = inNew.getRemark();
                    if (!Objects.equals(remarkOld, remarkNew)) {
                        infoVO = new ApplyInfoVO();
                        infoVO.setName(prodName + "备注");
                        infoVO.setOrgValue(StringUtils.isNotEmpty(remarkOld) ? remarkOld : "空");
                        infoVO.setNewValue(StringUtils.isNotEmpty(remarkNew) ? remarkNew : "空");
                        applyInfoList.add(infoVO);
                    }


                    List<OrderWarehouseInDetailsVO> orderWarehouseInDetailsOld = inOld.getOrderWarehouseInDetailsVOList();
                    List<OrderWarehouseInDetailsVO> orderWarehouseInDetailsNew = inNew.getOrderWarehouseInDetailsVOList();
                    if (!Objects.equals(JSON.toJSONString(orderWarehouseInDetailsOld), JSON.toJSONString(orderWarehouseInDetailsNew))) {
                        infoVO = new ApplyInfoVO();
                        infoVO.setName(prodName + "入仓明细");
                        infoVO.setOrgValue(CollectionUtil.isNotEmpty(orderWarehouseInDetailsOld) ? JSON.toJSONString(orderWarehouseInDetailsOld) : "空");
                        infoVO.setNewValue(CollectionUtil.isNotEmpty(orderWarehouseInDetailsNew) ? JSON.toJSONString(orderWarehouseInDetailsNew) : "空");
                        applyInfoList.add(infoVO);
                    }
                }
            }

        } else {
            if (CollectionUtil.isNotEmpty(orderWarehouseInListOld)) {
                // 删除 了所有入仓
                if (CollectionUtil.isNotEmpty(orderWarehouseInListOld)) {
                    ApplyInfoVO infoVO;
                    for (OrderWarehouseInDO old : orderWarehouseInListOld) {

                        DictDataRespDTO unitData = DictFrameworkUtils.getDictDataFromCache("packaging_type", old.getUnit());
                        // 不在老的里面，说明是新增的
                        infoVO = new ApplyInfoVO();
                        infoVO.setName("删除所有入仓");
                        infoVO.setOrgValue(String.format("商品：%s, %d%s，箱规：%s, 体积：%s m³, 重量：%s Kg, 总数量：%d, 快递单号：%s",
                                prodTitleZhOld,
                                old.getCartonsNum(),
                                unitData != null ? (I18nMessage.getLang() == 0 ? unitData.getLabel() : unitData.getLabelEn()) : "空",
                                old.getBoxGauge(), old.getVolume().toPlainString(),
                                old.getWeight().toPlainString(), old.getQuantityAll() != null ? old.getQuantityAll() : 0,
                                StringUtils.isNotEmpty(old.getExpressNo()) ? old.getExpressNo() : ""));
                        applyInfoList.add(infoVO);

                        //删除储位
                        orderLocationService.deleteIfPresent(old.getOrderId(),
                                old.getOrderItemId(), old.getId());
                    }

                }
            }
        }
    }

    private void compareOrderItemField(OrderWarehouseInUpdateApplyReqVO updateReqVO, OrderItemDO orderItemOld, List<ApplyInfoVO> applyInfoList) {
        String prodName = String.format("商品：%s - ", orderItemOld.getProdTitleZh());

        ApplyInfoVO infoVO;
        if (!Objects.equals(orderItemOld.getProdId(), updateReqVO.getProdId())) {
            infoVO = new ApplyInfoVO();
            infoVO.setName("商品");
            infoVO.setOrgValue(I18nMessage.getLang() == 0 ? orderItemOld.getProdTitleZh() : orderItemOld.getProdTitleEn());
            Long prodId = updateReqVO.getProdId();
            ProductDO productDONew = productService.getProduct(prodId);
            infoVO.setNewValue(productDONew == null ? "空" : (I18nMessage.getLang() == 0 ? productDONew.getTitleZh() : productDONew.getTitleEn()));
            applyInfoList.add(infoVO);
        }

        if (!Objects.equals(orderItemOld.getBrand(), updateReqVO.getBrand())) {
            infoVO = new ApplyInfoVO();
            infoVO.setName(prodName + "品牌");
            ProductBrankDO productBrankDOOld = productBrankMapper.selectById(orderItemOld.getBrand());
            infoVO.setOrgValue(productBrankDOOld == null ? "无" : (I18nMessage.getLang() == 0 ? productBrankDOOld.getTitleZh() : productBrankDOOld.getTitleEn()));
            ProductBrankDO productBrankDONew = productBrankMapper.selectById(updateReqVO.getBrand());
            infoVO.setNewValue(productBrankDONew == null ? "无" : (I18nMessage.getLang() == 0 ? productBrankDONew.getTitleZh() : productBrankDONew.getTitleEn()));
            applyInfoList.add(infoVO);
        }
//        Integer brandTypeOld = orderItemOld.getBrandType();
//        Integer brandTypeNew = updateReqVO.getBrandType();
//        if (!Objects.equals(brandTypeOld, brandTypeNew)) {
//            infoVO = new ApplyInfoVO();
//            infoVO.setName(prodName + "是否备案");
//            infoVO.setOrgValue(brandTypeOld.equals(0) ? "无备案" : (brandTypeOld.equals(1) ? "有备案" : "中性"));
//            infoVO.setNewValue(brandTypeNew.equals(0) ? "无备案" : (brandTypeNew.equals(1) ? "有备案" : "中性"));
//            applyInfoList.add(infoVO);
//        }
        Integer feeTypeOld = orderItemOld.getFeeType();
        Integer feeTypeNew = updateReqVO.getFeeType();
        if (!Objects.equals(feeTypeOld, feeTypeNew)) {
            infoVO = new ApplyInfoVO();
            infoVO.setName(prodName + "收费模式");
            infoVO.setOrgValue(feeTypeOld.equals(0) ? "无牌价" : (feeTypeOld.equals(1) ? "有牌价" : "中性品牌价"));
            infoVO.setNewValue(feeTypeNew.equals(0) ? "无牌价" : (feeTypeNew.equals(1) ? "有牌价" : "中性品牌价"));
            applyInfoList.add(infoVO);
        }
        Integer numOld = orderItemOld.getNum();
        Integer numNew = updateReqVO.getNum();
        if (numNew != null && !Objects.equals(numOld, numNew)) {
            infoVO = new ApplyInfoVO();
            infoVO.setName(prodName + "填单数量");
            infoVO.setOrgValue(numOld != null ? numOld.toString() : "0");
            infoVO.setNewValue(numNew != null ? numNew.toString() : "0");
            applyInfoList.add(infoVO);
        }
        BigDecimal volumeOld = orderItemOld.getVolume();
        BigDecimal volumeNew = updateReqVO.getVolume();
        if (volumeNew != null && volumeNew.compareTo(volumeOld) != 0) {
            infoVO = new ApplyInfoVO();
            infoVO.setName(prodName + "填单体积");
            infoVO.setOrgValue(volumeOld != null ? volumeOld.toPlainString() : "0");
            infoVO.setNewValue(volumeNew.toPlainString());
            applyInfoList.add(infoVO);
        }
        BigDecimal weightOld = orderItemOld.getWeight();
        BigDecimal weightNew = updateReqVO.getWeight();
        if (weightNew != null && weightNew.compareTo(weightOld) != 0) {
            infoVO = new ApplyInfoVO();
            infoVO.setName(prodName + "填单重量");
            infoVO.setOrgValue(weightOld != null ? weightOld.toPlainString() : "0");
            infoVO.setNewValue(weightNew.toPlainString());
            applyInfoList.add(infoVO);
        }

        String materialOld = orderItemOld.getMaterial();
        String materialNew = updateReqVO.getMaterial();
        if (!Objects.equals(materialOld, materialNew)) {

            infoVO = new ApplyInfoVO();
            infoVO.setName(prodName + "材质");

            if (StringUtils.isNotEmpty(materialOld)) {
                DictDataRespDTO material = DictFrameworkUtils.getDictDataFromCache("product_material", materialOld);
                String labelEn = material != null ? material.getLabelEn() : materialOld;
                String label = material != null ? material.getLabel() : materialOld;
                infoVO.setOrgValue(I18nMessage.getLang() == 0 ? label : labelEn);
            } else {
                infoVO.setOrgValue("空");
            }

            if (StringUtils.isNotEmpty(materialNew)) {
                DictDataRespDTO material = DictFrameworkUtils.getDictDataFromCache("product_material", materialNew);
                String labelEn = material != null ? material.getLabelEn() : materialNew;
                String label = material != null ? material.getLabel() : materialNew;
                infoVO.setNewValue(I18nMessage.getLang() == 0 ? label : labelEn);
            } else {
                infoVO.setNewValue("空");
            }
            applyInfoList.add(infoVO);
        }

        String warehouseInProdAttrIdsNew = updateReqVO.getWarehouseInProdAttrIds();
        String warehouseInProdAttrIdsOld = StringUtils.isNotEmpty(orderItemOld.getWarehouseInProdAttrIds()) ? orderItemOld.getWarehouseInProdAttrIds() : orderItemOld.getProdAttrIds();
        String prodAttrIdsSortOld = StringUtils.isNotEmpty(warehouseInProdAttrIdsOld) ?
                Arrays.stream(warehouseInProdAttrIdsOld.split(",")).filter(Objects::nonNull).sorted(Comparator.comparingInt(Integer::parseInt)).collect(Collectors.joining(",")) : "";

        String prodAttrIdsSortNew = StringUtils.isNotEmpty(warehouseInProdAttrIdsNew) ?
                Arrays.stream(warehouseInProdAttrIdsNew.split(",")).filter(Objects::nonNull).sorted(Comparator.comparingInt(Integer::parseInt)).collect(Collectors.joining(",")) : "";

        if (!Objects.equals(prodAttrIdsSortOld, prodAttrIdsSortNew)) {

            infoVO = new ApplyInfoVO();
            infoVO.setName(prodName + "入仓商品特性");

            if (StringUtils.isNotEmpty(warehouseInProdAttrIdsOld)) {
                List<ProductAttrDO> productAttrDOS = productAttrMapper.selectBatchIds(Arrays.asList(warehouseInProdAttrIdsOld.split(StrUtil.COMMA)));
                if (CollectionUtil.isNotEmpty(productAttrDOS)) {
                    infoVO.setOrgValue(I18nMessage.getLang() == 0 ? productAttrDOS.stream().map(ProductAttrDO::getAttrName).collect(Collectors.joining(","))
                            : productAttrDOS.stream().map(ProductAttrDO::getAttrNameEn).collect(Collectors.joining(",")));
                } else {
                    infoVO.setOrgValue("空");
                }
            } else {
                infoVO.setOrgValue("空");
            }

            if (StringUtils.isNotEmpty(warehouseInProdAttrIdsNew)) {
                List<ProductAttrDO> productAttrDOS = productAttrMapper.selectBatchIds(Arrays.asList(warehouseInProdAttrIdsNew.split(StrUtil.COMMA)));
                if (CollectionUtil.isNotEmpty(productAttrDOS)) {
                    infoVO.setNewValue(I18nMessage.getLang() == 0 ? productAttrDOS.stream().map(ProductAttrDO::getAttrName).collect(Collectors.joining(","))
                            : productAttrDOS.stream().map(ProductAttrDO::getAttrNameEn).collect(Collectors.joining(",")));
                } else {
                    infoVO.setNewValue("空");
                }
            } else {
                infoVO.setNewValue("空");
            }
            applyInfoList.add(infoVO);
        }


        // 入仓影像
        List<String> pictureUrls =
                CollectionUtil.isNotEmpty(updateReqVO.getPictureUrls()) ? updateReqVO.getPictureUrls() : new ArrayList<>();
        List<String> pictureUrlsOld =
                orderWarehousePictureService.getWarehousePictureUrlList(5,
                        orderItemOld.getOrderItemId());
        if (pictureUrlsOld.size() != pictureUrls.size() ||
                pictureUrlsOld.containsAll(pictureUrls)) {
            infoVO = new ApplyInfoVO();
            infoVO.setName(prodName + "入仓影像");
            infoVO.setOrgValue((CollectionUtil.isEmpty(pictureUrlsOld) ? 0 : pictureUrlsOld.size()) + "个");
            infoVO.setNewValue((CollectionUtil.isEmpty(pictureUrls) ? 0 : pictureUrls.size()) + "个");
            applyInfoList.add(infoVO);
        }


        // 入仓商品用途
        String usageIdsNew = updateReqVO.getUsageIds();
        String usageIdsOld = orderItemOld.getUsageIds();
        String usageIdsSortOld = StringUtils.isNotEmpty(usageIdsOld) ?
                Arrays.stream(usageIdsOld.split(",")).filter(Objects::nonNull).sorted(Comparator.comparingInt(Integer::parseInt)).collect(Collectors.joining(",")) : null;
        String usageIdsSortNew = StringUtils.isNotEmpty(usageIdsNew) ?
                Arrays.stream(usageIdsNew.split(",")).filter(Objects::nonNull).sorted(Comparator.comparingInt(Integer::parseInt)).collect(Collectors.joining(",")) : null;

        if (!Objects.equals(usageIdsSortOld, usageIdsSortNew)) {

            infoVO = new ApplyInfoVO();
            infoVO.setName(prodName + "入仓商品用途");

            if (StringUtils.isNotEmpty(usageIdsOld)) {
                StringJoiner labelEnJoiner = new StringJoiner(",");
                StringJoiner labelJoiner = new StringJoiner(",");
                for (String usageId : usageIdsOld.split(",")) {
                    DictDataRespDTO usageValue = DictFrameworkUtils.getDictDataFromCache("order_item_usage", usageId);
                    if (usageValue != null) {
                        labelEnJoiner.add(usageValue.getLabelEn());
                        labelJoiner.add(usageValue.getLabel());
                    }
                }
                infoVO.setOrgValue(I18nMessage.getLang() == 0 ? labelJoiner.toString() : labelEnJoiner.toString());
            } else {
                infoVO.setOrgValue("空");
            }

            if (StringUtils.isNotEmpty(usageIdsNew)) {
                StringJoiner labelEnJoiner = new StringJoiner(",");
                StringJoiner labelJoiner = new StringJoiner(",");
                for (String usageId : usageIdsNew.split(",")) {
                    DictDataRespDTO usageValue = DictFrameworkUtils.getDictDataFromCache("order_item_usage", usageId);
                    if (usageValue != null) {
                        labelEnJoiner.add(usageValue.getLabelEn());
                        labelJoiner.add(usageValue.getLabel());
                    }
                }
                infoVO.setNewValue(I18nMessage.getLang() == 0 ? labelJoiner.toString() : labelEnJoiner.toString());
            } else {
                infoVO.setNewValue("空");
            }
            applyInfoList.add(infoVO);
        }

    }


    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void updateApplyCallback(String bizId, Integer result) {

//        OrderWarehouseApprovalDO orderWarehouseApprovalDO = orderWarehouseApprovalService.selectOne(OrderWarehouseApprovalTypeEnum.WAREHOUSE_IN_UPDATE.getValue(), Long.parseLong(bizId));
        OrderWarehouseApprovalDO orderWarehouseApprovalDO =
                orderWarehouseApprovalService.getById(bizId);

        // 更新审批单状态
        orderWarehouseApprovalService.callbackUpdate(orderWarehouseApprovalDO,
                result);

        long orderId = Long.parseLong(orderWarehouseApprovalDO.getOrderIds());
        String processingResults = orderWarehouseApprovalDO.getProcessingResults();

        // 通过
        if (ApprovalResultStatusEnum.pass.getValue().equals(result)) {
            // 将老的信息更新成新的信息
            Long orderItemId = orderWarehouseApprovalDO.getOrderItemId();
            OrderItemDO orderItemDO = orderItemService.getById(orderItemId);
            OrderDO orderDO = orderService.getById(orderId);
            BigDecimal sumVolumeBeforeUpdate = orderDO.getSumVolume();
            BigDecimal sumWeightBeforeUpdate = orderDO.getSumWeight();

            // 验证是否不可接受货物
            this.validateProdAttrAccess(orderItemDO.getProdId(),
                    orderDO.getOrderNo());

            // 通过orderItemId查询db中的 orderWarehouseInDO
            List<OrderWarehouseInDO> orderWarehouseInListOld =
                    orderWarehouseInMapper
                            .selectList(new LambdaQueryWrapperX<OrderWarehouseInDO>().eq(OrderWarehouseInDO::getOrderId, orderId)
                                    .eq(OrderWarehouseInDO::getOrderItemId, orderItemId));

            String details = orderWarehouseApprovalDO.getDetails();
            if (StringUtils.isNotEmpty(details)) {
                OrderWarehouseInUpdateApplyReqVO updateReqVO =
                        JSON.parseObject(details, OrderWarehouseInUpdateApplyReqVO.class);
                // 先更新入仓
                List<OrderWarehouseInItemDto> orderWarehouseInItemDtoListNew =
                        updateReqVO.getOrderWarehouseInUpdateItemDoList();

                ZhongPaoBestVO zhongPaoBest = getZhongPaoBest(orderDO);
                BigDecimal zhongEdge = zhongPaoBest != null ? zhongPaoBest.getZhongEdge() : null;
                BigDecimal paoEdge = zhongPaoBest != null ? zhongPaoBest.getPaoEdge() : null;


                if (CollectionUtil.isNotEmpty(orderWarehouseInItemDtoListNew)) {

                    // 2023-04-20 1.入仓修改可以添加入仓记录，添加审核通过后，入仓时间为提交入仓的系统时间，无需选择入仓时间。
                    Date inTime = orderWarehouseApprovalDO.getCreateTime();

                    // 1、新增 （只有新增的可能有储位，修改储位是直接调用修改接口的。）
                    List<OrderWarehouseInItemDto> addList =
                            orderWarehouseInItemDtoListNew.stream().filter(t -> t.getId() == null).collect(Collectors.toList());
                    if (CollectionUtil.isNotEmpty(addList)) {
                        for (OrderWarehouseInItemDto orderWarehouseInItemDto : addList) {

                            OrderWarehouseInDO orderWarehouseInDO = convertOrderWarehouseInItemDo(orderDO, orderItemId, zhongPaoBest, zhongEdge, paoEdge, orderWarehouseInItemDto, inTime);
                            orderWarehouseInMapper.insert(orderWarehouseInDO);

                            // 保存储位
                            List<OrderLocationCreateReqVO> orderLocationCreateReqVOList = orderWarehouseInItemDto.getOrderLocationCreateReqVOList();
                            if (CollectionUtil.isNotEmpty(orderLocationCreateReqVOList)) {
                                for (OrderLocationCreateReqVO orderLocationCreateReqVO : orderLocationCreateReqVOList) {
                                    // 设置入仓纪录id
                                    orderLocationCreateReqVO.setWarehouseInId(orderWarehouseInDO.getId());
                                    orderLocationService.createOrderLocation(orderLocationCreateReqVO);
                                }
                            }
                        }
                    }

                    // 2、更新 //2023-04-20 入仓修改若修改已有入仓记录，
                    // 有改动（储位或其他信息修改）修改入仓记录的最新操作时间，
                    // 不修改入仓时间，不修改未发生变化的入仓记录的入仓时间和最新操作时间。
                    if (CollectionUtil.isNotEmpty(orderWarehouseInItemDtoListNew)) {

                        //更新的
                        List<OrderWarehouseInItemDto> orderWarehouseInItemDtoListUpdate =
                                orderWarehouseInItemDtoListNew.stream().filter(t -> t.getId() != null
                                        && orderWarehouseInListOld.stream().anyMatch(old -> old.getId().equals(t.getId()))).collect(Collectors.toList());

                        if (CollectionUtil.isNotEmpty(orderWarehouseInItemDtoListUpdate)) {

                            for (OrderWarehouseInItemDto itemDtoNew :
                                    orderWarehouseInItemDtoListUpdate) {

                                OrderWarehouseInDO orderWarehouseInDONew =
                                        convertOrderWarehouseInItemDo(orderDO, orderItemId, zhongPaoBest, zhongEdge, paoEdge, itemDtoNew, inTime);

                                // 判断有无变化
                                OrderWarehouseInDO old = orderWarehouseInMapper.selectById(itemDtoNew.getId());
                                List<ApplyInfoVO> applyInfoVOListTmp = new ArrayList<>();
                                compareOrderWarehouseInField("", Arrays.asList(old), Arrays.asList(itemDtoNew), applyInfoVOListTmp);
                                // 有变化才更新
                                if (CollectionUtil.isNotEmpty(applyInfoVOListTmp)) {
                                    orderWarehouseInMapper.updateById(orderWarehouseInDONew);

                                    applyInfoVOListTmp.clear();
                                } else {
                                    //20230821 fix: #4304 订单完成入仓后修改商品名称未更新最后入仓时间
                                    Long warehouseInId = orderWarehouseInDONew.getId();
                                    this.update(new LambdaUpdateWrapper<OrderWarehouseInDO>()
                                            .set(OrderWarehouseInDO::getUpdater,
                                                    WebFrameworkUtils.getLoginUserId() + "")
                                            .set(OrderWarehouseInDO::getUpdateTime, new Date())
                                            .eq(OrderWarehouseInDO::getId, warehouseInId));
                                }
                            }
                        }

                        // 3、删除
                        List<Long> deleteIds = orderWarehouseInListOld.stream()
                                .filter(old -> orderWarehouseInItemDtoListNew.stream().noneMatch(n -> old.getId().equals(n.getId()))).map(OrderWarehouseInDO::getId).collect(Collectors.toList());
                        if (CollectionUtil.isNotEmpty(deleteIds)) {
                            orderWarehouseInMapper.deleteBatchIds(deleteIds);
                        }
                    }
                }

                // 3、删除
                else {
                    List<Long> deleteIds =
                            orderWarehouseInListOld.stream().map(OrderWarehouseInDO::getId).collect(Collectors.toList());
                    orderWarehouseInMapper.deleteBatchIds(deleteIds);

                    //根据订单ID删除储位
                    orderLocationService.deleteIfPresent(orderId, null, null);
                }

                orderItemDO.setNum(updateReqVO.getNum());
                orderItemDO.setVolume(updateReqVO.getVolume());
                orderItemDO.setWeight(updateReqVO.getWeight());
                orderItemDO.setMaterial(updateReqVO.getMaterial());
                orderItemDO.setWarehouseInProdAttrIds(updateReqVO.getWarehouseInProdAttrIds());
                orderItemDO.setBrand(Objects.isNull(updateReqVO.getBrand()) ? 0L : updateReqVO.getBrand());// 使用的跟新方法不会将null值更新到数据库，所以给默认值0

                orderItemDO.setProdType(updateReqVO.getProdType());
                orderItemDO.setProdTitleZh(updateReqVO.getProdTitleZh());
                orderItemDO.setProdTitleEn(updateReqVO.getProdTitleEn());

                orderItemDO.setUsageIds(StringUtils.isEmpty(updateReqVO.getUsageIds()) ? "" : updateReqVO.getUsageIds());

                Long prodIdNew = updateReqVO.getProdId();

                // 更新订单的和订单项的入仓信息
                updateOrderAndOrderItemWarehouseIn(orderId, orderItemDO.getProdId(), prodIdNew, CollectionUtil.newArrayList(orderItemDO), zhongPaoBest);

                //入仓特性为空时 需要更新入仓特性为空
                if (StringUtils.isEmpty(updateReqVO.getWarehouseInProdAttrIds())) {
                    orderItemService.update(null, new LambdaUpdateWrapper<OrderItemDO>()
                            .set(OrderItemDO::getWarehouseInProdAttrIds, null)
                            .eq(OrderItemDO::getOrderItemId, orderItemDO.getOrderItemId()));
                }

                // 影像
                orderWarehousePictureService.createWarehousePictureBatch(updateReqVO.getPictureUrls(), 5, orderItemId);

                // 入仓修改审批通过，添加订单动态日志
                orderBusinessService.addOrderTimeLog(orderDO.getStatus(), orderDO, 8);


                orderDO = orderQueryService.getOrderById(orderId);
                //更新订单统计数据
                List<OrderWarehouseInDO> orderWarehouseInDOList = orderWarehouseInMapper.selectList(OrderWarehouseInDO::getOrderId, orderDO.getOrderId());
                // 入仓总数量、体积、重量
                int numSum = orderWarehouseInDOList.stream().filter(t -> t.getCartonsNum() != null).mapToInt(OrderWarehouseInDO::getCartonsNum).sum();
                int quantitySum = orderWarehouseInDOList.stream().filter(t -> t.getQuantityAll() != null).mapToInt(OrderWarehouseInDO::getQuantityAll).sum();
                BigDecimal weightSum = orderWarehouseInDOList.stream().map(OrderWarehouseInDO::getWeight).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal volumeSum = orderWarehouseInDOList.stream().map(OrderWarehouseInDO::getVolume).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);

                // 需要跟isUpdateCallback组合使用
                boolean isOrderSumVolumeNoChange = volumeSum.compareTo(sumVolumeBeforeUpdate) == 0;
                boolean isOrderSumWeightNoChange = weightSum.compareTo(sumWeightBeforeUpdate) == 0;

                orderDO.setSumQuantity(quantitySum);
                orderDO.setSumWeight(weightSum);
                orderDO.setSumVolume(volumeSum);
                orderDO.setSumNum(numSum);
                orderService.updateById(orderDO);

                // 更新订单状态 入仓修改-已通过
                Integer auditType = OrderApprovalTypeResultEnum.warehouse_update_pass.getType();

                Integer inWarehouseState = null;
                //非清关和出货的入仓修改，执行正常入仓修改流程
                if (!Objects.equals(OrderStatusEnum.CLEARED.getValue(), orderDO.getStatus())
                        && !Objects.equals(OrderStatusEnum.INSTALLED_CABINET.getValue(), orderDO.getStatus())
                        && !Objects.equals(OrderStatusEnum.SHIPMENT.getValue(), orderDO.getStatus())) {

                    inWarehouseState = OrderWarehouseInStatusEnum.warehouse_finished.getValue();
                    orderService.updateStatus(orderId, null, null, null,
                            inWarehouseState, null, 0, OrderApprovalTypeResultEnum.typeAndResultOf(auditType, result).getDesc(), false);

                    // 重新入仓，处理一些异常
                    try {

                        OrderWarehouseInFinishReqVO finishReqVO = new OrderWarehouseInFinishReqVO();
                        finishReqVO.setOrderId(orderId);
                        boolean splitOrder = orderQueryService.isSplitOrderChildren(orderDO);
                        // 拆单的订单不需要修改箱号，非拆单订单的要入仓修改要修改箱号
                        if (splitOrder) {
                            finishReqVO.setUpdateLabel(false);
                        }
                        finishReqVO.setIsUpdateCallback(true);

                        finishReqVO.setIsSumVolumeNoChange(isOrderSumVolumeNoChange);
                        finishReqVO.setIsSumWeightNoChange(isOrderSumWeightNoChange);

                        finishReqVO.setUpdateCustomer(false);
                        finishReqVO.setUpdateWarehouseInUrl(false);
                        finishReqVO.setSendMsg(false);
                        finishReqVO.setIsAddOrderOperateLog(false);

                        this.finishWarehouseIn(finishReqVO);
                    } catch (Exception e) {
                        log.error("入仓修改通过后重新入仓发生异常", e);
                    }

                } else {

                    //清关和出货的入仓修改，只需要更新审核状态，不更新订单主状态
                    orderService.updateStatus(orderId, null, null, null,
                            null, null, 0, OrderApprovalTypeResultEnum.typeAndResultOf(auditType, result).getDesc(), false);
                }

                // 添加仓库操作日志
                orderBusinessService.addOrderOperateLog(orderId, "仓库操作", "货物入仓修改已通过", updateReqVO.getApplyInfoVOList());
            }

        } else if (ApprovalResultStatusEnum.reject.getValue().equals(result)) {

            // 更新订单状态 入仓修改-拒绝
            Integer auditType = OrderApprovalTypeResultEnum.warehouse_update_reject.getType();
            OrderDO orderDO = orderQueryService.getOrderById(orderId);
            Integer inWarehouseState = null;
            //清关和出货的入仓修改，只需要更新审核状态，不更新订单主状态。  其他更新为完成入仓状态
            if (!Objects.equals(OrderStatusEnum.CLEARED.getValue(), orderDO.getStatus())
                    && !Objects.equals(OrderStatusEnum.INSTALLED_CABINET.getValue(), orderDO.getStatus())
                    && !Objects.equals(OrderStatusEnum.SHIPMENT.getValue(), orderDO.getStatus())) {
                inWarehouseState = OrderWarehouseInStatusEnum.warehouse_finished.getValue();
            }
            orderService.updateStatus(orderId, null, null, null,
                    inWarehouseState, null, 0, OrderApprovalTypeResultEnum.typeAndResultOf(auditType, result).getDesc(), false);

            String details = orderWarehouseApprovalDO.getDetails();
            if (StringUtils.isNotEmpty(details)) {
                OrderWarehouseInUpdateApplyReqVO updateReqVO = JSON.parseObject(details, OrderWarehouseInUpdateApplyReqVO.class);
                // 添加仓库操作日志
                orderBusinessService.addOrderOperateLog(orderId, "仓库操作", "货物入仓修改申请已拒绝", updateReqVO.getApplyInfoVOList());
            }

        } else if (ApprovalResultStatusEnum.cancel.getValue().equals(result)) {
            // 更新订单状态 入仓修改-取消
            Integer auditType = OrderApprovalTypeResultEnum.warehouse_update_cancel.getType();

            OrderDO orderDO = orderQueryService.getOrderById(orderId);
            Integer inWarehouseState = null;
            if (!Objects.equals(OrderStatusEnum.CLEARED.getValue(), orderDO.getStatus())
                    && !Objects.equals(OrderStatusEnum.INSTALLED_CABINET.getValue(), orderDO.getStatus())
                    && !Objects.equals(OrderStatusEnum.SHIPMENT.getValue(), orderDO.getStatus())) {
                inWarehouseState = OrderWarehouseInStatusEnum.warehouse_finished.getValue();
            }
            //清关和出货的入仓修改，只需要更新审核状态，不更新订单主状态。  其他更新为完成入仓状态
            orderService.updateStatus(orderId, null, null, null,
                    inWarehouseState, null, 0, OrderApprovalTypeResultEnum.typeAndResultOf(auditType, result).getDesc(), false);

            String details = orderWarehouseApprovalDO.getDetails();
            if (StringUtils.isNotEmpty(details)) {
                OrderWarehouseInUpdateApplyReqVO updateReqVO = JSON.parseObject(details, OrderWarehouseInUpdateApplyReqVO.class);
                // 添加仓库操作日志
                orderBusinessService.addOrderOperateLog(orderId, "仓库操作", "货物入仓修改申请已取消", updateReqVO.getApplyInfoVOList());
            }
        }
    }

    @Override
    public void updateOrderAndOrderItemWarehouseIn(Long orderId, Long prodIdOld, Long prodIdNew, List<OrderItemDO> orderItemDOList, ZhongPaoBestVO zhongPaoBest) {

        if (zhongPaoBest == null) {
            OrderDO orderDO = orderQueryService.getOrderById(orderId);
            zhongPaoBest = getZhongPaoBest(orderDO);
        }

        if (CollectionUtil.isNotEmpty(orderItemDOList)) {

            for (OrderItemDO orderItemDO : orderItemDOList) {
                // 修改了品名 需要删除未处理的预付异常和未处理的应收单
                Boolean changeProd = !Objects.equals(prodIdNew, prodIdOld);
                if (changeProd) {
                    orderItemDO.setIsPriced(Boolean.FALSE);// 修改品名需要重新定价
                    deletePendingOrderExceptionAfterUpdateProduct(orderId, orderItemDO.getOrderItemId());
                }
                // 更新orderItem
                orderItemDO.setProdId(prodIdNew);

                GetFeeTypeProductBrandEmpowerRespVO feeTypeByOrder = getGetFeeTypeProductBrandEmpowerRespVO(orderId, prodIdNew, orderItemDO.getBrand());
                // 设置是否备案和收费模式
                if (feeTypeByOrder != null) {
                    if (orderItemDO.getBrandType() == null && StringUtils.isNotEmpty(feeTypeByOrder.getRecordMode())) {
                        orderItemDO.setBrandType(Integer.parseInt(feeTypeByOrder.getRecordMode()));
                    }
                    if (StringUtils.isNotEmpty(feeTypeByOrder.getFeeType())) {
                        orderItemDO.setFeeType(Integer.parseInt(feeTypeByOrder.getFeeType()));
                    }
                }

                // 查看所有的入仓数据
                List<OrderWarehouseInDO> orderWarehouseInDoListOld = orderWarehouseInMapper.selectList(new LambdaQueryWrapper<OrderWarehouseInDO>()
                        .eq(OrderWarehouseInDO::getOrderId, orderId)
                        .eq(OrderWarehouseInDO::getOrderItemId, orderItemDO.getOrderItemId()));

                // 设置orderItem属性
                WarehouseInInfoVO warehouseInInfoVO = this.orderItemSetWarehouseInInfoVO(orderItemDO, orderWarehouseInDoListOld);

                // 入仓中状态下 这时不处理订单的重泡货值 改为处理
                this.setOrderItemZhongPao(zhongPaoBest, orderItemDO, warehouseInInfoVO.getWeight(), warehouseInInfoVO.getVolume());
                orderItemDO.setItemStatus(warehouseInInfoVO.getDiffType());

                //处理已删除的商品特性
                orderItemDO.setProdAttrIds(productAttrService.delInvalidAttrIds(orderItemDO.getProdAttrIds()));
                orderItemDO.setWarehouseInProdAttrIds(productAttrService.delInvalidAttrIds(orderItemDO.getWarehouseInProdAttrIds()));

                // 更新订单项
                orderItemService.updateById(orderItemDO);
            }
        }
    }


    private void deletePendingOrderExceptionAfterUpdateProduct(long orderId, Long orderItemId) {
        // 未处理的预付异常
        List<OrderExceptionDO> pendingOrderPayExceptionList = orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderId, null, OrderExceptionEnum.ORDER_PAY_EXCEPTION.getKey());
        if (CollectionUtil.isNotEmpty(pendingOrderPayExceptionList)) {
            for (OrderExceptionDO orderExceptionDO : pendingOrderPayExceptionList) {
                orderExceptionService.deleteOrderException(orderExceptionDO.getId());
            }
        }
        // 未处理的品名关联异常
        List<OrderExceptionDO> pendingOrderItemIdExceptionList = orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderId, orderItemId, null);
        if (CollectionUtil.isNotEmpty(pendingOrderItemIdExceptionList)) {
            for (OrderExceptionDO orderExceptionDO : pendingOrderItemIdExceptionList) {
                orderExceptionService.deleteOrderException(orderExceptionDO.getId());
            }
        }
        //未处理的应收
        List<ReceivableDO> receivableDOList = receivableService.getReceivableList(new ReceivableQueryVO().setState(0).setOrderItemId(orderItemId));
        if (CollectionUtil.isNotEmpty(receivableDOList)) {
            for (ReceivableDO receivableDO : receivableDOList) {
                receivableService.deleteReceivable(receivableDO.getId());
            }
        }
    }

    private void collectLabelSet(long orderId, Set<Integer> labelSet) {

        List<OrderLabelDO> orderLabelOldList = orderLabelService.getLabelList(new OrderLabelQueryVO().setOrderId(orderId));
        if (CollectionUtil.isNotEmpty(orderLabelOldList)) {

            Long parentOrderId = orderLabelOldList.get(0).getParentOrderId();
            if (parentOrderId != null) {
                collectLabelSet(parentOrderId, labelSet);
            } else {
                for (OrderLabelDO orderLabelDO : orderLabelOldList) {
                    getLabelSet(labelSet, orderLabelDO.getStart(), orderLabelDO.getEnd());
                }
            }

        }
    }

    private void getLabelSet(Set<Integer> labelSet, Integer start2, Integer end2) {
        Integer start = start2;
        Integer end = end2;
        if (start.equals(end)) {
            labelSet.add(start);
        } else if (end > start) {
            for (int i = start; i <= end; i++) {
                labelSet.add(i);
            }
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteWarehouseInOrderItem(OrderWarehouseInRollbackOrderItemReqVO orderItemReqVo) {

        Boolean isPackagingRollback = orderItemReqVo.getIsPackagingRollback();

        Long orderId = orderItemReqVo.getOrderId();
        Long orderItemId = orderItemReqVo.getOrderItemId();

        OrderDO orderDO = orderService.getById(orderId);
        boolean isSplitOrder = orderQueryService.isSplitOrderChildren(orderDO);
        if (isSplitOrder) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.SPLIT_ORDER_CAN_NOT_ROLLBACK);
        }
        if (OrderStatusEnum.WAREHOUSE_ADJUSTMENT.getValue().equals(orderDO.getStatus())) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_WAREHOUSE_ADJUSTMENT_STATUS_NOT_ALLOWED_WAREHOUSE_IN);
        }

        // 核验是否有未处理审批单
        throwProcessingApproval(orderDO);

        OrderItemDO orderItem = orderItemService.getOrderItem(orderItemId);

        // 校验是否有已核销的应收单，如果有，则不能退仓
        // receivableService.verificationReceivableIsWriteOff(null, orderItemId);

        // 订单排单校验
        applicationContext.publishEvent(new BoxCheckOrderSchedulingEvent(orderId));

        if (isPackagingRollback) {
            // 更新前一次打包数据
            orderDO = this.updateOrderSumPrevPacked(orderId);
        }

        // 添加仓库操作纪录
        orderBusinessService.addOrderOperateLog(orderId, "仓库操作", "货物退仓-品名[" + orderItem.getProdTitleZh() + "]", "");

        // 若是非填单项，则删除此订单项
        if (Boolean.TRUE.equals(orderItem.getIsWarehouseInAdd())) {
            orderItemService.deleteOrderItem(orderItemId);

            // 删除此商品项时，需要删除此订单下与此商品项对应的未处理异常
            List<OrderExceptionDO> pendingOrderExceptionList = orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderId, orderItemId, null);
            if (CollectionUtil.isNotEmpty(pendingOrderExceptionList)) {
                pendingOrderExceptionList.stream().forEach(orderExceptionDO -> {
                    orderExceptionService.deleteOrderException(orderExceptionDO.getId());
                });
            }
        } else {
            // 重置OrderItem记录的入仓信息
            orderItemService.updateOrderItemWarehouseInInfoToNull(orderId, orderItemId);
        }

        // 备货时退仓，不能删除这些数据，因为要查看备货历史
        if (!isPackagingRollback) {
            // 删除储位
            orderLocationService.deleteIfPresent(orderId, orderItemId, null);

            // 删除入仓图片
            orderWarehousePictureService.deleteOrderItemWarehousePicture(orderItemId);
        }

        // 删除应收
        receivableService.deleteReceivableByOrderItemId(orderItemId);

        // 删除
        orderWarehouseInMapper.delete(new LambdaQueryWrapperX<OrderWarehouseInDO>().eq(OrderWarehouseInDO::getOrderId, orderId)
                .eq(OrderWarehouseInDO::getOrderItemId, orderItemId));

        // 删除标签
        orderLabelService.deleteLabelByOrderId(orderId);
        // 再重新生成标签
        List<OrderWarehouseInDO> orderWarehouseInDOList = orderWarehouseInMapper.selectList(OrderWarehouseInDO::getOrderId, orderDO.getOrderId());
        int numSum2 = orderWarehouseInDOList.stream().filter(t -> t.getCartonsNum() != null).mapToInt(OrderWarehouseInDO::getCartonsNum).sum();
        if (numSum2 > 0) {
            List<OrderLabelDto> labelDtoList = CollectionUtil.newArrayList(new OrderLabelDto(null, 1, numSum2));
            orderLabelService.saveOrUpdateLabel(SaveOrUpdateOrderLabelDto.builder().orderId(orderId).orderLabelDtoList(labelDtoList).isAddLog(false).build());
        }

        // 更新订单入仓信息
        OrderWarehouseInVO orderWarehouseInVO = new OrderWarehouseInVO();
        orderWarehouseInVO.setOrderId(orderId);
        orderService.orderInWarehouse(orderWarehouseInVO);


        // 订单当前订单有无入仓信息
        Long count = orderWarehouseInMapper.selectCount(new LambdaQueryWrapperX<OrderWarehouseInDO>().eq(OrderWarehouseInDO::getOrderId, orderId));
        if (count == 0) {

            int abnormalState = 0;
            List<OrderExceptionDO> pendingOrderExceptionList = orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderId, null, null);
            if (CollectionUtil.isNotEmpty(pendingOrderExceptionList)) {

                // 同时存在未报价异常和清关费未报价异常，则使用多个异常
                if (pendingOrderExceptionList.stream().anyMatch(t -> OrderExceptionEnum.ORDER_NO_QUOTE_EXCEPTION.getKey().equals(t.getOrderExceptionType()))
                        && pendingOrderExceptionList.stream().anyMatch(t -> OrderExceptionEnum.CUSTOMS_FEE_NOT_QUOTE_EXCEPTION.getKey().equals(t.getOrderExceptionType()))) {
                    abnormalState = OrderAbnormalStateEnum.MULTIPLE_EXCEPTION.getValue();
                }
                // 未处理的未报价异常存在，则订单的异常使用未报价异常
                else if (pendingOrderExceptionList.stream().anyMatch(t -> OrderExceptionEnum.ORDER_NO_QUOTE_EXCEPTION.getKey().equals(t.getOrderExceptionType()))) {
                    abnormalState = OrderAbnormalStateEnum.ORDER_NO_QUOTE_EXCEPTION.getValue();
                }
                // 未处理的清关费未报价异常，则订单的异常使用清关费未报价异常
                else if (pendingOrderExceptionList.stream().anyMatch(t -> OrderExceptionEnum.CUSTOMS_FEE_NOT_QUOTE_EXCEPTION.getKey().equals(t.getOrderExceptionType()))) {
                    abnormalState = OrderAbnormalStateEnum.CUSTOMS_FEE_NOT_QUOTE_EXCEPTION.getValue();
                }

                // 删除除未报价异常外的其他异常
                pendingOrderExceptionList.stream().filter(t -> !OrderExceptionEnum.ORDER_NO_QUOTE_EXCEPTION.getKey().equals(t.getOrderExceptionType())
                        && !OrderExceptionEnum.CUSTOMS_FEE_NOT_QUOTE_EXCEPTION.getKey().equals(t.getOrderExceptionType())).forEach(orderExceptionDO -> {
                    orderExceptionService.deleteOrderException(orderExceptionDO.getId());
                });
            }

            // 无入仓时删除order的所有应收(单品退仓操作后无入仓时，只删除订单计费自动生成的应收单，自定义的费用申请和特需费用不用删除)
            receivableService.deleteReceivableByOrderIdAndFeeSource(orderId, 1);

            // 更新订单状态 - 已下单
            if (!isPackagingRollback) {
                orderService.updateStatus(orderId, null, OrderStatusEnum.ORDER_PLACED.getValue(), abnormalState, 0, 0, null, null, false);
            }
        } else {
            // 更新订单状态 - 入库中
            if (!isPackagingRollback) {
                orderService.updateStatus(orderId, null, OrderStatusEnum.WAREHOUSING.getValue(), null, OrderWarehouseInStatusEnum.warehousing.getValue(), null, null, null, false);
            }
        }
    }

    private void validateOrderWarehouseInExists(Long id) {
        if (orderWarehouseInMapper.selectById(id) == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_WAREHOUSE_IN_NOT_EXISTS);
        }
    }


    @Override
    public List<OrderWarehouseInBackVO> getOrderWarehouseInList(Long orderId) {

        // 根据订单id获取入库详情
        OrderDO orderDO = orderService.getById(orderId);
        if (orderDO == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_NOT_EXISTS);
        }

        List<OrderItemDO> orderItemDOList =
                orderItemService.list(new LambdaQueryWrapper<OrderItemDO>()
                        .eq(OrderItemDO::getOrderId, orderId).orderByAsc(OrderItemDO::getOrderItemId));
        List<OrderWarehouseInDO> orderWarehouseInDOList =
                orderWarehouseInMapper.selectList(
                        new LambdaQueryWrapper<OrderWarehouseInDO>()
                                .eq(OrderWarehouseInDO::getOrderId,
                                        orderId).orderByAsc(OrderWarehouseInDO::getId));

        //订单仓位
        List<OrderLocationDO> orderLocationListByOrderId =
                orderLocationService.getOrderLocationListByOrderId(orderId);

        if (CollectionUtil.isNotEmpty(orderItemDOList)) {
            return orderItemDOList.stream().map(orderItemDO -> {
                return getOrderWarehouseInBackVO(orderItemDO,
                        orderWarehouseInDOList,
                        orderLocationListByOrderId);
            }).collect(Collectors.toList());
        }

        return null;
    }

    @Override
    public OrderWarehouseInBackVO getOrderWarehouseInListDeleted(Long orderId, Long orderItemId) {

        OrderItemDO orderItemDO = orderItemService.getById(orderItemId);
        List<OrderWarehouseInDO> orderWarehouseInDOList = orderWarehouseInMapper.getDeletedList(orderId, orderItemId);

        List<OrderLocationDO> orderLocationListByOrderId = orderLocationService.getOrderLocationListByOrderId(orderId);

        if (orderItemDO != null) {
            return getOrderWarehouseInBackVO(orderItemDO, orderWarehouseInDOList, orderLocationListByOrderId);
        }

        return null;
    }

    private OrderWarehouseInBackVO getOrderWarehouseInBackVO(
            OrderItemDO orderItemDO,
            List<OrderWarehouseInDO> orderWarehouseInDOList,
            List<OrderLocationDO> orderLocationListByOrderId) {

        OrderWarehouseInBackVO orderWarehouseInBackVO =
                OrderItemConvert.INSTANCE.convertToOrderWarehouseInBackVo(orderItemDO);

        List<OrderWarehouseInBackItemDo> orderWarehouseInBackItemDoList =
                orderWarehouseInDOList.stream()
                        .filter(t -> t.getOrderItemId().equals(orderItemDO.getOrderItemId()))
                        .sorted(Comparator.comparing(OrderWarehouseInDO::getInTime))
                        .map(orderWarehouseInDO -> {
                            OrderWarehouseInBackItemDo orderWarehouseInBackItemDo =
                                    OrderWarehouseInConvert.INSTANCE.convert2(orderWarehouseInDO);

                            List<OrderLocationBackVO> orderLocationBackVOS =
                                    orderLocationService.filterByWarehouseIn(orderLocationListByOrderId, orderWarehouseInDO);
                            orderWarehouseInBackItemDo.setOrderLocationBackVOList(orderLocationBackVOS);
                            String orderLocationStr4Merge = orderLocationBackVOS.stream().map(item -> {
                                return (item.getAreaName() == null ? "" : item.getAreaName()) + (item.getLocationName() == null ? "" : item.getLocationName());
                            }).collect(Collectors.joining(","));
                            orderWarehouseInBackItemDo.setOrderLocationStr4Merge(orderLocationStr4Merge);

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

        orderWarehouseInBackItemDoList =
                orderWarehouseInBackItemDoList.stream().sorted(Comparator.comparing(OrderWarehouseInBackItemDo::getInTime).thenComparing(OrderWarehouseInBackItemDo::getUnit).thenComparing(OrderWarehouseInBackItemDo::getOrderLocationStr4Merge)).collect(Collectors.toList());

        // 设置件数差
        BigDecimal num = orderWarehouseInBackVO.getNum();
        int inSum = orderWarehouseInBackItemDoList.stream().mapToInt(OrderWarehouseInBackItemDo::getCartonsNum).sum();
        if (num != null) {
            Integer diffType;
            int diff = inSum - num.intValue();
            diffType = getDiffType(diff);
            orderWarehouseInBackVO.setDiffType(diffType);
            orderWarehouseInBackVO.setCartonsNumDiff(Math.abs(diff));
        }

        orderWarehouseInBackVO.setOrderWarehouseInBackItemDoList(
                orderWarehouseInBackItemDoList);

        // 设置入仓影像
        List<String> pictureUrls =
                orderWarehousePictureService.getWarehousePictureUrlList(5,
                        orderItemDO.getOrderItemId());
        if (CollectionUtil.isNotEmpty(pictureUrls)) {
            orderWarehouseInBackVO.setPictureUrls(pictureUrls);
        }

        return orderWarehouseInBackVO;
    }

    @Override
    public OrderWarehouseInBackVO getOrderWarehouseInBackVO(Long orderId, Long orderItemId) {
        List<OrderWarehouseInBackVO> orderWarehouseInList = this.getOrderWarehouseInList(orderId);

        if (CollectionUtil.isNotEmpty(orderWarehouseInList)) {
            return orderWarehouseInList.stream().filter(t -> t.getOrderItemId().equals(orderItemId)).findFirst().orElse(null);
        }
        return null;
    }

    @Override
    public List<OrderWarehouseInDO> getOrderWarehouseInList(Collection<Long> ids) {
        return orderWarehouseInMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<OrderWarehouseInDO> getOrderWarehouseInPage(OrderWarehouseInQueryVO query, PageVO page) {
        return orderWarehouseInMapper.selectPage(page, query);
    }

    @Override
    public List<OrderWarehouseInDO> getOrderWarehouseInList(OrderWarehouseInQueryVO query) {
        return orderWarehouseInMapper.selectList(query);
    }

    @Override
    public OrderWarehouseInDO getFirstOneOrderWarehouseInByProdId(Long orderId, Long prodId) {
        return orderWarehouseInMapper.getFirstOneOrderWarehouseInByProdId(orderId, prodId);
    }


    @Override
    public OrderWarehouseInDO getMinOrderWarehouseInByOrderItemId(Long orderItemId) {
        return orderWarehouseInMapper.selectOne(new LambdaQueryWrapperX<OrderWarehouseInDO>().eq(OrderWarehouseInDO::getOrderItemId, orderItemId).orderByAsc(OrderWarehouseInDO::getInTime).last("limit 1"));
    }

    private void setOrderItemBase(OrderWarehouseInCreateReqVO createReqVO, OrderItemDO orderItemDO) {
        // 设置orderItem基础参数
        if (createReqVO.getProdId() != null && createReqVO.getProdId() != 0) {
            orderItemDO.setProdId(createReqVO.getProdId());
        }
        if (createReqVO.getProdType() != null && createReqVO.getProdType() != 0) {
            orderItemDO.setProdType(createReqVO.getProdType());
        }

        if (StringUtils.isNotEmpty(createReqVO.getProdTitleEn())) {
            orderItemDO.setProdTitleEn(createReqVO.getProdTitleEn());
        }

        if (StringUtils.isNotEmpty(createReqVO.getProdTitleZh())) {
            orderItemDO.setProdTitleZh(createReqVO.getProdTitleZh());
        }

        if (createReqVO.getBrand() != null) {
            orderItemDO.setBrand(createReqVO.getBrand());
        }

        Long prodId = orderItemDO.getProdId();
        Long brand = orderItemDO.getBrand();
        Long orderId = orderItemDO.getOrderId();

        GetFeeTypeProductBrandEmpowerRespVO feeTypeByOrder = getGetFeeTypeProductBrandEmpowerRespVO(orderId, prodId, brand);
        // 设置是否备案和收费模式
        if (feeTypeByOrder != null) {
            // 当订单项的brandType为null时才设置。（说明是新品入仓）
            if (orderItemDO.getBrandType() == null && StringUtils.isNotEmpty(feeTypeByOrder.getRecordMode())) {
                orderItemDO.setBrandType(Integer.parseInt(feeTypeByOrder.getRecordMode()));
            }
            if (StringUtils.isNotEmpty(feeTypeByOrder.getFeeType())) {
                orderItemDO.setFeeType(Integer.parseInt(feeTypeByOrder.getFeeType()));

                // 反向设置，后面要使用。 修复入仓提交时由于客户端未及时获取到feeType而未传递过来导致比较时出现异常的bug
                createReqVO.setFeeType(orderItemDO.getFeeType());
            }
        }

        if (StringUtils.isNotEmpty(createReqVO.getMaterial())) {
            orderItemDO.setMaterial(createReqVO.getMaterial());
        }

        //处理已删除的商品特性
        orderItemDO.setProdAttrIds(productAttrService.delInvalidAttrIds(orderItemDO.getProdAttrIds()));
        orderItemDO.setWarehouseInProdAttrIds(productAttrService.delInvalidAttrIds(createReqVO.getWarehouseInProdAttrIds()));

        //用途
        if (StringUtils.isNotEmpty(createReqVO.getUsageIds())) {
            orderItemDO.setUsageIds(createReqVO.getUsageIds());
        }
    }

    private GetFeeTypeProductBrandEmpowerRespVO getGetFeeTypeProductBrandEmpowerRespVO(Long orderId, Long prodId, Long brand) {
        GetFeeTypeProductBrandEmpowerRespVO feeTypeByOrder = null;
        if (prodId != null && prodId != 0 && brand != null) {
            GetFeeTypeProductBrandByOrderEmpowerReqVO getFeeTypeProductBrandByOrderEmpowerReqVO = new GetFeeTypeProductBrandByOrderEmpowerReqVO();
            getFeeTypeProductBrandByOrderEmpowerReqVO.setProductId(prodId);
            getFeeTypeProductBrandByOrderEmpowerReqVO.setBrandId(brand);
            getFeeTypeProductBrandByOrderEmpowerReqVO.setOrderId(orderId);
            feeTypeByOrder = productBrandEmpowerService.getFeeTypeByOrder(getFeeTypeProductBrandByOrderEmpowerReqVO);
        }
        return feeTypeByOrder;
    }

    /**
     * 入仓时添加新品，需要将新品添加进订单项中
     *
     * @param createReqVO 入仓请求
     * @param orderDO     订单
     * @param unit        单位
     * @return 新生成的订单项
     */
    private OrderItemDO createNewOrderItem(OrderWarehouseInCreateReqVO createReqVO, OrderDO orderDO, String unit) {
        OrderItemDO orderItemDO = new OrderItemDO();
        orderItemDO.setOrderId(orderDO.getOrderId());
        orderItemDO.setOrderNo(orderDO.getOrderNo());

        // 非下单货物对应的订单信息
        orderItemDO.setTransportId(orderDO.getTransportId());
        orderItemDO.setLineId(orderDO.getLineId());
        orderItemDO.setChannelId(orderDO.getChannelId());

        // 非下单货物无数量和单位
        orderItemDO.setNum(0);
        orderItemDO.setUnit(Objects.isNull(unit) ? "1" : unit);
        orderItemDO.setQuantity(0);
        orderItemDO.setVolume(BigDecimal.ZERO);
        orderItemDO.setWeight(BigDecimal.ZERO);

        // 设置为非下单货物
        orderItemDO.setIsWarehouseInAdd(true);
        // 设置orderItem基础参数
        setOrderItemBase(createReqVO, orderItemDO);

        // 保存
        orderItemService.save(orderItemDO);
        return orderItemDO;
    }

    private OrderExceptionCreateReqVO genOrderException(Long orderId, Long orderItemId, OrderDO
            orderDO, OrderExceptionEnum orderSuperfluousBoxException, String descZh, String
                                                                descEn, List<String> exceptionUrls, String additionalJson) {
        OrderExceptionCreateReqVO orderExceptionCreateReqVO = new OrderExceptionCreateReqVO();
        orderExceptionCreateReqVO.setOrderId(orderId);
        orderExceptionCreateReqVO.setOrderItemId(orderItemId);
        orderExceptionCreateReqVO.setOrderNumber(orderDO.getOrderNo());
        orderExceptionCreateReqVO.setOrderExceptionType(orderSuperfluousBoxException.getKey());
        if (CollectionUtil.isNotEmpty(exceptionUrls)) {
            orderExceptionCreateReqVO.setOrderExceptionAttr(CollectionUtil.join(exceptionUrls, ","));
        }
        orderExceptionCreateReqVO.setOrderExceptionDescVO(OrderExceptionDescVO.builder().descZh(descZh).descEn(descEn).build());
        orderExceptionCreateReqVO.setAdditionalJson(additionalJson);
        return orderExceptionCreateReqVO;
    }

    private OrderExceptionCreateReqVO genOrderException(Long orderId, Long orderItemId, OrderDO
            orderDO, OrderExceptionEnum orderSuperfluousBoxException, String descZh, String
                                                                descEn, List<String> exceptionUrls) {
        return this.genOrderException(orderId, orderItemId, orderDO, orderSuperfluousBoxException, descZh, descEn, exceptionUrls, null);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void rollbackApply(OrderWarehouseInRollbackApplyReqVO orderWarehouseInRollbackApplyReqVO, Long adminId, Boolean isFromUserClient) {

        Long orderId = orderWarehouseInRollbackApplyReqVO.getOrderId();
        OrderDO orderDO = orderService.getById(orderId);
        if (orderDO == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_NOT_EXISTS);
        }
        boolean isSplitOrder = orderQueryService.isSplitOrderChildren(orderDO);
        if (isSplitOrder) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.SPLIT_ORDER_CAN_NOT_ROLLBACK);
        }
        if (OrderStatusEnum.WAREHOUSE_ADJUSTMENT.getValue().equals(orderDO.getStatus())) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_WAREHOUSE_ADJUSTMENT_STATUS_NOT_ALLOWED_WAREHOUSE_IN);
        }
        // 校验是否有已核销的应收单，如果有，则不能退仓
        // receivableService.verificationReceivableIsWriteOff(orderId, null);

        // 订单排单校验
        applicationContext.publishEvent(new BoxCheckOrderSchedulingEvent(orderId));

        // 判断是否有未处理的审核单
        orderQueryService.throwProcessingApproval(orderId);

        String orderNo = orderWarehouseInRollbackApplyReqVO.getOrderNo();
        OrderWarehouseApprovalDO orderWarehouseApprovalDO = OrderWarehouseApprovalDO.builder()
                .orderIds(orderId.toString())
                .orderNo(orderNo)
                .type(OrderWarehouseApprovalTypeEnum.WAREHOUSE_IN_TO_RETURN.getValue())
                .followUpAdminId(adminId)
                .isFromUserClient(isFromUserClient)
                .details(JSON.toJSONString(orderWarehouseInRollbackApplyReqVO))
                .imgUrl(orderWarehouseInRollbackApplyReqVO.getImgUrl())
                .build();

        orderWarehouseApprovalService.applyAndCreate(orderWarehouseApprovalDO, WorkFlowEmus.ORDER_RETIRED_WAREHOUSE, orderWarehouseInRollbackApplyReqVO.getCopyUserId());

        // 更新订单状态
        Integer auditType = OrderApprovalTypeResultEnum.warehouse_rollback_processing.getType();
        orderService.updateStatus(orderId, orderNo, null, null,
                OrderWarehouseInStatusEnum.rollback_applying.getValue(), null, auditType, OrderApprovalTypeResultEnum.typeAndResultOf(auditType, 1).getDesc(), false);


        orderBusinessService.addOrderOperateLog(orderId, "仓库操作", "提交订单退仓申请", "");
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void rollbackApplyCallback(String approvalId, Integer result) {

        OrderWarehouseApprovalDO orderWarehouseApprovalDO =
                orderWarehouseApprovalService.getById(Long.parseLong(approvalId));

        // 更新审核单状态
        orderWarehouseApprovalService.callbackUpdate(orderWarehouseApprovalDO,
                result);

        String processingResults = orderWarehouseApprovalDO.getProcessingResults();
        if (StringUtils.isNotEmpty(orderWarehouseApprovalDO.getOrderIds())) {
            String[] split =
                    orderWarehouseApprovalDO.getOrderIds().split(",");
            Date date = new Date();
            for (String s : split) {
                long orderId = Long.parseLong(s);

                if (ApprovalResultStatusEnum.pass.getValue().equals(result)) {

                    orderBusinessService.addOrderOperateLog(orderId,
                            "仓库操作", "订单退仓申请通过", "");

                    // 重置OrderItem记录的入仓信息
                    orderItemService.updateOrderItemWarehouseInInfoToNull(orderId,
                            null);

                    // 更新订单状态 7-已退仓
                    Integer auditType =
                            OrderApprovalTypeResultEnum.warehouse_rollback_pass.getType();

                    // 更新订单状态，同时将异常状态重置为0
                    orderService.updateStatus(orderId, null, OrderStatusEnum.WITHDRAWN.getValue(), 0,
                            OrderWarehouseInStatusEnum.rollback_finished.getValue(), null, 0, OrderApprovalTypeResultEnum.typeAndResultOf(auditType, result).getDesc(), false);

                    // 执行退仓
                    orderWarehouseInMapper.delete(
                            new LambdaQueryWrapperX<OrderWarehouseInDO>().eq(OrderWarehouseInDO::getOrderId, orderId));
                    // 删除标签
                    orderLabelService.deleteLabelByOrderId(orderId);

                    //删除储位
                    orderLocationService.deleteIfPresent(orderId,
                            null, null);

                    // 删除订单除未报价和清关费未报价外的所有异常
                    List<OrderExceptionDO> pendHeavyExceptionList =
                            orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderId, null, null);
                    if (CollectionUtil.isNotEmpty(pendHeavyExceptionList)) {
                        pendHeavyExceptionList.stream().filter(t -> !OrderExceptionEnum.ORDER_NO_QUOTE_EXCEPTION.getKey().equals(t.getOrderExceptionType()) && !OrderExceptionEnum.CUSTOMS_FEE_NOT_QUOTE_EXCEPTION.getKey().equals(t.getOrderExceptionType()))
                                .forEach(orderExceptionDO -> orderExceptionService.deleteOrderException(orderExceptionDO.getId()));
                    }

                    //删除订单的应收(整体退仓审批通过后需要删除订单的全部应收单)
                    receivableService.deleteReceivableByOrderId(orderId);

                    // 退仓减少业绩
//                    targetLogService.addTargetLog(orderId, date, TargetLogEnum.WITHDRAWAL);


                } else if (ApprovalResultStatusEnum.reject.getValue().equals(result)) {
                    // 更新订单状态  退仓-已拒绝
                    Integer auditType = OrderApprovalTypeResultEnum.warehouse_rollback_reject.getType();
                    orderService.updateStatus(orderId, null, null, null, OrderWarehouseInStatusEnum.warehouse_finished.getValue(), null, 0, OrderApprovalTypeResultEnum.typeAndResultOf(auditType, result).getDesc(), false);

                    orderBusinessService.addOrderOperateLog(orderId, "仓库操作", "订单退仓申请拒绝", "");
                } else if (ApprovalResultStatusEnum.cancel.getValue().equals(result)) {
                    // 更新订单状态  退仓-已取消
                    Integer auditType = OrderApprovalTypeResultEnum.warehouse_rollback_cancel.getType();
                    orderService.updateStatus(orderId, null, null, null, OrderWarehouseInStatusEnum.warehouse_finished.getValue(), null, 0, OrderApprovalTypeResultEnum.typeAndResultOf(auditType, result).getDesc(), false);

                    orderBusinessService.addOrderOperateLog(orderId, "仓库操作", "订单退仓申请取消", "");
                }
            }
        }
    }

    @Override
    public void changeOrderWarehouseInCartonsNumCorrect(Long orderId, Long orderItemId) {

        OrderItemDO orderItemDO = orderItemService.getOrderItem(orderItemId);
        String warehouseInInfo = orderItemDO.getWarehouseInInfo();

        if (StringUtils.isNotEmpty(warehouseInInfo)) {
            WarehouseInInfoVO warehouseInInfoVO = JSON.parseObject(warehouseInInfo, WarehouseInInfoVO.class);

            if (warehouseInInfoVO != null) {
                // 多箱/少箱
                Integer cartonsNumDiff = warehouseInInfoVO.getCartonsNumDiff();
                if (cartonsNumDiff != null) {

                    // 拨正 找到最近的一次入仓，将其数据加上diff
                    OrderWarehouseInDO orderWarehouseInDO = orderWarehouseInMapper.selectOne(new LambdaQueryWrapperX<OrderWarehouseInDO>()
                            .eq(OrderWarehouseInDO::getOrderId, orderId)
                            .eq(OrderWarehouseInDO::getOrderItemId, orderItemId)
                            .orderByDesc(OrderWarehouseInDO::getId).last("limit 1"));

                    // 多箱 (拨正的时候 就要减)
                    // 少箱，正常 都用+
                    if (warehouseInInfoVO.getDiffType() != null && warehouseInInfoVO.getDiffType() == 2) {
                        cartonsNumDiff = -1 * warehouseInInfoVO.getCartonsNumDiff();
                    }
                    orderWarehouseInDO.setCartonsNum(orderWarehouseInDO.getCartonsNum() + cartonsNumDiff);

                    // 更新入仓信息
                    orderWarehouseInMapper.updateById(orderWarehouseInDO);

                    // 更新订单项的统计信息
                    warehouseInInfoVO.setDiffType(4);
                    warehouseInInfoVO.setCartonsNumDiff(0);
                    warehouseInInfoVO.setCartonsNum(warehouseInInfoVO.getCartonsNum() + cartonsNumDiff);
                    orderItemDO.setWarehouseInInfo(JSON.toJSONString(warehouseInInfoVO));
                    orderItemService.updateById(orderItemDO);

                    // 更新订单总件数
                    OrderDO orderDO = orderService.getById(orderId);
                    orderDO.setSumNum(orderDO.getSumNum() + cartonsNumDiff);
                    orderService.updateById(orderDO);

                    log.info("拨正订单orderNo={}，warehouseInId={}, cartonsNum={}", orderDO.getOrderNo(), orderWarehouseInDO.getId(), cartonsNumDiff);
                }
            }
        }
    }


    @Override
    public void changeCustomerStatusByOrder() {

        // 发货人处理
        List<CustomerDO> hasOrderConsignorCustomerList = customerMapper.getHasOrderCustomerList();
        if (CollectionUtil.isNotEmpty(hasOrderConsignorCustomerList)) {
            OrderQueryVO query;
            PageVO page;

            for (CustomerDO customerDO : hasOrderConsignorCustomerList) {
                // 先查订单
                query = new OrderQueryVO();
                query.setCustomerDetailId(customerDO.getId());
                page = new PageVO();
                page.setPage(1);
                page.setRows(100);
                PageResult<OrderBackPageVO> orderBackPageVOPageResult = orderQueryService.orderPage(query, page);
                if (orderBackPageVOPageResult != null) {
                    List<OrderBackPageVO> orderBackPageVOList = orderBackPageVOPageResult.getList();
                    if (CollectionUtil.isNotEmpty(orderBackPageVOList)) {

                        // 状态大于5已入仓的数据
                        Date rucangTime = orderBackPageVOList.stream().filter(t -> t.getStatus() >= OrderStatusEnum.IN_WAREHOUSE.getValue() && t.getRucangTime() != null)
                                .map(OrderBackPageVO::getRucangTime).max(Date::compareTo).orElse(null);
                        if (rucangTime != null) {
                            // 若在公海池 且 客户经理不为空，则跳出公海
                            changeCustomerStatus(customerDO, rucangTime, 6, CustomerStatusEnum.DEAL);

                        }

                        // 若还是入仓中的，则更新为意向
                        else {
                            // 状态包含 2 已下单  3 入仓中  4特价申请
                            Date createTime = orderBackPageVOList.stream().filter(t -> t.getStatus() >= OrderStatusEnum.ORDER_PLACED.getValue() && t.getStatus() < OrderStatusEnum.IN_WAREHOUSE.getValue())
                                    .map(OrderBackPageVO::getCreateTime).max(Date::compareTo).orElse(null);
                            if (createTime != null) {
                                changeCustomerStatus(customerDO, createTime, 3, CustomerStatusEnum.INTENTION);
                            }
                        }
                    }
                }
            }
        }
    }

    @Override
    public List<OrderWarehouseInBackItemVO> getOrderWarehouseInListOrderByInTime(Long orderId) {
        return orderWarehouseInMapper.getOrderWarehouseInListOrderByInTime(orderId);
    }

    private void changeCustomerStatus(CustomerDO customerDO, Date createTime, int offset, CustomerStatusEnum intention) {
        // 若在公海池 且 客户经理不为空，则跳出公海
        if (Boolean.TRUE.equals(customerDO.getIsInOpenSea())) {
            if (customerDO.getCustomerService() != null) {
                customerDO.setIsInOpenSea(false);
            } else {
                log.warn("根据订单执行更新客户类型时，客户【{}】的客服经理为null，不能跳出公海，请手工处理。");
            }
        }
        // 更新下次入公海时间
        Date estimateEnterOpenSeaTime = DateUtil.offsetMonth(createTime, offset).toJdkDate();
        if (customerDO.getEstimateEnterOpenSeaTime() == null || customerDO.getEstimateEnterOpenSeaTime().compareTo(estimateEnterOpenSeaTime) == -1) {
            customerDO.setEstimateEnterOpenSeaTime(estimateEnterOpenSeaTime);
        }
        // 更新客户类型
        customerDO.setStatus(intention.getValue());
        customerMapper.updateById(customerDO);

        Long customerId = customerDO.getId();

        boolean isFcl = customerService.isFcl(customerDO);
        //海运整柜 不掉入公海
        if (isFcl) {
            customerMapper.updateCustomerEstimateEnterOpenSeaTimeToNull(customerId);
        }

        //更新关联会员的成交状态
        memberUserApi.updateMemberUserDealStatus(customerId, intention.getValue());
    }


    private void setLocationName(OrderLocationMergeVO orderLocation, Map<Long, WarehouseAreaDO> wareMap, Map<Long, WarehouseAreaPositionDO> positionMap) {
        String wareName = "";
        if (orderLocation.getWareId() != null) {
            WarehouseAreaDO wareDO = wareMap.get(orderLocation.getWareId());
            if (wareDO != null) {
                wareName = wareDO.getName();
            }
        }
        orderLocation.setWareName(wareName);

        String areaName = "";
        if (orderLocation.getAreaId() != null) {
            WarehouseAreaDO areaDO = wareMap.get(orderLocation.getAreaId());
            if (areaDO != null) {
                areaName = areaDO.getName();
            }
        }
        orderLocation.setAreaName(areaName);

        String positionName = "";
        if (orderLocation.getLocationId() != null) {
            WarehouseAreaPositionDO positionDO = positionMap.get(orderLocation.getLocationId());
            if (positionDO != null) {
                positionName = positionDO.getCode();
            }
        }
        orderLocation.setLocationName(positionName);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void finishPacked(OrderItemFinishPackedReqVO orderItemFinishPackedReqVO) {

        // 添加新品标识
        boolean isAddNewOrderItem = orderItemFinishPackedReqVO.getType() != 0;

        Long orderId = orderItemFinishPackedReqVO.getOrderId();
        Long orderItemId = orderItemFinishPackedReqVO.getOrderItemId();

        OrderDO orderDO = orderQueryService.getOrderById(orderId);
        if (orderDO == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_NOT_EXISTS);
        }
        if (orderDO.getStatus() != 5 && orderDO.getInWarehouseState() != 202) {
            throw exception(ORDER_CAN_NOT_FINISH_PACKED);
        }
        // if (orderDO.getAbnormalState() != 0) {
        //     throw exception(ORDER_HAS_PENDING_EXCEPTION, orderDO.getOrderNo());
        // }
        if (orderDO.getAuditType() != 0) {
            throw exception(ORDER_HAS_PROCESSING_APPROVAL, orderDO.getOrderNo());
        }


        // 校验是否有已核销的应收单，如果有，则不能打包，只能无需打包
        try {
            receivableService.verificationReceivableIsWriteOff(orderId, null);
        } catch (Exception e) {
            // 该订单已有应收明细正在核销中或已核销，只能无需打包
            throw exception(RECEIVABLE_WRITE_OFF_ING_NO_NEED_TO_PACK);
        }

        // 更新前一次打包数据
        orderDO = this.updateOrderSumPrevPacked(orderId);

        // 是否 “更新打包” 的标识
        boolean isUpdatePacked = false;

        if (!isAddNewOrderItem) {
            OrderItemDO orderItemDO = orderItemService.getOrderItem(orderItemId);
            if (orderItemDO == null) {
                throw exception(ORDER_ITEM_NOT_EXISTS);
            }
            isUpdatePacked = !orderItemDO.getPackStatus().equals(OrderItemPackStatusEnum.UNPACKED.getValue());

            // 纪录打包历史
            savePackLog(orderId, orderItemId, false);
        }


        // 对象转换
        OrderWarehouseInCreateReqVO createReqVO = BeanUtil.copyProperties(orderItemFinishPackedReqVO, OrderWarehouseInCreateReqVO.class);
        createReqVO.setOrderWarehouseInItemDoList(orderItemFinishPackedReqVO.getOrderWarehouseInItemDtoList());
        // 打包 需要理影像
        createReqVO.setIsProcessPicture(true);

        // 非下单货物，请求中包含
        Long brand = createReqVO.getBrand();
        String prodTitleZh = createReqVO.getProdTitleZh();
        String prodTitleEn = createReqVO.getProdTitleEn();

        if (orderItemId != null) {
            OrderItemDO orderItemDO = orderItemService.selectOne(OrderItemDO::getOrderItemId, orderItemId);

            prodTitleZh = orderItemDO.getProdTitleZh();
            prodTitleEn = orderItemDO.getProdTitleEn();
            brand = orderItemDO.getBrand();
        }

        validateWarehouseInItem(orderDO, brand, createReqVO.getOrderWarehouseInItemDoList(), prodTitleZh, prodTitleEn);

        orderItemId = this.doSaveOrUpdateOrderWarehouseInDo(createReqVO, orderId, orderItemId, orderDO, createReqVO.getPictureUrls(), true, false);

        // 更新订单入仓信息
        OrderWarehouseInVO orderWarehouseInVO = new OrderWarehouseInVO();
        orderWarehouseInVO.setOrderId(orderId);
        orderService.orderInWarehouse(orderWarehouseInVO);

        // 备货时添加新品，纪录个空的打包历史。因为在入仓后才会产生orderItemId，所以才在这里纪录。
        if (isAddNewOrderItem) {
            saveNewOrderItemPackLog(orderId, orderItemId);
        }

        // 设置备货状态，“备货中”
        orderAirService.readyStockProcessing(orderId);

        // 设置打包状态`
        OrderItemDO orderItemDO = orderItemService.getOrderItem(orderItemId);
        orderItemDO.setPackStatus(OrderItemPackStatusEnum.PACKED.getValue());
        // 更新订单项
        orderItemService.updateById(orderItemDO);

        // 纪录操作日志
        orderBusinessService.addOrderOperateLog(orderId, "仓库操作",
                (isUpdatePacked ? "修改" : "完成") + (isAddNewOrderItem ? "打包-添加新品名[" : "打包-品名[") + orderItemDO.getProdTitleZh() + "]", "");
    }

    private void savePackLog(Long orderId, Long orderItemId, boolean isNoNeedPack) {
        OrderItemPackLogCreateReqVO createReqVO = new OrderItemPackLogCreateReqVO();
        createReqVO.setOrderId(orderId);
        createReqVO.setOrderItemId(orderItemId);
        createReqVO.setIsNoNeedToPack(isNoNeedPack);
        OrderWarehouseInBackVO orderWarehouseInBackVO = this.getOrderWarehouseInBackVO(orderId, orderItemId);
        if (orderWarehouseInBackVO != null) {
            createReqVO.setOrderWarehouseInContent(JSON.toJSONString(orderWarehouseInBackVO));
        }
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        if (loginUser != null) {
            createReqVO.setCreatorName(loginUser.getUsername());
        }
        orderItemPackLogService.createItemPackLog(createReqVO);
    }

    private void saveNewOrderItemPackLog(Long orderId, Long orderItemId) {
        OrderItemPackLogCreateReqVO createReqVO = new OrderItemPackLogCreateReqVO();
        createReqVO.setOrderId(orderId);
        createReqVO.setOrderItemId(orderItemId);
        createReqVO.setIsNoNeedToPack(false);
        OrderWarehouseInBackVO orderWarehouseInBackVO = this.getOrderWarehouseInBackVO(orderId, orderItemId);
        if (orderWarehouseInBackVO != null) {
            // 设置打包前的入仓集合为空
            orderWarehouseInBackVO.setOrderWarehouseInBackItemDoList(null);
            orderWarehouseInBackVO.setPictureUrls(null);

            createReqVO.setOrderWarehouseInContent(JSON.toJSONString(orderWarehouseInBackVO));
        }
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        if (loginUser != null) {
            createReqVO.setCreatorName(loginUser.getUsername());
        }
        orderItemPackLogService.createItemPackLog(createReqVO);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void noNeedToPack(Long orderItemId) {
        OrderItemDO orderItemDO = orderItemService.getOrderItem(orderItemId);
        if (orderItemDO == null) {
            throw exception(ORDER_ITEM_NOT_EXISTS);
        }
        Long orderId = orderItemDO.getOrderId();

        OrderDO orderDO = orderQueryService.getOrderById(orderId);
        if (orderDO == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_NOT_EXISTS);
        }
        if (orderDO.getStatus() != 5 && orderDO.getInWarehouseState() != 202) {
            throw exception(ORDER_NOT_WAREHOUSE_IN);
        }
        // if (orderDO.getAbnormalState() != 0) {
        //     throw exception(ORDER_HAS_PENDING_EXCEPTION, orderDO.getOrderNo());
        // }
        if (orderDO.getAuditType() != 0) {
            throw exception(ORDER_HAS_PROCESSING_APPROVAL, orderDO.getOrderNo());
        }

        // 更新前一次打包数据
        orderDO = this.updateOrderSumPrevPacked(orderId);

        // 纪录打包历史
        savePackLog(orderId, orderItemId, true);


        orderItemDO.setPackStatus(OrderItemPackStatusEnum.NO_NEED_TO_PACK.getValue());
        orderItemService.updateById(orderItemDO);

        // 设置备货状态，“备货中”
        orderAirService.readyStockProcessing(orderId);

        // 纪录操作日志
        orderBusinessService.addOrderOperateLog(orderId, "仓库操作", "无需打包-品名[" + orderItemDO.getProdTitleZh() + "]", "");
    }

    /**
     * 完成备货
     *
     * @param finishReqVO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void finishStocked(OrderItemFinishStockedReqVO finishReqVO) {


        String msg = "完成备货";

        Long orderId = finishReqVO.getOrderId();
        OrderDO orderDO = orderService.getById(orderId);
        if (orderDO == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_NOT_EXISTS);
        }

        if (orderDO.getStatus() != 5 && orderDO.getInWarehouseState() != 202) {
            throw exception(ORDER_NOT_WAREHOUSE_IN);
        }
        // if (orderDO.getAbnormalState() != 0) {
        //     throw exception(ORDER_HAS_PENDING_EXCEPTION, orderDO.getOrderNo());
        // }
        if (orderDO.getAuditType() != 0) {
            throw exception(ORDER_HAS_PROCESSING_APPROVAL, orderDO.getOrderNo());
        }

        List<OrderItemDO> orderItemDOList = orderItemService.getOrderItemListByOrderIdList(CollectionUtil.newArrayList(orderId));
        List<OrderWarehouseInDO> orderWarehouseInDOList = orderWarehouseInMapper.selectList(OrderWarehouseInDO::getOrderId, orderDO.getOrderId());

        // fix: https://zentao.test.jdshangmen.com/bug-view-5765.html
        // 完成备货时需要判断有没有品名详情（备货时退仓了），  没有详情时不可完成备货
        if (CollectionUtil.isEmpty(orderWarehouseInDOList)) {
            throw exception(NO_WAREHOUSE_IN_CAN_NOT_PACKED);
        }

        // 除了没有任何入仓的数据，其他所有商品都要完成打包
        if (CollectionUtil.isNotEmpty(orderItemDOList)) {
            String unpackedProdName = orderItemDOList.stream().filter(t -> {
                boolean isUnpacked = t.getPackStatus().equals(OrderItemPackStatusEnum.UNPACKED.getValue());
                // 退仓的可以直接打包，不用判断状态。因为备货时可以退仓，退仓时又不变更打包状态，所以这里就不需要判断没有任何入仓数据的打包状态。
                if (orderWarehouseInDOList.stream().noneMatch(warehouseIn -> warehouseIn.getOrderItemId().equals(t.getOrderItemId()))) {
                    isUnpacked = false;
                }
                return isUnpacked;
            }).map(t -> I18nMessage.getLang() == 0 ? t.getProdTitleZh() : t.getProdTitleEn()).collect(Collectors.joining(","));
            if (StringUtils.isNotEmpty(unpackedProdName)) {
                throw exception(ORDER_ITEM_PRODUCT_UNPACKED);
            }
        }

        // 完成入仓的体积重量
        BigDecimal sumWeightFinishedWarehouseIn = orderDO.getSumWeightFinishedWarehouseIn();
        BigDecimal sumVolumeFinishedWarehouseIn = orderDO.getSumVolumeFinishedWarehouseIn();
        // 上一次打包体积重量
        BigDecimal sumWeightPrevPacked = orderDO.getSumWeightPrevPacked();
        BigDecimal sumVolumePrevPacked = orderDO.getSumVolumePrevPacked();

        // 更新前一次打包数据
        orderDO = this.updateOrderSumPrevPacked(orderId);

        //  完成备货自动计算打包后重量-打包前重量=重量差额大于固定重量（3kg字典查询），自动生成一个重量异常
        BigDecimal stockOverWeightLimit = getStockOverweightLimit();

        // 打包后的
        BigDecimal sumWeightNew = finishReqVO.getSumWeight();
        BigDecimal sumVolumeNew = finishReqVO.getSumVolume();

        boolean isNotRollbackIn = false;

        List<ChannelPackagingOverWeightAdditionalBo> channelPackagingOverWeightAdditionalBoList = genChannelPackagingOverweightAdditionalBoList(orderDO, orderWarehouseInDOList);

        // 重泡货配置
        ZhongPaoBestVO zhongPaoBest = getZhongPaoBest(orderDO);

        // 根据订单项产生异常，多箱，少箱，新增商品异常，入仓特性不符异常
        processOrderItemException(orderId, orderDO, orderItemDOList, isNotRollbackIn, orderWarehouseInDOList, zhongPaoBest, channelPackagingOverWeightAdditionalBoList, true);

        if (CollectionUtil.isNotEmpty(channelPackagingOverWeightAdditionalBoList)) {
            channelPackagingOverWeightAdditionalBoList = channelPackagingOverWeightAdditionalBoList.stream().filter(t -> !t.isMerged()).collect(Collectors.toList());

            for (ChannelPackagingOverWeightAdditionalBo channelPackagingOverWeightAdditionalBo : channelPackagingOverWeightAdditionalBoList) {
                // 生成渠道包装超限异常
                OrderExceptionCreateReqVO orderExceptionCreateReqVO = genOrderException(orderId, null, orderDO,
                        OrderExceptionEnum.CHANNEL_PACKAGING_OVERWEIGHT_EXCEPTION,
                        channelPackagingOverWeightAdditionalBo.getExceptionDescZh(),
                        channelPackagingOverWeightAdditionalBo.getExceptionDescEn(), null, JSON.toJSONString(channelPackagingOverWeightAdditionalBo));
                orderExceptionService.createOrderException(orderExceptionCreateReqVO);
            }

        } else {
            orderExceptionService.autoProcessException(orderId, null, OrderExceptionEnum.CHANNEL_PACKAGING_OVERWEIGHT_EXCEPTION, "未超过路线渠道包装重量上限，系统已自动处理", OrderExceptionResult.CHANNEL_PACKAGING_OVERWEIGHT_EXCEPTION_RESULT.CONFIRMED_SEND);
        }

        // 订单重泡货异常
        BigDecimal weightSum = orderWarehouseInDOList.stream().map(OrderWarehouseInDO::getWeight).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal volumeSum = orderWarehouseInDOList.stream().map(OrderWarehouseInDO::getVolume).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
        Boolean isUpdateCallback = false;
        Boolean isSumVolumeNoChange = sumVolumePrevPacked == null || sumVolumePrevPacked.compareTo(volumeSum) == 0;
        Boolean isSumWeightNoChange = sumWeightPrevPacked == null || sumWeightPrevPacked.compareTo(weightSum) == 0;
        boolean finishStocked = true;
        // 处理重泡货异常
        processZhongPaoException(orderId, orderDO, zhongPaoBest, weightSum, volumeSum, isUpdateCallback,
                isSumVolumeNoChange, isSumWeightNoChange, finishStocked);


        //更新打包前的入仓重量和备货重量阀值
        BigDecimal weightBeforePack = sumWeightFinishedWarehouseIn;
        BigDecimal weightAfterPack = sumWeightNew;

        if (weightBeforePack != null && stockOverWeightLimit != null && weightAfterPack != null
                && (orderDO.getFirstStockedTime() == null || Boolean.FALSE.equals(isSumWeightNoChange))) {
            orderService.update(null, new LambdaUpdateWrapper<OrderDO>()
                    .set(OrderDO::getWeightBeforePack, weightBeforePack)
                    .set(OrderDO::getWeightAfterPack, weightAfterPack)
                    .set(OrderDO::getStockOverWeightLimit, stockOverWeightLimit)
                    .eq(OrderDO::getOrderId, orderDO.getOrderId()));
        }

        //备货异常生成规则：产生规则：
        // 1. 完成备货打包，备货后重量-入仓完成重量>系统设置浮动重量
        // 2. 当前订单无未处理的泡货异常(优先级低于泡货异常)
        //
        // 处理规则：
        //
        // 1. 当前有备货异常未处理的，二次备货且符合产生异常条件，更新异常信息
        // 2. 当前有备货异常未处理的，二次备货且不符合产生条件，自动处理异常，处理结果为已处理， 备注：订单备货后超出重量在系统设置范围内，异常自动处理，操作人=admin

        List<OrderExceptionDO> unProcessPaoExceptionList = orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderId, null, OrderExceptionEnum.ORDER_BULKY_CARGO_EXCEPTION.getKey());
        // 15-10>3 且无泡货异常，说明需要生成重量异常
        if (sumWeightNew.subtract(sumWeightFinishedWarehouseIn).compareTo(stockOverWeightLimit) > 0 && CollectionUtil.isEmpty(unProcessPaoExceptionList)) {
            String manualExceptionType = "7"; // 重量异常
            String descZh = getStockUpExceptionDesc(manualExceptionType, 0, finishReqVO.getDescZh(), finishReqVO.getDescZh());
            String descEn = getStockUpExceptionDesc(manualExceptionType, 1, finishReqVO.getDescZh(), finishReqVO.getDescEn());
            descZh += String.format("系统设置浮动重量[%skg], 备货前重量[%sKg], 备货后重量[%sKg], 备货前后重量差大于浮动重量", stockOverWeightLimit, sumWeightFinishedWarehouseIn, sumWeightNew);
            descEn += String.format("stock threshold [%skg], before stock weight [%sKg], after stock weight [%sKg],  the weight difference before and after stock is greater than threshold", stockOverWeightLimit, sumWeightFinishedWarehouseIn, sumWeightNew);

            OrderExceptionCreateReqVO orderExceptionCreateReqVO = genOrderException(orderId, null, orderDO,
                    OrderExceptionEnum.STOCK_UP_EXCEPTION, descZh, descEn, finishReqVO.getExceptionUrls());
            orderExceptionService.createOrderException(orderExceptionCreateReqVO);

            // 超过超重标准3kg，修改入仓数据、收费数据，订单重新计费。
            orderService.finishOrderWarehouseInUpdate(orderId);
        } else {
            orderExceptionService.autoProcessException(orderId, null, OrderExceptionEnum.STOCK_UP_EXCEPTION, "订单备货后未生产重量异常，异常自动处理",
                    OrderExceptionResult.STOCK_UP_EXCEPTION_RESULT.CONFIRMED_SEND);
        }


        // 查错最原始的入仓纪录纪录
        // 转异
        String manualExceptionType = finishReqVO.getManualExceptionType();
        if (StringUtils.isNotEmpty(manualExceptionType)) {

            msg = "备货转异";

            // 异常影像
            orderWarehousePictureService.createWarehousePictureBatch(finishReqVO.getExceptionUrls(), 4, orderId);

            // 异常
            String descZh = getStockUpExceptionDesc(manualExceptionType, 0, finishReqVO.getDescZh(), finishReqVO.getDescZh());
            String descEn = getStockUpExceptionDesc(manualExceptionType, 1, finishReqVO.getDescZh(), finishReqVO.getDescEn());

            OrderExceptionCreateReqVO orderExceptionCreateReqVO = genOrderException(orderId, null, orderDO,
                    OrderExceptionEnum.STOCK_UP_EXCEPTION, descZh + "（手动转异）", descEn + "(manual)", finishReqVO.getExceptionUrls());
            orderExceptionService.createOrderException(orderExceptionCreateReqVO);
        }

        // 更新备货状态
        orderAirService.readyStock(orderId);

        // 纪录操作日志
        List<ApplyInfoVO> list = new ArrayList<>();
        ApplyInfoVO applyInfoVO = new ApplyInfoVO();
        applyInfoVO.setName("首次打包前重量和完成备货后重量");
        applyInfoVO.setOrgValue(sumWeightFinishedWarehouseIn.toPlainString());
        applyInfoVO.setNewValue(sumWeightNew.toPlainString());
        list.add(applyInfoVO);
        ApplyInfoVO applyInfoVO2 = new ApplyInfoVO();
        applyInfoVO2.setName("打包重量阀值");
        applyInfoVO2.setNewValue(stockOverWeightLimit.toPlainString());
        list.add(applyInfoVO2);
        orderBusinessService.addOrderOperateLog(orderId, "仓库操作", msg, list);
    }

    @Override
    public void processChannelPackagingOverWeightException(OrderDO orderDO) {
        // 空运订单，渠道包装重量超限异常
        if (orderDO.getTransportId() == 3 || orderDO.getTransportId() == 4) {
            Long orderId = orderDO.getOrderId();
            List<OrderWarehouseInDO> orderWarehouseInDOList =
                    orderWarehouseInMapper.selectList(OrderWarehouseInDO::getOrderId, orderId);

            List<ChannelPackagingOverWeightAdditionalBo>
                    channelPackagingOverWeightAdditionalBoList =
                    genChannelPackagingOverweightAdditionalBoList(orderDO,
                            orderWarehouseInDOList);

            if (CollectionUtil.isNotEmpty(channelPackagingOverWeightAdditionalBoList)) {
                channelPackagingOverWeightAdditionalBoList = channelPackagingOverWeightAdditionalBoList.stream().filter(t -> !t.isMerged()).collect(Collectors.toList());

                for (ChannelPackagingOverWeightAdditionalBo channelPackagingOverWeightAdditionalBo : channelPackagingOverWeightAdditionalBoList) {
                    // 生成渠道包装超限异常
                    OrderExceptionCreateReqVO orderExceptionCreateReqVO = genOrderException(orderId, null, orderDO,
                            OrderExceptionEnum.CHANNEL_PACKAGING_OVERWEIGHT_EXCEPTION,
                            channelPackagingOverWeightAdditionalBo.getExceptionDescZh(),
                            channelPackagingOverWeightAdditionalBo.getExceptionDescEn(), null, JSON.toJSONString(channelPackagingOverWeightAdditionalBo));
                    orderExceptionService.createOrderException(orderExceptionCreateReqVO);
                }

            } else {
                orderExceptionService.autoProcessException(orderId,
                        null,
                        OrderExceptionEnum.CHANNEL_PACKAGING_OVERWEIGHT_EXCEPTION,
                        "未超过路线渠道包装重量上限，系统已自动处理",
                        OrderExceptionResult.CHANNEL_PACKAGING_OVERWEIGHT_EXCEPTION_RESULT.CONFIRMED_SEND);
            }
        }
    }

    @Override
    public void dealMergeOrderWarehouseInAndLocation(List<OrderWarehouseInDO> orderWarehouseInList) {
        if (CollectionUtil.isNotEmpty(orderWarehouseInList)) {
            orderWarehouseInList.stream().forEach(item -> {
                //先查原入仓记录id下所有的储位信息
                List<OrderLocationDO> orderLocationListByWarehouseInId = orderLocationService.getOrderLocationListByWarehouseInId(item.getId());
                //设置入仓记录id为空保存为新的入仓记录并返回id
                item.setId(null);
                orderWarehouseInMapper.insert(item);
                //拿到新入仓记录的id 设置新的订单号 和订单项id 然后保存储位信息
                List<OrderLocationDO> orderLocationDOS = orderLocationListByWarehouseInId.stream().map(jj -> {
                    jj.setId(null);
                    jj.setOrderId(item.getOrderId());
                    jj.setOrderItemId(item.getOrderItemId());
                    jj.setWarehouseInId(item.getId());
                    return jj;
                }).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(orderLocationDOS)) {
                    orderLocationService.insertBatch(orderLocationDOS);
                }
            });
        }
    }


    public BigDecimal getStockOverweightLimit() {
        DictDataRespDTO data = DictFrameworkUtils.getDictDataFromCache("air_config", "stock_overweight_limit");
        return data != null && StringUtils.isNotEmpty(data.getValue()) ? new BigDecimal(data.getValue()).setScale(2, RoundingMode.HALF_UP) : new BigDecimal(3).setScale(2, RoundingMode.HALF_UP);
    }

    public BigDecimal getBubbleWeightFloatingThreshold() {
        DictDataRespDTO data = DictFrameworkUtils.getDictDataFromCache("air_config", "bubble_weight_floating_threshold");
        return data != null && StringUtils.isNotEmpty(data.getValue()) ? new BigDecimal(data.getValue()).setScale(2, RoundingMode.HALF_UP) : new BigDecimal(0.05).setScale(2, RoundingMode.HALF_UP);
    }

    public BigDecimal getHeavyVolumeFloatingThreshold() {
        DictDataRespDTO data = DictFrameworkUtils.getDictDataFromCache("air_config", "heavy_volume_floating_threshold");
        return data != null && StringUtils.isNotEmpty(data.getValue()) ? new BigDecimal(data.getValue()).setScale(2, RoundingMode.HALF_UP) : new BigDecimal(0.05).setScale(2, RoundingMode.HALF_UP);
    }


    @Override
    public WarehouseInInfoVO getStatisticsFirstFinishedAfterPacked(Long orderId) {

        WarehouseInInfoVO warehouseInInfoVO = new WarehouseInInfoVO();
        warehouseInInfoVO.setWeight(BigDecimal.ZERO);
        warehouseInInfoVO.setQuantityAll(0);
        warehouseInInfoVO.setCartonsNum(0);
        warehouseInInfoVO.setVolume(BigDecimal.ZERO);

        List<OrderItemDO> orderItemList = orderItemService.getOrderItemListByOrderIdList(CollectionUtil.newArrayList(orderId));

        if (CollectionUtil.isNotEmpty(orderItemList)) {

            // 查最初的入仓日志
            List<OrderItemPackLogDO> originalPackLogList = orderItemPackLogService.getOriginalPackLogList(orderId);

            for (OrderItemDO orderItemDO : orderItemList) {

                OrderItemPackLogDO orderItemPackLogDO = originalPackLogList.stream().filter(t -> t.getOrderItemId().equals(orderItemDO.getOrderItemId())).findFirst().orElse(null);
                if (orderItemPackLogDO != null) {
                    //若有打包纪录，则取打包日志中的首次入仓数据
                    String orderWarehouseInContent = orderItemPackLogDO.getOrderWarehouseInContent();
                    if (StringUtils.isNotEmpty(orderWarehouseInContent)) {
                        OrderWarehouseInBackVO orderWarehouseInBackVO = JSON.parseObject(orderWarehouseInContent, OrderWarehouseInBackVO.class);

                        List<OrderWarehouseInBackItemDo> orderWarehouseInBackItemDoList = orderWarehouseInBackVO.getOrderWarehouseInBackItemDoList();
                        if (CollectionUtil.isNotEmpty(orderWarehouseInBackItemDoList)) {
                            for (OrderWarehouseInBackItemDo orderWarehouseInBackItemDo : orderWarehouseInBackItemDoList) {
                                warehouseInInfoVO.setWeight(warehouseInInfoVO.getWeight().add(orderWarehouseInBackItemDo.getWeight()));
                                warehouseInInfoVO.setVolume(warehouseInInfoVO.getVolume().add(orderWarehouseInBackItemDo.getVolume()));
                                warehouseInInfoVO.setCartonsNum(warehouseInInfoVO.getCartonsNum() + orderWarehouseInBackItemDo.getCartonsNum());
                                warehouseInInfoVO.setQuantityAll(warehouseInInfoVO.getQuantityAll() + (orderWarehouseInBackItemDo.getQuantityAll() == null ? 0 : orderWarehouseInBackItemDo.getQuantityAll()));
                            }
                        }
                    }
                } else {
                    //若没有打包日志，则取原订单项中的数据
                    WarehouseInInfoVO info = orderItemDO.getWarehouseInInfoVO();
                    if (info != null) {
                        warehouseInInfoVO.setWeight(warehouseInInfoVO.getWeight().add(info.getWeight()));
                        warehouseInInfoVO.setVolume(warehouseInInfoVO.getVolume().add(info.getVolume()));
                        warehouseInInfoVO.setCartonsNum(warehouseInInfoVO.getCartonsNum() + info.getCartonsNum());
                        warehouseInInfoVO.setQuantityAll(warehouseInInfoVO.getQuantityAll() + (info.getQuantityAll() == null ? 0 : info.getQuantityAll()));
                    }

                }
            }
        }
        return warehouseInInfoVO;
    }

    @Override
    public List<OrderWarehouseInWithAttrVO> getOrderWarehouseInCommonAttrList(
            Long orderId, Long excludeOrderWarehouseInId) {

        // 根据订单id获取入库详情
        OrderDO orderDO = orderService.getById(orderId);
        if (orderDO == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_NOT_EXISTS);
        }

        //订单明细
        List<OrderItemDO> orderItemDOList =
                orderItemService.list(new LambdaQueryWrapper<OrderItemDO>()
                        .eq(OrderItemDO::getOrderId, orderId).orderByAsc(OrderItemDO::getOrderItemId));
        //ecw_order_warehouse_in 入仓货物详情表
        List<OrderWarehouseInDO> orderWarehouseInDOList =
                orderWarehouseInMapper.selectList(
                        new LambdaQueryWrapper<OrderWarehouseInDO>()
                                .eq(OrderWarehouseInDO::getOrderId, orderId).orderByAsc(OrderWarehouseInDO::getId));

        if (excludeOrderWarehouseInId != null) {
            orderWarehouseInDOList =
                    orderWarehouseInDOList.stream().filter(t -> !t.getId().equals(excludeOrderWarehouseInId)).collect(Collectors.toList());
        }

        List<OrderWarehouseInWithAttrVO> resultList = new ArrayList<>();

        if (CollectionUtil.isNotEmpty(orderWarehouseInDOList)) {
            // 入仓纪录
            for (OrderWarehouseInDO orderWarehouseInDO : orderWarehouseInDOList) {

                // 添加入仓信息
                OrderWarehouseInWithAttrVO orderWarehouseInWithAttrVO = BeanUtil.copyProperties(orderWarehouseInDO, OrderWarehouseInWithAttrVO.class);
                resultList.add(orderWarehouseInWithAttrVO);

                // 设置箱明细属性集合
                List<OrderWarehouseInCommonAttrVO> orderWarehouseInCommonAttrVOList = new ArrayList<>();
                orderWarehouseInWithAttrVO.setOrderWarehouseInCommonAttrVOList(orderWarehouseInCommonAttrVOList);

                // 添加入仓属性
                Long orderItemId = orderWarehouseInDO.getOrderItemId();
                orderItemDOList.stream().filter(t -> t.getOrderItemId().equals(orderItemId)).findFirst().ifPresent(orderItemDO -> {
                    OrderWarehouseInCommonAttrVO orderWarehouseInCommonAttrVO = new OrderWarehouseInCommonAttrVO();
                    orderWarehouseInCommonAttrVO.setProdId(orderItemDO.getProdId());
                    orderWarehouseInCommonAttrVO.setBrand(orderItemDO.getBrand());
                    if (StringUtils.isNotEmpty(orderItemDO.getMaterial())) {
                        orderWarehouseInCommonAttrVO.setMaterial(orderItemDO.getMaterial());
                    }
                    orderWarehouseInCommonAttrVO.setProdAttrIds(orderItemDO.getProdAttrIds());
                    if (StringUtils.isNotEmpty(orderItemDO.getUsageIds())) {
                        orderWarehouseInCommonAttrVO.setUsageIds(orderItemDO.getUsageIds());
                    }
                    orderWarehouseInCommonAttrVO.setQuantityAll(orderWarehouseInDO.getQuantityAll() == null ? orderWarehouseInDO.getCartonsNum() : orderWarehouseInDO.getQuantityAll());

                    orderWarehouseInCommonAttrVOList.add(orderWarehouseInCommonAttrVO);
                });

                // 设置入仓影像
                List<String> pictureUrls = orderWarehousePictureService.getWarehousePictureUrlList(5, orderItemId);
                if (CollectionUtil.isNotEmpty(pictureUrls)) {
                    orderWarehouseInWithAttrVO.setPictureUrls(pictureUrls);
                }


                // 箱明细属性
                List<OrderWarehouseInDetailsVO> orderWarehouseInDetailsVOList = orderWarehouseInDO.getOrderWarehouseInDetailsVOList();
                if (CollectionUtil.isNotEmpty(orderWarehouseInDetailsVOList)) {
                    for (OrderWarehouseInDetailsVO orderWarehouseInDetailsVO : orderWarehouseInDetailsVOList) {

                        OrderWarehouseInCommonAttrVO orderWarehouseInCommonAttrVO = new OrderWarehouseInCommonAttrVO();

                        orderWarehouseInCommonAttrVO.setProdId(orderWarehouseInDetailsVO.getProdId());
                        orderWarehouseInCommonAttrVO.setBrand(orderWarehouseInDetailsVO.getBrand());
                        if (StringUtils.isNotEmpty(orderWarehouseInDetailsVO.getMaterial())) {
                            orderWarehouseInCommonAttrVO.setMaterial(orderWarehouseInDetailsVO.getMaterial());
                        }
                        orderWarehouseInCommonAttrVO.setProdAttrIds(orderWarehouseInDetailsVO.getProdAttrIds());
                        if (StringUtils.isNotEmpty(orderWarehouseInDetailsVO.getUsageIds())) {
                            orderWarehouseInCommonAttrVO.setUsageIds(orderWarehouseInDetailsVO.getUsageIds());
                        }
                        orderWarehouseInCommonAttrVO.setQuantityAll(orderWarehouseInDetailsVO.getQuantityAll());

                        orderWarehouseInCommonAttrVOList.add(orderWarehouseInCommonAttrVO);

                    }
                }

                if (CollectionUtil.isNotEmpty(orderWarehouseInCommonAttrVOList)) {
                    orderWarehouseInCommonAttrVOList.stream().forEach(attrVO -> {

                        // 产品名称
                        if (attrVO.getProdId() != null) {
                            ProductDO product = productService.getProduct(attrVO.getProdId());
                            if (product != null) {
                                attrVO.setProdNameEn(product.getTitleEn());
                                attrVO.setProdNameZh(product.getTitleZh());
                            }
                        }

                        // 品牌名称
                        if (attrVO.getBrand() != null) {
                            ProductBrankDO productBrank = productBrankService.getProductBrank(attrVO.getBrand());
                            if (productBrank != null) {
                                attrVO.setBrandNameZh(productBrank.getTitleZh());
                                attrVO.setBrandNameEn(productBrank.getTitleEn());
                            }
                        }

                        // 材质
                        if (StringUtils.isNotEmpty(attrVO.getMaterial())) {
                            List<DictDataRespDTO> dictDataRespDTOList = dictDataApi.getDictDatas("product_material");
                            Map<String, DictDataRespDTO> dictDataRespDTOMap = dictDataRespDTOList.stream().collect(Collectors.toMap(DictDataRespDTO::getValue, Function.identity(), (key1, key2) -> key2));
                            DictDataRespDTO dictDataRespDTO = dictDataRespDTOMap.get(attrVO.getMaterial());
                            if (dictDataRespDTO != null) {
                                attrVO.setMaterialLabelZh(dictDataRespDTO.getLabel());
                                attrVO.setMaterialLabelEn(dictDataRespDTO.getLabelEn());
                            }
                        }

                        // 商品特性
                        if (StringUtils.isNotEmpty(attrVO.getProdAttrIds())) {
                            List<Long> attrIdList = Arrays.stream(attrVO.getProdAttrIds().split(","))
                                    .filter(StringUtils::isNotEmpty).map(Long::parseLong).collect(Collectors.toList());
                            if (CollectionUtil.isNotEmpty(attrIdList)) {
                                List<ProductAttrDO> attrDOList = productAttrService.getAttrByIds(attrIdList);
                                if (CollectionUtil.isNotEmpty(attrDOList)) {
                                    String attrNameEn = attrDOList.stream().map(ProductAttrDO::getAttrNameEn).collect(Collectors.joining(","));
                                    if (StringUtils.isNotEmpty(attrNameEn)) {
                                        attrVO.setProdAttrNamesEn(attrNameEn);
                                    }
                                    String attrNameZh = attrDOList.stream().map(ProductAttrDO::getAttrName).collect(Collectors.joining(","));
                                    if (StringUtils.isNotEmpty(attrNameZh)) {
                                        attrVO.setProdAttrNamesZh(attrNameZh);
                                    }
                                }
                            }
                        }

                        // 用途
                        if (StringUtils.isNotEmpty(attrVO.getUsageIds())) {
                            List<DictDataRespDTO> dictDataRespDTOList = dictDataApi.getDictDatas("order_item_usage");
                            Map<String, DictDataRespDTO> dictDataRespDTOMap = dictDataRespDTOList.stream().collect(Collectors.toMap(DictDataRespDTO::getValue, Function.identity(), (key1, key2) -> key2));
                            String usageNamesZh = Arrays.stream(attrVO.getUsageIds().split(","))
                                    .map(usageId -> dictDataRespDTOMap.get(usageId) != null ? dictDataRespDTOMap.get(usageId).getLabel() : null)
                                    .filter(Objects::nonNull).collect(Collectors.joining(","));
                            attrVO.setUsageNamesZh(usageNamesZh);
                            String usageNamesEn = Arrays.stream(attrVO.getUsageIds().split(","))
                                    .map(usageId -> dictDataRespDTOMap.get(usageId) != null ? dictDataRespDTOMap.get(usageId).getLabelEn() : null)
                                    .filter(Objects::nonNull).collect(Collectors.joining(","));
                            attrVO.setUsageNamesEn(usageNamesEn);
                        }
                    });
                }

            }
        }
        return resultList;

    }

    private OrderDO updateOrderSumPrevPacked(Long orderId) {
        orderService.updateSumDataPrevPacked(orderId);
        return orderService.getById(orderId);
    }
}
