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

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.apollo.core.event.*;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.util.bigDecimal.BigDecimalUtils;
import cn.iocoder.yudao.framework.common.util.code.CodeUtils;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.i18n.core.I18nMessage;
import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
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.dataobject.customerOperateLog.CustomerOperateLogDO;
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.customerOperateLog.CustomerOperateLogService;
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.mysql.warehouse.WarehouseLineMapper;
import cn.iocoder.yudao.module.depository.dto.LogisticsInfoDto;
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.currency.dto.ExchangeRateRespDTO;
import cn.iocoder.yudao.module.ecw.api.unit.UnitApi;
import cn.iocoder.yudao.module.ecw.api.unit.dto.UnitRespDto;
import cn.iocoder.yudao.module.ecw.dal.dataobject.country.CountryDO;
import cn.iocoder.yudao.module.ecw.dal.dataobject.region.RegionDO;
import cn.iocoder.yudao.module.ecw.service.country.CountryService;
import cn.iocoder.yudao.module.order.dal.dataobject.order.OrderDO;
import cn.iocoder.yudao.module.order.dal.dataobject.order.zTest;
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.orderItem.OrderItemDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderNumberLog.OrderNumberLogDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderObjective.OrderObjectiveDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderSplit.OrderSplitDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderTime.OrderTimeDO;
import cn.iocoder.yudao.module.order.dal.mysql.order.OrderMapper;
import cn.iocoder.yudao.module.order.dal.mysql.order.ZTestMapper2;
import cn.iocoder.yudao.module.order.dal.mysql.orderCargoControl.OrderCargoControlMapper;
import cn.iocoder.yudao.module.order.dal.mysql.orderItem.OrderItemMapper;
import cn.iocoder.yudao.module.order.dal.mysql.orderSplit.OrderSplitMapper;
import cn.iocoder.yudao.module.order.dal.mysql.orderTime.OrderTimeMapper;
import cn.iocoder.yudao.module.order.dto.CalculationItemFeeDto;
import cn.iocoder.yudao.module.order.dto.OrderRemindExceptionDto;
import cn.iocoder.yudao.module.order.enums.*;
import cn.iocoder.yudao.module.order.param.OrderChangePriceParam;
import cn.iocoder.yudao.module.order.param.OrderControlLogParam;
import cn.iocoder.yudao.module.order.service.order.*;
import cn.iocoder.yudao.module.order.service.orderControlLog.OrderControlLogService;
import cn.iocoder.yudao.module.order.service.orderException.OrderExceptionService;
import cn.iocoder.yudao.module.order.service.orderNumberLog.OrderNumberLogService;
import cn.iocoder.yudao.module.order.service.orderOperateLog.OrderOperateLogService;
import cn.iocoder.yudao.module.order.vo.order.*;
import cn.iocoder.yudao.module.order.vo.orderControlLog.OrderControlLogCreateReqVO;
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.orderOperateLog.OrderOperateLogCreateReqVO;
import cn.iocoder.yudao.module.product.component.ProdCostCalculation;
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.dto.CalculationCostResultDto;
import cn.iocoder.yudao.module.product.dto.FeeDto;
import cn.iocoder.yudao.module.product.dto.ProdCostDto;
import cn.iocoder.yudao.module.product.enums.FeeTypeEnum;
import cn.iocoder.yudao.module.product.param.ProdConditionParam;
import cn.iocoder.yudao.module.product.service.product.ProductAttrService;
import cn.iocoder.yudao.module.product.service.product.ProductService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
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.ReceivableCreateReqVO;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.MessageFormat;
import java.util.*;
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.ecw.enums.ErrorCodeConstants.EXCHANGE_RATE_NOT_EXISTS_PARAM;
import static cn.iocoder.yudao.module.order.enums.ErrorCodeConstants.*;

/**
 * 订单 Service 实现类
 *
 * @author 系统管理员
 */
@Service
@Validated
@AllArgsConstructor
@Slf4j
public class OrderBusinessServiceImpl extends AbstractService<OrderMapper, OrderDO> implements OrderBusinessService {

    private final ZTestMapper2 zTestMapper;

    private final OrderMapper orderMapper;
    private final OrderSplitMapper orderSplitMapper;
    private final OrderItemMapper orderItemMapper;
    private final OrderTimeMapper orderTimeMapper;
    private final OrderObjectiveService orderObjectiveService;
    private final OrderConsignorService orderConsignorService;
    private final OrderCargoControlMapper orderCargoControlMapper;
    private final OrderControlLogService orderControlLogService;
    private final OrderConsigneeService orderConsigneeService;
    private final ProductService productService;
    private final WarehouseLineMapper warehouseLineMapper;
    private final CustomerContactsService customerContactsService;
    private final CustomerService customerService;
    private final CustomerOperateLogService customerOperateLogService;
    private final CountryService countryService;
    private final ZhongPaoService zhongPaoService;
    private final OrderNumberLogService orderNumberLogService;
    private final ProdCostCalculation prodCostCalculation;

    private final ReceivableService receivableService;
    private final AdminUserApi adminUserApi;
    private final OrderExceptionService orderExceptionService;
    private final ProductAttrService productAttrService;
    private final ApplicationContext applicationContext;
    private final CurrencyApi currencyApi;
    private final OrderQueryService orderQueryService;
    private final UnitApi unitApi;
    private final OrderOperateLogService orderOperateLogService;


    /**
     * 最新订单单号缓存 0 国家 1 运输方式 2 目的地城市
     */
    private static final String ORDER_NEW_NUMBER = "order:new:number:{0}:{1}:{2}";
    private static final String AIR_ORDER_NEW_NUMBER = "air:order:new:number:A";


    @Override
    public void addOrderCustomerService(OrderDO order, int customerType) {
        if (Objects.nonNull(order.getParentOrderId()) && order.getParentOrderId() > 0 && !order.getSplitSeparateOrder()) {
            // 拆单子订单,并且未标记为独立订单，则不执行客户经理分配规则，以原单为主
            return;
        }
        // 判断该订单、该客户是否有未分配客户异常，如果有，则这个订单不计算业绩
        List<OrderExceptionDO> orderExceptionDOList =
                orderExceptionService.getOrderExceptionByCustomerId(
                        order.getCustomerId());
        // 获取当前订单的异常
        OrderExceptionDO currentOrderException = orderExceptionDOList.stream()
                .filter(orderExceptionDO -> Objects.equals(orderExceptionDO.getOrderId(), order.getOrderId())).findFirst().orElse(null);
        CustomerDO customerDO = customerService.getById(order.getCustomerId());
        Long oldCustomerService = null; // 老客户经理默认为null
        if (Objects.nonNull(customerDO) &&
                Objects.nonNull(customerDO.getCustomerService())
                && customerDO.getCustomerService() != 0L
                && Objects.nonNull(customerDO.getCustomerServiceAssignedTime())
                && !customerDO.getIsCustomerServiceConfirmed()
                && !customerDO.getIsInOpenSea()) {
            // 如果客户存在，客户经理已分配，有分配时间，但是待确认接收，
            // 也不是公海捞取，那么需要判断该客户之前是否有客户经理，
            // 没有则业绩属于公司客户，有则业绩归属于上个客户经理
            CustomerOperateLogDO customerOperateLogDO =
                    customerOperateLogService.getOne(new LambdaQueryWrapper<CustomerOperateLogDO>()
                            .eq(CustomerOperateLogDO::getCustomerId, customerDO.getId())
                            .eq(CustomerOperateLogDO::getOperateType, 4) // TODO 暂定操作类型4为分配操作，有遗漏后面补充操作类型即可
                            .orderByDesc(CustomerOperateLogDO::getId).last("limit 1"));
            if (Objects.nonNull(customerOperateLogDO) && Objects.nonNull(customerOperateLogDO.getOldCustomerService()) && customerOperateLogDO.getOldCustomerService() != 0L) {
                oldCustomerService = customerOperateLogDO.getOldCustomerService();
            }
        }
        // 没有该订单，该客户的未分配客户经理异常
        if (Objects.isNull(currentOrderException) && Objects.nonNull(customerDO) && Objects.nonNull(customerDO.getCustomerService()) && customerDO.getCustomerService() != 0L
                && (customerDO.getIsCustomerServiceConfirmed() || (!customerDO.getIsCustomerServiceConfirmed() && Objects.nonNull(oldCustomerService)))) {
            if (Objects.nonNull(oldCustomerService)) {
                // 如果这里的旧客户经理id不为null，说明此客户属于移交新客户经理，但是新客户经理还未接收，业绩算老客户经理的
                order.setSalesmanId(oldCustomerService);
            } else {
                order.setSalesmanId(customerDO.getCustomerService());
            }
            AdminUserRespDTO adminUserRespDTO = adminUserApi.getUser(order.getSalesmanId());
            if (Objects.nonNull(adminUserRespDTO)) {
                order.setDeptId(adminUserRespDTO.getDeptId());
            } else {
                order.setDeptId(0L);
            }
        } else if (CollectionUtil.isEmpty(orderExceptionDOList) &&
                Objects.nonNull(customerDO)
                && (Objects.isNull(customerDO.getCustomerService()) ||
                (!customerDO.getIsCustomerServiceConfirmed()
                        && Objects.isNull(oldCustomerService)))) {

            // 如果客户正在移交新客户经理，但是未接收，并且老客户经理不为null，则不创建客户经理未分配异常
            //web下单，业绩为收货人，不产生未分配客户经理异常
            if (order.getUserId() != null && order.getUserId() > 0 && customerType == 2) {
                order.setSalesmanId(0L);
                order.setDeptId(0L);
                log.info("web下单，业绩为收货人，不产生未分配客户经理异常 orderNo={}", order.getOrderNo());
            } else {
                // 只有客户的客户经理为空时
                String descZh = "归属客户：%s  客户编号：%s";
                String descEn = "Customer: %s Customer No.: %s";
                // 该客户没有客户经理, 需要生成异常，判断当前客户是发货人还是收货人
                if (customerType == 1) {
                    // 发货人
                    descZh = String.format(descZh, "发货人", customerDO.getNumber());
                    descEn = String.format(descEn, "consignor", customerDO.getNumber());
                } else {
                    // 收货人
                    descZh = String.format(descZh, "收货人", customerDO.getNumber());
                    descEn = String.format(descEn, "consignee", customerDO.getNumber());
                }
                OrderExceptionCreateReqVO orderExceptionCreateReqVO = this.genOrderException(order.getOrderId(), order, null, order.getCustomerId(), OrderExceptionEnum.NOT_CUSTOMER_SERVICE_EXCEPTION,
                        descZh, descEn);
                orderExceptionService.createOrderException(orderExceptionCreateReqVO);
            }
        } else {
            // 该订单存在该客户未分配客户经理异常，
            // 或者该客户的客户经理待接收，则不再生成未分配客户经理异常，且该订单不产生业绩归属
            order.setSalesmanId(0L);
            order.setDeptId(0L);
        }
    }

    @Override
    public void createNoCanShipmentChannelException(OrderDO orderDO,
                                                    QueryChannelInfoEvent event,
                                                    OrderItemDO orderItemDO,
                                                    WarehouseInInfoVO warehouseInInfoVO,
                                                    Integer type,
                                                    List<OrderExceptionDO> orderExceptionDOList) {

        // 入仓订单才判断是否产生不可出渠道异常 bug-view-4783 时间2023-09-24 ，
        // type为null时，是单独检查订单的不可出特效信息,订单状态必定是5已入仓
        if (Objects.nonNull(warehouseInInfoVO) &&
                warehouseInInfoVO.getCartonsNum() > 0
                && (orderDO.getStatus() == 5 || type == 15)
                && Objects.nonNull(orderDO.getChannelId())
                && orderDO.getChannelId() > 0
                && (Objects.isNull(orderDO.getHandlerChannelAttrException())
                || !orderDO.getHandlerChannelAttrException()
                || Objects.isNull(orderItemDO.getHandlerChannelAttrException())
                || !orderItemDO.getHandlerChannelAttrException())) {

            String prodAttrIds = orderItemDO.getWarehouseInProdAttrIds();
            // 品名特性与渠道包含特性比较，判断是否生成不可出渠道异常

            if (StringUtils.isNotBlank(prodAttrIds)) {
                List<String> notShippingIds = null;
                if (StringUtils.isBlank(event.getAttrId())) {
                    notShippingIds = Arrays.asList(prodAttrIds.split(StrUtil.COMMA));
                } else {
                    String[] channelAttrIds = event.getAttrId().split(StrUtil.COMMA);
                    notShippingIds = Arrays.stream(prodAttrIds.split(StrUtil.COMMA)).filter(t -> !ArrayUtil.contains(channelAttrIds, t)).collect(Collectors.toList());
                }

                if (CollectionUtil.isNotEmpty(notShippingIds)) {
                    // 标记此订单项品名已经比较过不可出特性,并更新到数据库
                    orderItemMapper.update(null, new LambdaUpdateWrapper<OrderItemDO>().set(OrderItemDO::getHandlerChannelAttrException, true).eq(OrderItemDO::getOrderItemId, orderItemDO.getOrderItemId()));
                    // 没有待处理的不可出渠道异常，则需要生成，有则只需要标记此订单项品名一比较过不可出渠道特性即可
                    if (CollectionUtil.isEmpty(orderExceptionDOList)) {
                        List<ProductAttrDO> productAttrDOList = productAttrService.getProductAttrList();
                        StringJoiner notShippingNameZh = new StringJoiner(",");
                        StringJoiner notShippingNameEn = new StringJoiner(",");

                        for (String notShippingId : notShippingIds) {
                            ProductAttrDO productAttrDO = productAttrDOList.stream().filter(p -> p.getId().toString().equals(notShippingId)).findFirst().orElse(null);
                            if (productAttrDO != null) {
                                notShippingNameZh.add(productAttrDO.getAttrName());
                                notShippingNameEn.add(productAttrDO.getAttrNameEn());
                            }
                        }

                        String descZh = String.format("订单包含【%s】不可出商品特性【%s】", event.getNameZh(), notShippingNameZh);
                        String descEn = String.format("Order includes 【%s】 Non-export feature 【%s】", event.getNameEn(), notShippingNameEn);

                        // 当前空运或海空联运订单下单时，没又渠道id，则生成渠道异常
                        OrderExceptionCreateReqVO orderExceptionCreateReqVO = this.genOrderException(orderDO.getOrderId(), orderDO, null, null, OrderExceptionEnum.NOT_SHIPPING_CHANNEL_EXCEPTION,
                                descZh, descEn);
                        orderExceptionService.createOrderException(orderExceptionCreateReqVO);
                    }
                } else {
                    // 如果没有不可出特性，且有待处理的不可出渠道异常，需要自动处理
                    if (CollectionUtil.isNotEmpty(orderExceptionDOList)) {
                        orderDO.setIsAutomaticHandleNoCanShipmentChannelException(true);
                    }
                }
            } else {
                // 如果没有不可出特性，且有待处理的不可出渠道异常，
                // 则需要排查当不可出渠道异常是否为当前品名生成的
                if (CollectionUtil.isNotEmpty(orderExceptionDOList)) {
                    orderDO.setIsAutomaticHandleNoCanShipmentChannelException(true);
                }
            }
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleOrderNoQuote(Long orderId) {
        log.info("处理未报价异常开始....订单id【{}】", orderId);
        OrderDO orderDO = orderMapper.selectById(orderId);
        if (Objects.isNull(orderDO)) {
            throw exception(ORDER_NOT_EXISTS);
        }
        handleException(orderId, orderDO, 6);
        log.info("处理未报价异常结束....订单id【{}】", orderId);
    }

    /*
     重载的函数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleOrderNoQuote(Long orderId,
                                   ProductPriceDO productPriceDO) {
        log.info("处理未报价异常开始....订单id【{}】", orderId);
        OrderDO orderDO = orderMapper.selectById(orderId);
        if (Objects.isNull(orderDO)) {
            throw exception(ORDER_NOT_EXISTS);
        }
        handleException(orderId, orderDO, 6, productPriceDO);
        log.info("处理未报价异常结束....订单id【{}】", orderId);
    }


    @Override
    public void handleOrderChannelException(Long orderId, Long channelId, Long lineId, List<OrderChangePriceParam> channelPriceParams) {
        log.info("切换线路处理不可出渠道异常开始....订单id【{}】....线路ID【{}】....渠道ID【{}】", orderId, lineId, channelId);
        OrderDO orderDO = orderMapper.selectById(orderId);
        if (Objects.isNull(orderDO)) {
            throw exception(ORDER_NOT_EXISTS);
        }
        // 当没有切换线路或渠道时，处理完渠道异常是不再生成此异常，反之既是允许，这里需要在线路和渠道未变更的情况下做已处理过渠道异常标记
        if (Objects.equals(lineId, orderDO.getLineId()) && Objects.equals(channelId, orderDO.getChannelId())) {
            orderDO.setHandlerChannelAttrException(Boolean.TRUE);
        }
        orderDO.setLineId(lineId);
        orderDO.setChannelId(channelId);
        handleException(orderId, orderDO, channelPriceParams, 11);
        log.info("切换线路处理不可出渠道异常结束....订单id【{}】....线路ID【{}】....渠道ID【{}】", orderId, lineId, channelId);
    }

    @Override
    public void handleOrderWeightOverrun(Long orderId, List<OrderChangePriceParam> channelPriceParams) {
        log.info("处理超重异常开始....订单id【{}】", orderId);
        OrderDO orderDO = orderMapper.selectById(orderId);
        if (Objects.isNull(orderDO)) {
            throw exception(ORDER_NOT_EXISTS);
        }
        handleException(orderId, orderDO, channelPriceParams, 13);
        log.info("处理超重异常结束....订单id【{}】", orderId);
    }

    @Override
    public void handleOrderInquiryException(Long orderId, List<OrderChangePriceParam> inquiryPriceParams) {
        log.info("处理单询异常开始....订单id【{}】", orderId);
        OrderDO orderDO = orderMapper.selectById(orderId);
        if (Objects.isNull(orderDO)) {
            throw exception(ORDER_NOT_EXISTS);
        }
        // 处理单询异常是否需要做标记不再允许生成
        handleException(orderId, orderDO, inquiryPriceParams, 12);
        log.info("处理单询异常结束....订单id【{}】", orderId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleOrderChannelException(Long orderId, Long channelId) {
        log.info("处理渠道异常开始....订单id【{}】....渠道ID【{}】", orderId, channelId);
        OrderDO orderDO = orderMapper.selectById(orderId);
        if (Objects.isNull(orderDO)) {
            throw exception(ORDER_NOT_EXISTS);
        }
        orderDO.setChannelId(channelId);
        handleException(orderId, orderDO, 11);
        log.info("处理渠道异常结束....订单id【{}】....渠道ID【{}】", orderId, channelId);
    }

    @Override
    public void handleOrderChannelAttrException(Long orderId) {
        log.info("处理订单继续不可出特性渠道异常开始....订单id【{}】", orderId);
        OrderDO orderDO = orderMapper.selectById(orderId);
        if (Objects.isNull(orderDO)) {
            throw exception(ORDER_NOT_EXISTS);
        }
        // 继续不可出渠道
        orderDO.setHandlerChannelAttrException(Boolean.TRUE);
        handleException(orderId, orderDO, 11);
        log.info("处理订单继续不可出特性渠道异常结束....订单id【{}】", orderId);
    }


    @Override
    public void handleOrderChannelAttrException(Long orderId, List<OrderChangePriceParam> channelClearanceParams) {
        log.info("处理订单渠道不可出特性异常开始....订单id【{}】", orderId);
        OrderDO orderDO = orderMapper.selectById(orderId);
        if (Objects.isNull(orderDO)) {
            throw exception(ORDER_NOT_EXISTS);
        }
        // 处理渠道特性价格自定义
        orderDO.setHandlerChannelAttrException(Boolean.TRUE);
        handleException(orderId, orderDO, channelClearanceParams, 11);
        log.info("处理订单渠道不可出特性异常结束....订单id【{}】", orderId);
    }

    @Override
    public void handleOrderHeavyBubble(Long orderId, Integer orderType) {
        OrderDO orderDO = orderMapper.selectById(orderId);
        if (Objects.isNull(orderDO)) {
            throw exception(ORDER_NOT_EXISTS);
        }
        orderDO.setOrderType(orderType);
        handleException(orderId, orderDO, 9);
    }

    @Override
    public void handleOrderPickleType(Long orderId, Integer pickleType) {
        OrderDO orderDO = orderMapper.selectById(orderId);
        if (Objects.isNull(orderDO)) {
            throw exception(ORDER_NOT_EXISTS);
        }
        orderDO.setOrderType(3);
        orderDO.setPickleType(pickleType);
        handleException(orderId, orderDO, 9);
    }

    private void handleException(Long orderId, OrderDO orderDO, int type) {
        OrderConsignorDO orderConsignorDO =
                orderConsignorService.getOne(
                        new LambdaQueryWrapper<OrderConsignorDO>().
                                eq(OrderConsignorDO::getOrderId, orderId).
                                last("limit 1"));

        OrderConsigneeDO orderConsigneeDO =
                orderConsigneeService.getOne(
                        new LambdaQueryWrapper<OrderConsigneeDO>().
                                eq(OrderConsigneeDO::getOrderId, orderId).
                                last("limit 1"));

        List<OrderItemDO> orderItemDOList =
                orderItemMapper.selectList(new LambdaQueryWrapper<OrderItemDO>().
                        eq(OrderItemDO::getOrderId, orderId));

        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();

        String updater =
                String.valueOf(loginUser != null ? loginUser.getId() : null);
        // 插入订单商品项
        this.costCalculation(updater, orderDO,
                orderConsignorDO.getCustomerId(),
                Objects.isNull(orderConsigneeDO) ? 0L : orderConsigneeDO.getCustomerId(),
                orderConsignorDO.getCustomerContactsId(),
                Objects.isNull(orderConsigneeDO) ? 0L : orderConsigneeDO.getCustomerContactsId(),
                orderItemDOList, type);
    }

    private void handleException(Long orderId, OrderDO orderDO, int type,
                                 ProductPriceDO productPriceDO) {
        OrderConsignorDO orderConsignorDO =
                orderConsignorService.getOne(
                        new LambdaQueryWrapper<OrderConsignorDO>().
                                eq(OrderConsignorDO::getOrderId, orderId).
                                last("limit 1"));

        OrderConsigneeDO orderConsigneeDO =
                orderConsigneeService.getOne(
                        new LambdaQueryWrapper<OrderConsigneeDO>().
                                eq(OrderConsigneeDO::getOrderId, orderId).
                                last("limit 1"));

        List<OrderItemDO> orderItemDOList =
                orderItemMapper.selectList(new LambdaQueryWrapper<OrderItemDO>().
                        eq(OrderItemDO::getOrderId, orderId));


        for (OrderItemDO oItem : orderItemDOList
        ) {
            if (productPriceDO.getNeedOrderInquiry() == null) {
                oItem.setNeedOrderInquiry(0);
            } else {
                if (productPriceDO.getNeedOrderInquiry() == 1)
                    oItem.setNeedOrderInquiry(productPriceDO.getNeedOrderInquiry());
            }
        }


        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();

        String updater =
                String.valueOf(loginUser != null ? loginUser.getId() : null);
        // 插入订单商品项
        this.costCalculation(updater, orderDO,
                orderConsignorDO.getCustomerId(),
                Objects.isNull(orderConsigneeDO) ? 0L : orderConsigneeDO.getCustomerId(),
                orderConsignorDO.getCustomerContactsId(),
                Objects.isNull(orderConsigneeDO) ? 0L : orderConsigneeDO.getCustomerContactsId(),
                orderItemDOList, type);
    }


    private void handleException(Long orderId, OrderDO orderDO, List<OrderChangePriceParam> channelPriceParams, int type) {
        OrderConsignorDO orderConsignorDO = orderConsignorService.getOne(new LambdaQueryWrapper<OrderConsignorDO>().eq(OrderConsignorDO::getOrderId, orderId).last("limit 1"));
        OrderConsigneeDO orderConsigneeDO = orderConsigneeService.getOne(new LambdaQueryWrapper<OrderConsigneeDO>().eq(OrderConsigneeDO::getOrderId, orderId).last("limit 1"));
        List<OrderItemDO> orderItemDOList = orderItemMapper.selectList(new LambdaQueryWrapper<OrderItemDO>().eq(OrderItemDO::getOrderId, orderId));
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        if (CollectionUtil.isNotEmpty(channelPriceParams)) {
            Map<Long, OrderChangePriceParam> channelPriceParamMap = channelPriceParams.stream()
                    .collect(Collectors.toMap(OrderChangePriceParam::getOrderItemId, v -> v, (v1, v2) -> v2));
            for (OrderItemDO it : orderItemDOList) {
                OrderChangePriceParam channelPriceParam = channelPriceParamMap.get(it.getOrderItemId());
                if (Objects.nonNull(channelPriceParam)) {
                    if (it.getCharging() == 0) {
                        // 运费+清关费，两者都为0则不是自定义价格
                        if ((Objects.isNull(channelPriceParam.getFreightFee()) || channelPriceParam.getFreightFee().compareTo(BigDecimal.ZERO) == 0)
                                && (Objects.isNull(channelPriceParam.getClearanceFee()) || channelPriceParam.getClearanceFee().compareTo(BigDecimal.ZERO) == 0)) {
                            continue;
                        }
                    } else {
                        // 全包价 运费不为0即是自定义价格，否则跳过
                        if (Objects.isNull(channelPriceParam.getFreightFee()) || channelPriceParam.getFreightFee().compareTo(BigDecimal.ZERO) == 0) {
                            continue;
                        }
                    }
                    if (type == 12) {
                        // 单询异常的参数单独处理, 以传参为准
                        it.setCharging(channelPriceParam.getCharging());
                        it.setIsPayAdvance(channelPriceParam.getIsPayAdvance());
                        it.setSeaFreightCurrency(channelPriceParam.getFreightCurrencyId());
                        it.setSeaFreightVolume(channelPriceParam.getFreightUnitId());
                        it.setClearanceFreightCurrency(channelPriceParam.getClearanceCurrencyId());
                        it.setClearanceFreightVolume(channelPriceParam.getClearanceUnitId());
                    }
                    if (it.getSeaFreightCurrency() == 0 || it.getSeaFreightVolume() == 0L) {
                        throw exception(ORDER_NO_QUOTE_NOT_CUSTOM_PRICE);
                    }
                    it.setOneSeaFreight(channelPriceParam.getFreightFee());
                    if (it.getCharging() == 0) {
                        if (it.getClearanceFreightCurrency() == 0 || it.getClearanceFreightVolume() == 0L) {
                            throw exception(ORDER_CLEARANCE_NO_QUOTE_NOT_CUSTOM_PRICE);
                        }
                        it.setOneClearanceFreight(channelPriceParam.getClearanceFee());
                    }
                    it.setChannelManualPricing(true); // 确认渠道/单询手动定价/重量超限异常定价
                }
            }
        }
        String updater = String.valueOf(loginUser != null ? loginUser.getId() : null);
        // 插入订单商品项
        this.costCalculation(updater, orderDO, orderConsignorDO.getCustomerId(), Objects.isNull(orderConsigneeDO) ? 0L : orderConsigneeDO.getCustomerId(),
                orderConsignorDO.getCustomerContactsId(), Objects.isNull(orderConsigneeDO) ? 0L : orderConsigneeDO.getCustomerContactsId(), orderItemDOList, type);
//        orderMapper.updateById(orderDO);
    }


    private OrderExceptionCreateReqVO genOrderException(Long orderId, OrderDO orderDO, OrderItemDO orderItemDO, Long customerId,
                                                        OrderExceptionEnum orderException, String descZh, String descEn) {
        OrderExceptionCreateReqVO orderExceptionCreateReqVO = new OrderExceptionCreateReqVO();
        orderExceptionCreateReqVO.setOrderId(orderId);
        orderExceptionCreateReqVO.setOrderNumber(orderDO.getOrderNo());
        orderExceptionCreateReqVO.setCustomerId(Objects.nonNull(customerId) ? customerId : null);
        if (Objects.nonNull(orderItemDO)) {
            orderExceptionCreateReqVO.setOrderItemId(orderItemDO.getOrderItemId());
            orderExceptionCreateReqVO.setProdId(orderItemDO.getProdId());
        }
        orderExceptionCreateReqVO.setOrderExceptionType(orderException.getKey());
        orderExceptionCreateReqVO.setOrderExceptionDescVO(OrderExceptionDescVO.builder().descZh(descZh).descEn(descEn).build());
        return orderExceptionCreateReqVO;
    }

    private OrderExceptionCreateReqVO genOrderException(Long orderId, OrderBackVO vo, OrderItemDO orderItemDO, Long customerId,
                                                        OrderExceptionEnum orderException, String descZh, String descEn) {
        OrderExceptionCreateReqVO orderExceptionCreateReqVO = new OrderExceptionCreateReqVO();
        orderExceptionCreateReqVO.setOrderId(orderId);
        orderExceptionCreateReqVO.setOrderNumber(vo.getOrderNo());
        orderExceptionCreateReqVO.setCustomerId(Objects.nonNull(customerId) ? customerId : null);
        if (Objects.nonNull(orderItemDO)) {
            orderExceptionCreateReqVO.setOrderItemId(orderItemDO.getOrderItemId());
            orderExceptionCreateReqVO.setProdId(orderItemDO.getProdId());
        }
        orderExceptionCreateReqVO.setOrderExceptionType(orderException.getKey());
        orderExceptionCreateReqVO.setOrderExceptionDescVO(OrderExceptionDescVO.builder().descZh(descZh).descEn(descEn).build());
        return orderExceptionCreateReqVO;
    }

    //添加的逻辑日志记录
    private void saveLog(Collection<Long> orderIds,
                         BigDecimal freightFee,
                         Integer freightCurrencyId,
                         Long freightUnitId,
                         BigDecimal clearanceFee,
                         Integer clearanceCurrencyId,
                         Long clearanceUnitId) {

        String s = "";
        if (freightFee == null) {
            s += "freightFee 为空";
        } else {
            s += "freightFee= " + freightFee.toString();
        }

        if (freightCurrencyId == null) {
            s += "freightCurrencyId 为空";
        } else {
            s += "freightCurrencyId=" + freightCurrencyId.toString();
        }

        if (freightUnitId == null) {
            s += "freightUnitId 为空";

        } else {
            s += "freightUnitId=" + freightUnitId.toString();

        }

        //清关费
        if (clearanceFee == null) {
            s += "clearanceFee 为空";
        } else {
            s += "clearanceFee=" + clearanceFee.toString();
        }

        if (clearanceCurrencyId == null) {
            s += "clearanceCurrencyId 为空";
        } else {
            s += "clearanceCurrencyId=" + clearanceCurrencyId;
        }

        if (clearanceUnitId == null) {
            s += "clearanceUnitId 为空";
        } else {
            s += "clearanceUnitId=" + clearanceUnitId.toString();
        }

        zTest z = new zTest();
        z.setTestname("逻辑参数为：" + s);
        z.setCreatedate(new Date());
        zTestMapper.insert(z);
    }

    //记录逻辑日志
    private String getLog(OrderItemDO it, BigDecimal freightFee,
                          Integer freightCurrencyId,
                          Long freightUnitId) {
        String sR = "";

        if (it == null) {
            sR += "OrderItemDO 为空";
        }

        if (Objects.isNull(freightFee)) {
            sR += " freightFee为空";
            return sR;
        }

        if (Objects.isNull(freightCurrencyId)) {
            sR += " freightCurrencyId 为空";
            return sR;
        }

        if (Objects.isNull(freightUnitId)) {
            sR += " freightUnitId 为空";
            return sR;
        }

        if (it.getSeaFreightCurrency() == null) {
            sR += " it.getSeaFreightCurrency 为空";
            return sR;
        }
        if (freightCurrencyId.equals(it.getSeaFreightCurrency())) {
            sR += " freightCurrencyId=it.getSeaFreightCurrency";
        } else {
            sR += " freightCurrencyId" + freightCurrencyId
                    + "<>it.getSeaFreightCurrency" + it.getSeaFreightCurrency();
            return sR;
        }

        if (it.getSeaFreightVolume() == null) {
            sR += " it.getSeaFreightVolume为空";
            return sR;
        }

        if (freightUnitId.equals(it.getSeaFreightVolume())) {
            sR += "freightUnitId=it.getSeaFreightVolume";
        } else {
            sR += "freightUnitId" + freightUnitId + "<>it.getSeaFreightVolume" +
                    it.getSeaFreightVolume();
        }
        return sR;
    }


    @Override
    public void handleAirOrderBatchMarkup(Collection<Long> orderIds,
                                          BigDecimal freightFee,
                                          Integer freightCurrencyId,
                                          Long freightUnitId,
                                          BigDecimal clearanceFee,
                                          Integer clearanceCurrencyId,
                                          Long clearanceUnitId) {

        //
        saveLog(orderIds,
                freightFee,
                freightCurrencyId,
                freightUnitId,
                clearanceFee,
                clearanceCurrencyId,
                clearanceUnitId);

        for (Long orderId : orderIds) {

            OrderDO orderDO = orderMapper.selectById(orderId);
            if (Objects.isNull(orderDO)) {
                throw exception(ORDER_NOT_EXISTS);
            }
            OrderConsignorDO orderConsignorDO =
                    orderConsignorService.getOne(
                            new LambdaQueryWrapper<OrderConsignorDO>().
                                    eq(OrderConsignorDO::getOrderId, orderId).
                                    last("limit 1"));
            OrderConsigneeDO orderConsigneeDO =
                    orderConsigneeService.getOne(
                            new LambdaQueryWrapper<OrderConsigneeDO>().
                                    eq(OrderConsigneeDO::getOrderId, orderId).
                                    last("limit 1"));
            List<OrderItemDO> orderItemDOList =
                    orderItemMapper.selectList(
                            new LambdaQueryWrapper<OrderItemDO>().
                                    eq(OrderItemDO::getOrderId, orderId));

            LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
            Map<Integer, UnitRespDto> unitRespDtoMap = unitApi.getAllUnit();
            //币种
            Map<Integer, CurrencyRespDTO> currencyRespDTOMap =
                    currencyApi.getAllCurrency();
            List<ApplyInfoVO> applyInfoVOList = new ArrayList<>();
            for (OrderItemDO it : orderItemDOList) {
                String sLog = getLog(it, freightFee, freightCurrencyId, freightUnitId);
                // 只针对已入仓的品名进行加价处理
                if (Objects.nonNull(it.getWarehouseInInfoVO()) &&
                        it.getWarehouseInInfoVO().getCartonsNum() > 0) {

                    // 设置空运订单的每个品名的加价
                    if (Objects.nonNull(freightFee) &&
                            Objects.nonNull(freightCurrencyId) &&
                            Objects.nonNull(freightUnitId) &&
                            freightCurrencyId.equals(it.getSeaFreightCurrency())
                            && freightUnitId.equals(it.getSeaFreightVolume())) {

                        //运费价值，币种，单位都不能为空
                        //清关费币种和单位要和原来的一致

                        ApplyInfoVO freightInfoVO = new ApplyInfoVO();
                        // 货币与计量
                        it.setMarkupSeaFreight(it.getMarkupSeaFreight().add(freightFee));// 累加批量加价
                        it.setOneSeaFreight(it.getOneSeaFreight().add(freightFee)); // 这里对成交单价进行修正
                        freightInfoVO.setName(it.getProdTitleZh() + "/" + it.getProdTitleEn() + (it.getCharging() == 0 ? "运费加价" : "全包价加价"));
                        freightInfoVO.setNewValue(freightFee + currencyRespDTOMap.get(freightCurrencyId).getTitleZh() + "/" + unitRespDtoMap.get(freightUnitId.intValue()).getFuhao());
                        applyInfoVOList.add(freightInfoVO);

                        zTest z = new zTest();
                        z.setTestname("符合条件 币种和单位的判断");
                        z.setCreatedate(new Date());
                        zTestMapper.insert(z);
                    } else {
                        zTest z = new zTest();
                        z.setTestname(sLog + "不符合条件 币种和单位的判断");
                        z.setCreatedate(new Date());
                        zTestMapper.insert(z);
                    }

                    if (it.getCharging() == 0) {
                        //运费加清关价
                        //运费价值，币种，单位都不能为空
                        //清关费币种和单位要和原来的一致
                        if (Objects.nonNull(clearanceFee) &&
                                Objects.nonNull(clearanceCurrencyId) &&
                                Objects.nonNull(clearanceUnitId) &&
                                clearanceCurrencyId.equals(it.getClearanceFreightCurrency()) &&
                                clearanceUnitId.equals(it.getClearanceFreightVolume())) {

                            ApplyInfoVO clearanceInfoVO = new ApplyInfoVO();
                            it.setMarkupClearanceFreight(it.getMarkupClearanceFreight().add(clearanceFee));// 累加批量加价
                            it.setOneClearanceFreight(it.getOneClearanceFreight().add(clearanceFee)); // 这里对成交单价进行修正
                            clearanceInfoVO.setName(it.getProdTitleZh() + "/" + it.getProdTitleEn() + "清关费加价");
                            clearanceInfoVO.setNewValue(clearanceFee + currencyRespDTOMap.get(clearanceCurrencyId).getTitleZh() + "/" + unitRespDtoMap.get(clearanceUnitId.intValue()).getFuhao());
                            applyInfoVOList.add(clearanceInfoVO);

                            zTest z = new zTest();
                            z.setTestname("符合条件 运费加清关价=0");
                            z.setCreatedate(new Date());
                            zTestMapper.insert(z);

                        } else {
                            zTest z = new zTest();
                            z.setTestname("不符合条件 运费加清关价<>0");
                            z.setCreatedate(new Date());
                            zTestMapper.insert(z);
                        }
                    }
                }
            }
            String updater =
                    String.valueOf(loginUser != null ? loginUser.getId() : null);
            // 批量加价计价调整
            this.costCalculation(updater,
                    orderDO, orderConsignorDO.getCustomerId(),
                    Objects.isNull(orderConsigneeDO) ? 0L : orderConsigneeDO.getCustomerId(),
                    orderConsignorDO.getCustomerContactsId(),
                    Objects.isNull(orderConsigneeDO) ? 0L : orderConsigneeDO.getCustomerContactsId(),
                    orderItemDOList, 14);

            // 添加出货批量加价日志
            if (CollectionUtil.isNotEmpty(applyInfoVOList)
                    && applyInfoVOList.size() > 0) {
                this.addOrderOperateLog(orderId,
                        "出货操作",
                        "出货批量加价",
                        applyInfoVOList);
            }
        }
    }

    @Override
    @Async
    public void airOrderPriceRefresh(OrderDO orderDO) {
        log.info("空运订单[{}]重订价开始...", orderDO.getOrderNo());
        List<OrderItemDO> orderItemDOList =
                orderItemMapper.selectList(
                        new LambdaQueryWrapper<OrderItemDO>().
                                eq(OrderItemDO::getOrderId,
                                        orderDO.getOrderId()));

        OrderConsignorDO orderConsignorDO =
                orderConsignorService.getOne(
                        new LambdaQueryWrapper<OrderConsignorDO>().eq(OrderConsignorDO::getOrderId, orderDO.getOrderId()).last("limit 1"));
        OrderConsigneeDO orderConsigneeDO =
                orderConsigneeService.getOne(
                        new LambdaQueryWrapper<OrderConsigneeDO>().eq(OrderConsigneeDO::getOrderId, orderDO.getOrderId()).last("limit 1"));

        this.costCalculation("0", orderDO,
                orderConsignorDO.getCustomerId(),
                Objects.isNull(orderConsigneeDO) ? 0L : orderConsigneeDO.getCustomerId(),
                orderConsignorDO.getCustomerContactsId(),
                Objects.isNull(orderConsigneeDO) ? 0L : orderConsigneeDO.getCustomerContactsId(),
                orderItemDOList, 30);

        this.addOrderOperateLog(orderDO.getOrderId(),
                "空运待出订单每日重订价", null);
        log.info("空运订单[{}]重订价结束...", orderDO.getOrderNo());
    }

    public String saveOrUpdateOrderNo(RegionDO objective, Integer transportId, Boolean isExternalWarehouse, Boolean
            isConcentrateTransport) {
        if (Objects.isNull(objective) || (!StrUtil.equals(objective.getType(), "1") && !StrUtil.equals(objective.getType(), "3"))) {
            throw exception(OBJECTIVE_NOT_EXISTS);
        }
        if (StringUtils.isBlank(objective.getLabelCode())) {
            throw exception(CITY_NOT_SET_LABEL_CODE, I18nMessage.getLang() == 0 ? objective.getTitleZh() : objective.getTitleEn());
        }
        String[] labelCodes = objective.getLabelCode().split(StrUtil.DASHED);
        if (transportId == 3) {
            // 空运订单编号国家简称在目的地配置国家简称的第三位
            if (labelCodes.length < 3) {
                throw exception(CITY_NOT_SET_AIR_LABEL_CODE, I18nMessage.getLang() == 0 ? objective.getTitleZh() : objective.getTitleEn());
            }
        } else {
            if (labelCodes.length < 2) {
                throw exception(CITY_NOT_SET_LABEL_CODE, I18nMessage.getLang() == 0 ? objective.getTitleZh() : objective.getTitleEn());
            }
        }

        // countryShort 国家  尼日利亚：N， 加纳：G， 莫桑比克：M， 肯尼亚：K， 阿联酋：U
        String countryShort = labelCodes[0];
        // cityShort 城市  Lagos：L， Onisha：O， Maputo：M， Accra：A， Nairobi：N， Dubai：D
        String cityShort = labelCodes[1];
        // countryAirShort A+YY（年份）+00000（5位数字，按订单累计，不区分国家）+国家简称(尼日利亚=NG, 加纳=GA，暂时只有这两个国家）
        String countryAirShort = transportId == 3 ? labelCodes[2] : "";
        // transportShort 运输方式简称  海运拼柜：G， 海运整柜：F， 空运专线：A， 海空联运：SA
        String transportShort = TransportTypeShortEnum.valueOf(transportId).getShortName();
        // 目的地发生变更,则重新生成订单号
        String key = StringUtils.equals(transportShort, "F") ? MessageFormat.format(ORDER_NEW_NUMBER, "A", "F", "A") :
                MessageFormat.format(ORDER_NEW_NUMBER,
                        (isConcentrateTransport ? "J" : "") + ((isExternalWarehouse != null && isExternalWarehouse) ? "X" : "") + (StringUtils.equals(transportShort, "A") ? countryAirShort : countryShort), transportShort, cityShort);
        if (Objects.equals(TransportTypeShortEnum.AIR_FREIGHT_LINE.getValue(), transportId)) {
            // 空运编号规则key
            key = AIR_ORDER_NEW_NUMBER;
        }
        String newOrderNo = "";
        // 订单号生成
        try {
            OrderNumberLogDO orderNumberLogDO = orderNumberLogService.newNumberInfo(key, OrderNumberEnum.ORDER_NO.getType());

            String orderNo = Objects.isNull(orderNumberLogDO) ? "" : orderNumberLogDO.getNumber();
            newOrderNo = CodeUtils.getOddOrderNumbers(orderNo, countryShort, countryAirShort, transportShort, cityShort, isExternalWarehouse, isConcentrateTransport);
            if (StringUtils.isBlank(newOrderNo)) {
                throw exception(ORDER_NO_NOT_NULL);
            }
            // 更新最新订单
            if (Objects.equals(TransportTypeShortEnum.AIR_FREIGHT_LINE.getValue(), transportId)) {
                // 空运编号规则key maxOddOrderNumbers.substring(isExternalWarehouse && isConcentrateTransport ? 6 : (isExternalWarehouse || isConcentrateTransport ? 5 : 4), maxOddOrderNumbers.length() - endIndex)
                orderNumberLogService.saveOrUpdateNewNumber(orderNumberLogDO, key, OrderNumberEnum.ORDER_NO.getType(), newOrderNo.substring(0, newOrderNo.length() - countryAirShort.length()));
            } else {
                orderNumberLogService.saveOrUpdateNewNumber(orderNumberLogDO, key, OrderNumberEnum.ORDER_NO.getType(), newOrderNo);
            }
        } catch (ServiceException e) {
            log.error("订单编号生成错误，原因：{}", e.getMessage());
        }

        // 校验最新的编号是否已存在
        long count = orderMapper.selectCount(new LambdaQueryWrapper<OrderDO>().eq(OrderDO::getOrderNo, newOrderNo));
        if (count > 0) {
            newOrderNo = this.saveOrUpdateOrderNo(objective, transportId, isExternalWarehouse, isConcentrateTransport);
        }
        return newOrderNo;
    }

    @Override
    public String getNewOrderNo(String newOrderNo, RegionDO objective, Integer transportId, Boolean
            isExternalWarehouse, Boolean isConcentrateTransport) {
        if (Objects.isNull(objective) || (!StrUtil.equals(objective.getType(), "1") && !StrUtil.equals(objective.getType(), "3"))) {
            throw exception(OBJECTIVE_NOT_EXISTS);
        }
        if (StringUtils.isBlank(objective.getLabelCode())) {
            throw exception(CITY_NOT_SET_LABEL_CODE, I18nMessage.getLang() == 0 ? objective.getTitleZh() : objective.getTitleEn());
        }
        String[] labelCodes = objective.getLabelCode().split(StrUtil.DASHED);
        if (transportId == 3) {
            // 空运订单编号国家简称在目的地配置国家简称的第三位
            if (labelCodes.length < 3) {
                throw exception(CITY_NOT_SET_AIR_LABEL_CODE, I18nMessage.getLang() == 0 ? objective.getTitleZh() : objective.getTitleEn());
            }
        } else {
            if (labelCodes.length < 2) {
                throw exception(CITY_NOT_SET_LABEL_CODE, I18nMessage.getLang() == 0 ? objective.getTitleZh() : objective.getTitleEn());
            }
        }

        // countryShort 国家  尼日利亚：N， 加纳：G， 莫桑比克：M， 肯尼亚：K， 阿联酋：U
        String countryShort = labelCodes[0];
        // cityShort 城市  Lagos：L， Onisha：O， Maputo：M， Accra：A， Nairobi：N， Dubai：D
        String cityShort = labelCodes[1];
        // countryAirShort A+YY（年份）+00000（5位数字，按订单累计，不区分国家）+国家简称(尼日利亚=NG, 加纳=GA，暂时只有这两个国家）
        String countryAirShort = transportId == 3 ? labelCodes[2] : "";
        // transportShort 运输方式简称  海运拼柜：G， 海运整柜：F， 空运专线：A， 海空联运：SA
        String transportShort = TransportTypeShortEnum.valueOf(transportId).getShortName();
        // 目的地发生变更,则重新生成订单号
        String key = StringUtils.equals(transportShort, "F") ? MessageFormat.format(ORDER_NEW_NUMBER, "A", "F", "A") :
                MessageFormat.format(ORDER_NEW_NUMBER,
                        (isConcentrateTransport ? "J" : "") + ((isExternalWarehouse != null && isExternalWarehouse) ? "X" : "") + (StringUtils.equals(transportShort, "A") ? countryAirShort : countryShort), transportShort, cityShort);
        if (Objects.equals(TransportTypeShortEnum.AIR_FREIGHT_LINE.getValue(), transportId)) {
            // 空运编号规则key
            key = AIR_ORDER_NEW_NUMBER;
        }
        // 订单号生成
        try {
            String orderNo = "";
            if (StringUtils.isNotBlank(newOrderNo)) {
                orderNo = newOrderNo;
            } else {
                OrderNumberLogDO orderNumberLogDO = orderNumberLogService.newNumberInfo(key, OrderNumberEnum.ORDER_NO.getType());
                orderNo = Objects.isNull(orderNumberLogDO) ? "" : orderNumberLogDO.getNumber();
            }
            newOrderNo = CodeUtils.getOddOrderNumbers(orderNo, countryShort, countryAirShort, transportShort, cityShort, isExternalWarehouse, isConcentrateTransport);
            if (StringUtils.isBlank(newOrderNo)) {
                throw exception(ORDER_NO_NOT_NULL);
            }
            // 此处只获取最新的订单编号，不一定使用，所以不用保存
        } catch (ServiceException e) {
            log.error("订单编号生成错误，原因：{}", e.getMessage());
        }
        // 校验最新的编号是否已存在
        long count = orderSplitMapper.selectCount(new LambdaQueryWrapper<OrderSplitDO>().eq(OrderSplitDO::getOrderNo, newOrderNo));
        if (count > 0) {
            newOrderNo = this.getNewOrderNo(newOrderNo, objective, transportId, isExternalWarehouse, isConcentrateTransport);
        }
        return newOrderNo;
    }

    //费用来源：1 订单计算 2 费用申请 3 特需费用
    @Override
    public boolean addOrderReceivable(OrderDO orderDO, Integer type) {
        boolean isPayAdvanceException = false;
        // 查询订单已添加的费用类型
        List<ReceivableDO> receivableDOList =
                receivableService.list(
                        new LambdaQueryWrapper<ReceivableDO>().eq(ReceivableDO::getOrderId, orderDO.getOrderId()).eq(ReceivableDO::getDeleted, false));
        // TODO 处理订单项
        CostVO costVO = JSONObject.parseObject(orderDO.getCost(), CostVO.class);
        FeeDto premiumFeeDto = null;
        FeeDto worthFeeDto = null;
        if (Objects.nonNull(costVO)) {
            List<FeeDto> feeDtoList = costVO.getFeeDtoList();
            if (CollectionUtil.isNotEmpty(feeDtoList)) {
                premiumFeeDto = costVO.getFeeDtoList().stream().filter(fee -> Objects.equals(fee.getFeeType(), FeeTypeEnum.INSURANCE_FEE.getType())).findFirst().orElse(null);
                worthFeeDto = costVO.getFeeDtoList().stream().filter(fee -> Objects.equals(fee.getFeeType(), FeeTypeEnum.WORTH.getType())).findFirst().orElse(null);
            }
        }
        List<OrderItemDO> itemDOList =
                orderItemMapper.selectList(new LambdaQueryWrapper<OrderItemDO>().eq(OrderItemDO::getOrderId, orderDO.getOrderId()));
        if (CollectionUtil.isNotEmpty(receivableDOList)) {
            // TODO 处理保价费
            ReceivableDO premiumReceivable = receivableDOList.stream().filter(r -> r.getFeeType() == 6 && Objects.nonNull(r.getFeeSource()) && 1 == r.getFeeSource()).findFirst().orElse(null);
            if (Objects.isNull(premiumReceivable)) {
                if (type == 1) {
                    ReceivableCreateReqVO reqVO = new ReceivableCreateReqVO();
                    reqVO.setOrderId(orderDO.getOrderId());
                    reqVO.setOrderNo(orderDO.getOrderNo());
                    reqVO.setTitleZh(null);
                    reqVO.setTitleEn(null);
                    reqVO.setPaymentUser(String.valueOf(orderDO.getDrawee() != 3 ? orderDO.getDrawee() : orderQueryService.customDrawee(orderDO, 6)));
                    reqVO.setIsPayAdvance(0);
                    reqVO.setCollectionType(4);// 到付
                    reqVO.setFeeType(6);//保价费
                    reqVO.setFeeSource(1);//费用来源，订单计算
                    if (Objects.nonNull(premiumFeeDto)) {
                        reqVO.setAmountWorth(Objects.isNull(worthFeeDto) ? BigDecimal.ZERO : worthFeeDto.getAmount());
                        reqVO.setUnitPrice(premiumFeeDto.getAmount().setScale(0, RoundingMode.HALF_UP));
                        reqVO.setTotalAmount(
                                premiumFeeDto.getAmount().setScale(0, RoundingMode.HALF_UP));
                        reqVO.setTaxAmount(premiumFeeDto.getAmount().setScale(0, RoundingMode.HALF_UP));
                        reqVO.setCurrencyId(Long.valueOf(premiumFeeDto.getCurrencyId()));
                        receivableService.createReceivable(reqVO);
                    }
                }
            } else {
                // TODO 已经付款的应收单不允许修改
                if (Objects.nonNull(premiumFeeDto) &&
                        premiumReceivable.getState() == 0) {
                    premiumReceivable.setTitleZh(null);
                    premiumReceivable.setTitleEn(null);
                    premiumReceivable.setPaymentUser(String.valueOf(orderDO.getDrawee() != 3 ? orderDO.getDrawee() : orderQueryService.customDrawee(orderDO, 6)));
                    premiumReceivable.setAmountWorth(Objects.isNull(worthFeeDto) ? BigDecimal.ZERO : worthFeeDto.getAmount());
                    premiumReceivable.setUnitPrice(premiumFeeDto.getAmount().setScale(0, RoundingMode.HALF_UP));
                    premiumReceivable.setTotalAmount(
                            premiumFeeDto.getAmount().setScale(0, RoundingMode.HALF_UP));
                    premiumReceivable.setTaxAmount(premiumFeeDto.getAmount().setScale(0, RoundingMode.HALF_UP));
                    premiumReceivable.setCurrencyId(Long.valueOf(premiumFeeDto.getCurrencyId()));
                    premiumReceivable.setFeeSource(1);//费用来源，订单计算
                    try {
                        receivableService.updateReceivableById(premiumReceivable);
                    } catch (Exception e) {
                        log.error(String.format("订单号[%s]的保价费应收单更新失败，失败原因:%s",
                                orderDO.getOrderNo(),
                                e.getMessage()));
                    }
                }
            }

            if (CollectionUtil.isNotEmpty(itemDOList)) {
                for (OrderItemDO orderItemDO : itemDOList) {

                    if (Objects.isNull(orderItemDO.getWarehouseInInfoVO()) || orderItemDO.getWarehouseInInfoVO().getCartonsNum() == 0) {
                        continue;
                    }

                    ReceivableDO freightReceivable = receivableDOList.stream().filter(r -> r.getFeeType() == 1 && Objects.nonNull(r.getFeeSource())
                            && 1 == r.getFeeSource() && Objects.equals(r.getOrderItemId(), orderItemDO.getOrderItemId())).findFirst().orElse(null);
                    // 运费
                    if (Objects.isNull(freightReceivable)) {
                        if (type == 1) {
                            // 未生成应收时，根据预付状态判断当前订单状态是否生成应收单
                            if (Objects.nonNull(orderItemDO.getIsPayAdvance()) && orderItemDO.getIsPayAdvance() == 1) {
                                if (!Objects.equals(orderDO.getInWarehouseState(), OrderWarehouseInStatusEnum.warehouse_finished.getValue())
                                        && orderDO.getShipmentState() == 0
                                        && Objects.nonNull(orderItemDO.getWarehouseInInfoVO())
                                        && orderItemDO.getWarehouseInInfoVO().getCartonsNum() > 0) {
                                    continue;
                                }
                                isPayAdvanceException = true;
                            } else {
                                if (!Objects.equals(orderDO.getShipmentState(), OrderStatusMsgEnum.PRE_INSTALLED.getShipmentState()) && !Objects.equals(orderDO.getShipmentState(), OrderStatusMsgEnum.WAREHOUSED.getShipmentState())) {
                                    continue;
                                }
                            }
                            //运费
                            this.createReceivable(orderDO,
                                    orderItemDO, 1,
                                    orderItemDO.getOneSeaFreight(),
                                    orderItemDO.getSeaFreight(),
                                    orderItemDO.getSeaFreightCurrency());
                        }
                    } else {
                        if (freightReceivable.getState() == 0) {
                            freightReceivable.setTitleZh(orderItemDO.getProdTitleZh());
                            freightReceivable.setTitleEn(orderItemDO.getProdTitleEn());
                            freightReceivable.setIsPayAdvance(orderItemDO.getIsPayAdvance());
                            freightReceivable.setCollectionType(Objects.isNull(orderItemDO.getIsPayAdvance()) || orderItemDO.getIsPayAdvance() == 0 ? 4 : 1);
                            freightReceivable.setPaymentUser(String.valueOf(orderDO.getDrawee() != 3 ? orderDO.getDrawee() : orderQueryService.customDrawee(orderDO, 1)));
                            freightReceivable.setAmountWorth(orderItemDO.getWorth());
                            freightReceivable.setUnitPrice(orderItemDO.getOneSeaFreight());
                            freightReceivable.setTotalAmount(
                                    orderItemDO.getSeaFreight().setScale(0, RoundingMode.HALF_UP));
                            freightReceivable.setTaxAmount(orderItemDO.getSeaFreight().setScale(0, RoundingMode.HALF_UP));
                            freightReceivable.setFeeSource(1);
                            if (Objects.isNull(orderItemDO.getWarehouseInInfoVO()) || orderItemDO.getWarehouseInInfoVO().getCartonsNum() == 0) {
                                continue;
                            } else {
                                freightReceivable.setNum(orderItemDO.getWarehouseInInfoVO().getCartonsNum());
                                freightReceivable.setQuantity(orderItemDO.getChargeQuantity().compareTo(orderItemDO.getMinMeteringQuantity()) > 0 ? orderItemDO.getChargeQuantity().intValue() : orderItemDO.getMinMeteringQuantity().intValue());
                                freightReceivable.setWeight(orderItemDO.getChargeWeight().compareTo(orderItemDO.getMinMeteringWeight()) > 0 ? orderItemDO.getChargeWeight() : orderItemDO.getMinMeteringWeight());
                                freightReceivable.setVolume(orderItemDO.getChargeVolume().compareTo(orderItemDO.getMinMeteringVolume()) > 0 ? orderItemDO.getChargeVolume() : orderItemDO.getMinMeteringVolume());
                            }
                            freightReceivable.setCurrencyId(Long.valueOf(orderItemDO.getSeaFreightCurrency()));
                            try {
                                receivableService.updateReceivableById(freightReceivable);
                                if (orderItemDO.getIsPayAdvance() == 1) {
                                    isPayAdvanceException = true;
                                }
                            } catch (Exception e) {
                                log.error(String.format("商品[%s],订单项ID[%s]的运费应收单更新失败，失败原因:%s", freightReceivable.getTitleZh(), freightReceivable.getOrderItemId(), e.getMessage()));
                            }
                        }
                    }
                    ReceivableDO clearanceFeeReceivable =
                            receivableDOList.stream().filter(r -> r.getFeeType() == 2 &&
                                    Objects.nonNull(r.getFeeSource()) && 1 == r.getFeeSource() && Objects.equals(r.getOrderItemId(),
                                    orderItemDO.getOrderItemId())).findFirst().orElse(null);

                    if (orderItemDO.getCharging() == 0) {
                        // 清关费
                        if (Objects.isNull(clearanceFeeReceivable)) {
                            if (type == 1) {
                                // 未生成应收时，根据预付状态判断当前订单状态是否生成应收单
                                if (Objects.nonNull(orderItemDO.getIsPayAdvance()) && orderItemDO.getIsPayAdvance() == 1) {
                                    if (!Objects.equals(orderDO.getInWarehouseState(), OrderWarehouseInStatusEnum.warehouse_finished.getValue()) &&
                                            orderDO.getShipmentState() == 0 &&
                                            Objects.nonNull(orderItemDO.getWarehouseInInfoVO()) &&
                                            orderItemDO.getWarehouseInInfoVO().getCartonsNum() > 0) {
                                        continue;
                                    }
                                    isPayAdvanceException = true;
                                } else {
                                    if (!Objects.equals(orderDO.getShipmentState(), OrderStatusMsgEnum.PRE_INSTALLED.getShipmentState()) && !Objects.equals(orderDO.getShipmentState(), OrderStatusMsgEnum.WAREHOUSED.getShipmentState())) {
                                        continue;
                                    }
                                }
                                this.createReceivable(orderDO, orderItemDO, 2, orderItemDO.getOneClearanceFreight(), orderItemDO.getClearanceFreight(), orderItemDO.getClearanceFreightCurrency());
                            }
                        } else {
                            if (clearanceFeeReceivable.getState() != 2) {
                                clearanceFeeReceivable.setTitleZh(orderItemDO.getProdTitleZh());
                                clearanceFeeReceivable.setTitleEn(orderItemDO.getProdTitleEn());
                                clearanceFeeReceivable.setIsPayAdvance(orderItemDO.getIsPayAdvance());
                                clearanceFeeReceivable.setCollectionType(Objects.isNull(orderItemDO.getIsPayAdvance()) || orderItemDO.getIsPayAdvance() == 0 ? 4 : 1);
                                clearanceFeeReceivable.setFeeSource(1);
                                clearanceFeeReceivable.setPaymentUser(String.valueOf(orderDO.getDrawee() != 3 ? orderDO.getDrawee() : orderQueryService.customDrawee(orderDO, 2)));
                                if (Objects.isNull(orderItemDO.getWarehouseInInfoVO()) || orderItemDO.getWarehouseInInfoVO().getCartonsNum() == 0) {
                                    continue;
                                } else {
                                    clearanceFeeReceivable.setNum(orderItemDO.getWarehouseInInfoVO().getCartonsNum());
                                    if (orderItemDO.getTransportId() == 1 || orderItemDO.getTransportId() == 2) {
                                        clearanceFeeReceivable.setQuantity(orderItemDO.getChargeQuantity().compareTo(orderItemDO.getMinMeteringQuantity()) > 0 ? orderItemDO.getChargeQuantity().intValue() : orderItemDO.getMinMeteringQuantity().intValue());
                                        clearanceFeeReceivable.setWeight(orderItemDO.getChargeWeight().compareTo(orderItemDO.getMinMeteringWeight()) > 0 ? orderItemDO.getChargeWeight() : orderItemDO.getMinMeteringWeight());
                                        clearanceFeeReceivable.setVolume(orderItemDO.getChargeVolume().compareTo(orderItemDO.getMinMeteringVolume()) > 0 ? orderItemDO.getChargeVolume() : orderItemDO.getMinMeteringVolume());
                                    } else {
                                        // 空运清关费按实际入仓数据来计费
                                        Integer quantityAll = orderItemDO.getWarehouseInInfoVO().getQuantityAll();
                                        clearanceFeeReceivable.setQuantity((Objects.isNull(quantityAll) ? BigDecimal.ZERO : new BigDecimal(quantityAll)).compareTo(orderItemDO.getMinMeteringQuantity()) > 0 ? quantityAll : orderItemDO.getMinMeteringQuantity().intValue());
                                        clearanceFeeReceivable.setWeight(orderItemDO.getWarehouseInInfoVO().getWeight().compareTo(orderItemDO.getMinMeteringWeight()) > 0 ? orderItemDO.getWarehouseInInfoVO().getWeight() : orderItemDO.getMinMeteringWeight());
                                        clearanceFeeReceivable.setVolume(orderItemDO.getWarehouseInInfoVO().getVolume().compareTo(orderItemDO.getMinMeteringVolume()) > 0 ? orderItemDO.getWarehouseInInfoVO().getVolume() : orderItemDO.getMinMeteringVolume());
                                    }
                                }
                                clearanceFeeReceivable.setAmountWorth(orderItemDO.getWorth());
                                clearanceFeeReceivable.setUnitPrice(orderItemDO.getOneClearanceFreight());
                                clearanceFeeReceivable.setTotalAmount(
                                        orderItemDO.getClearanceFreight().setScale(0, RoundingMode.HALF_UP));
                                clearanceFeeReceivable.setTaxAmount(
                                        orderItemDO.getClearanceFreight().setScale(0, RoundingMode.HALF_UP));
                                clearanceFeeReceivable.setCurrencyId(
                                        Long.valueOf(orderItemDO.getClearanceFreightCurrency()));
                                try {
                                    receivableService.updateReceivableById(clearanceFeeReceivable);
                                } catch (Exception e) {
                                    log.error(String.format("商品[%s],订单项ID[%s]的清关费应收单更新失败，失败原因:%s", clearanceFeeReceivable.getTitleZh(), clearanceFeeReceivable.getOrderItemId(), e.getMessage()));
                                }
                            }
                        }
                    } else {
                        // TODO 全价时 对于以存在的清关费未生成应收单的应收需要数据清除
                        if (Objects.nonNull(clearanceFeeReceivable)) {
                            receivableService.update(new LambdaUpdateWrapper<ReceivableDO>().set(ReceivableDO::getDeleted, true).eq(ReceivableDO::getId, clearanceFeeReceivable.getId()));
                        }
                    }
                }
            }
        } else {
            if (type == 2) {
                return false;
            }
            if (Objects.nonNull(premiumFeeDto)) {
                ReceivableCreateReqVO reqVO = new ReceivableCreateReqVO();
                reqVO.setOrderId(orderDO.getOrderId());
                reqVO.setOrderNo(orderDO.getOrderNo());
                reqVO.setTitleZh(null);
                reqVO.setTitleEn(null);
                reqVO.setFeeType(6);
                reqVO.setFeeSource(1);
                reqVO.setPaymentUser(String.valueOf(orderDO.getDrawee() != 3 ? orderDO.getDrawee() : orderQueryService.customDrawee(orderDO, 6)));
                reqVO.setIsPayAdvance(0);
                reqVO.setCollectionType(4); // 到付
                reqVO.setUnitPrice(premiumFeeDto.getAmount().setScale(0, RoundingMode.HALF_UP));
                reqVO.setTotalAmount(premiumFeeDto.getAmount().setScale(0, RoundingMode.HALF_UP));
                reqVO.setTaxAmount(premiumFeeDto.getAmount().setScale(0, RoundingMode.HALF_UP));
                reqVO.setCurrencyId(Long.valueOf(premiumFeeDto.getCurrencyId()));
                receivableService.createReceivable(reqVO);
            }
            for (OrderItemDO orderItemDO : itemDOList) {

                if (Objects.isNull(orderItemDO.getWarehouseInInfoVO()) || orderItemDO.getWarehouseInInfoVO().getCartonsNum() == 0) {
                    continue;
                }

                if (Objects.nonNull(orderItemDO.getIsPayAdvance()) && orderItemDO.getIsPayAdvance() == 1) {
                    if (!Objects.equals(orderDO.getInWarehouseState(), OrderWarehouseInStatusEnum.warehouse_finished.getValue()) && orderDO.getShipmentState() == 0) {
                        continue;
                    }
                    isPayAdvanceException = true;
                } else {
//                    if (!Objects.equals(orderDO.getShipmentState(), OrderStatusMsgEnum.PRE_INSTALLED.getShipmentState())) {
                    if (Objects.isNull(orderDO.getShipmentState()) || orderDO.getShipmentState() == 0) {
                        continue;
                    }
                }
                this.createReceivable(orderDO, orderItemDO, 1, orderItemDO.getOneSeaFreight(), orderItemDO.getSeaFreight(), orderItemDO.getSeaFreightCurrency());

                if (orderItemDO.getCharging() == 0) {
                    this.createReceivable(orderDO, orderItemDO, 2, orderItemDO.getOneClearanceFreight(), orderItemDO.getClearanceFreight(), orderItemDO.getClearanceFreightCurrency());
                }

            }
        }
        return isPayAdvanceException;
    }


    /**
     * @param orderDO     订单信息
     * @param orderItemDO 订单商品项信息
     * @param feeType     费用类型 1 运费 2 清关费
     * @param unitPrice   单价
     * @param totalAmount 总额
     * @param currencyId  货币ID
     */
    private void createReceivable(OrderDO orderDO,
                                  OrderItemDO orderItemDO,
                                  Integer feeType, BigDecimal
                                          unitPrice, BigDecimal totalAmount, Integer currencyId) {
        if (Objects.nonNull(orderItemDO.getWarehouseInInfoVO()) && orderItemDO.getWarehouseInInfoVO().getCartonsNum() > 0) {
            if (Objects.isNull(orderItemDO.getIsPayAdvance())) {
                // TODO 这里来生成应收的都不可能为0, 在这里兼容可能发生的插件查询结果导致null值报空，默认给到付状态
                orderItemDO.setIsPayAdvance(0);
            }
            // 只有已入仓的订单项才可能生成应收单
            ReceivableCreateReqVO reqVO = new ReceivableCreateReqVO();
            reqVO.setOrderId(orderDO.getOrderId());
            reqVO.setOrderNo(orderDO.getOrderNo());
            reqVO.setOrderItemId(orderItemDO.getOrderItemId());
            reqVO.setTitleZh(orderItemDO.getProdTitleZh());
            reqVO.setTitleEn(orderItemDO.getProdTitleEn());
            reqVO.setFeeType(feeType);
            reqVO.setFeeSource(1);
            reqVO.setPaymentUser(String.valueOf(orderDO.getDrawee() != 3 ? orderDO.getDrawee() : orderQueryService.customDrawee(orderDO, feeType)));
            reqVO.setIsPayAdvance(Objects.isNull(orderItemDO.getIsPayAdvance()) ? 0 : orderItemDO.getIsPayAdvance());
            reqVO.setCollectionType(Objects.isNull(orderItemDO.getIsPayAdvance()) || orderItemDO.getIsPayAdvance() == 0 ? 4 : 1);

            reqVO.setNum(orderItemDO.getWarehouseInInfoVO().getCartonsNum());
            reqVO.setQuantity(orderItemDO.getChargeQuantity().compareTo(orderItemDO.getMinMeteringQuantity()) > 0 ? orderItemDO.getChargeQuantity().intValue() : orderItemDO.getMinMeteringQuantity().intValue());
            reqVO.setWeight(orderItemDO.getChargeWeight().compareTo(orderItemDO.getMinMeteringWeight()) > 0 ? orderItemDO.getChargeWeight() : orderItemDO.getMinMeteringWeight());
            reqVO.setVolume(orderItemDO.getChargeVolume().compareTo(orderItemDO.getMinMeteringVolume()) > 0 ? orderItemDO.getChargeVolume() : orderItemDO.getMinMeteringVolume());
            if (orderItemDO.getTransportId() == 1 || orderItemDO.getTransportId() == 2 || feeType == 1) {
                reqVO.setQuantity(orderItemDO.getChargeQuantity().compareTo(orderItemDO.getMinMeteringQuantity()) > 0 ? orderItemDO.getChargeQuantity().intValue() : orderItemDO.getMinMeteringQuantity().intValue());
                reqVO.setWeight(orderItemDO.getChargeWeight().compareTo(orderItemDO.getMinMeteringWeight()) > 0 ? orderItemDO.getChargeWeight() : orderItemDO.getMinMeteringWeight());
                reqVO.setVolume(orderItemDO.getChargeVolume().compareTo(orderItemDO.getMinMeteringVolume()) > 0 ? orderItemDO.getChargeVolume() : orderItemDO.getMinMeteringVolume());
            } else {
                // 空运清关费按实际入仓数据来计费
                Integer quantityAll = orderItemDO.getWarehouseInInfoVO().getQuantityAll();
                reqVO.setQuantity((Objects.isNull(quantityAll) ? BigDecimal.ZERO : new BigDecimal(quantityAll)).compareTo(orderItemDO.getMinMeteringQuantity()) > 0 ? quantityAll : orderItemDO.getMinMeteringQuantity().intValue());
                reqVO.setWeight(orderItemDO.getWarehouseInInfoVO().getWeight().compareTo(orderItemDO.getMinMeteringWeight()) > 0 ? orderItemDO.getWarehouseInInfoVO().getWeight() : orderItemDO.getMinMeteringWeight());
                reqVO.setVolume(orderItemDO.getWarehouseInInfoVO().getVolume().compareTo(orderItemDO.getMinMeteringVolume()) > 0 ? orderItemDO.getWarehouseInInfoVO().getVolume() : orderItemDO.getMinMeteringVolume());
            }
            reqVO.setAmountWorth(orderItemDO.getWorth());
            reqVO.setUnitPrice(unitPrice);
            //四舍五入取整数
            reqVO.setTotalAmount(totalAmount.setScale(0,
                    RoundingMode.HALF_UP));
            reqVO.setTaxAmount(totalAmount.setScale(0,
                    RoundingMode.HALF_UP));
            reqVO.setCurrencyId(Long.valueOf(currencyId));
            receivableService.createReceivable(reqVO);
        }
    }

    /**
     * 添加订单动态日志
     *
     * @param status  最新变更订单状态
     * @param orderDO 订单信息
     * @param type    0 正常主状态变更 1 拆单后创建的新订单  2 合单后创建的新订单
     *                3 特价-优惠申请通过 4 特价-管理折扣通过 5 特价-重货优惠通过 6 特价-泡货优惠通过
     *                7、订单修改审批通过 8 入仓修改审批通过 9 佣金设置审批通过 10 撤销拆单成功
     *                11 特价-批量优惠申请通过 12 特价-管理折扣申请通过 99 未定义
     */
    public void addOrderTimeLog(Integer status, OrderDO orderDO, Integer type) {
        Date now = new Date();
        this.addOrderTimeLogAndTime(status, orderDO, type, null, now);
    }

    /**
     * @param orderDO          订单信息
     * @param orderAirTimeEnum OrderAirTimeEnum空运动态枚举值
     * @param reasonZh         业务说明
     * @param reasonEn         业务说明
     * @param estTime          业务时间
     * @param businessTime     业务时间
     * @param now              当前执行时间
     * @param timeId           动态id
     */
    @Override
    public void addAirOrderTimeLog(OrderDO orderDO, OrderAirTimeEnum orderAirTimeEnum, String reasonZh, String
            reasonEn, Date estTime, Date businessTime, Date now, Long timeId) {
        if (Objects.isNull(now)) {
            now = new Date();
        }
        if (Objects.isNull(reasonEn)) {
            reasonEn = "[]";
        }
        if (Objects.isNull(reasonZh)) {
            reasonZh = "[]";
        }
        Integer value = orderAirTimeEnum.getValue();
        OrderTimeDO orderTimeDO = new OrderTimeDO();
        if (Objects.nonNull(timeId)) {
            orderTimeDO.setId(timeId);
        }
        if (value != 200 && value != 520201) {
            // 非入仓和下单动态，则根据入仓动态次数来校验其他动态
            List<OrderTimeDO> orderTimeDOList = orderTimeMapper.selectList(new LambdaQueryWrapper<OrderTimeDO>().eq(OrderTimeDO::getOrderId, orderDO.getOrderId()).eq(OrderTimeDO::getStatus, value).orderByDesc(OrderTimeDO::getId));
            // 如果是退场从新入仓的订单业务线允许重置
            if (CollectionUtil.isNotEmpty(orderTimeDOList) && orderTimeDOList.size() > 0) {
                OrderTimeDO newOrderTime = orderTimeDOList.get(0);
                if (orderDO.getHasExitAndEntry()) {
                    // 入仓动态添加次数
                    long inWarehouseCount = orderTimeMapper.selectCount(new LambdaQueryWrapper<OrderTimeDO>().eq(OrderTimeDO::getOrderId, orderDO.getOrderId()).eq(OrderTimeDO::getStatus, 520201));
                    if (orderTimeDOList.size() == inWarehouseCount) {
                        // 出货及其他动态不允许超出入仓动态次数,如果一致了，则更新信息
                        orderTimeDO.setId(newOrderTime.getId());
                    }
                } else {
                    orderTimeDO.setId(newOrderTime.getId());
                }
            }
        }
        // 主订单状态发生改变时存入日志
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        orderTimeDO.setStatus(value);
        orderTimeDO.setType(0);
        orderTimeDO.setOrderId(orderDO.getOrderId());
        orderTimeDO.setBusinessTime(Objects.isNull(businessTime) ? now : businessTime);
        if (Objects.isNull(orderTimeDO.getId())) {
            orderTimeDO.setCreateTime(now);
            orderTimeDO.setCreator(String.valueOf(userId));
        }
        orderTimeDO.setUpdateTime(now);
        orderTimeDO.setUpdater(String.valueOf(userId));
        switch (orderAirTimeEnum) {
            case AIR_IN_WAREHOUSE:
                CostVO costVO = JSONObject.parseObject(orderDO.getCost(), CostVO.class);
                int placeOrderNum = Objects.nonNull(costVO) && Objects.nonNull(costVO.getTotalNum()) ? costVO.getTotalNum() : 0;// 下单件数
                int sumNum = Objects.nonNull(orderDO.getSumNum()) ? orderDO.getSumNum() : 0; // 入仓件数
                int timeTotalNum = Objects.nonNull(orderDO.getLastTimeTotalNum()) ? orderDO.getLastTimeTotalNum() : 0;
                int currentTotalNum = sumNum - timeTotalNum;
                if (currentTotalNum < 0) {
                    currentTotalNum = 0;
                }
                LogisticsInfoDto logisticsStartInfoDto = warehouseLineMapper.getStartInfoAndDestInfoByLineId(orderDO.getLineId());
                if (Objects.nonNull(logisticsStartInfoDto)) {
                    if (sumNum < placeOrderNum) {
                        // 入仓件数<下单件数
                        orderTimeDO.setRemarksZh(String.format(OrderSeaTimeEnum.SEA_IN_WAREHOUSE_REMARK.getRemarksZh(), logisticsStartInfoDto.getStartTitleZh(), sumNum, currentTotalNum));
//                        orderTimeDO.setRemarksZh(String.format(OrderAirTimeEnum.AIR_IN_WAREHOUSE_REMARK.getRemarksZh(), logisticsStartInfoDto.getStartTitleZh(), sumNum));
                        orderTimeDO.setRemarksEn(String.format(OrderSeaTimeEnum.SEA_IN_WAREHOUSE_REMARK.getRemarksEn(), currentTotalNum, logisticsStartInfoDto.getStartQianzhui(), sumNum));
//                        orderTimeDO.setRemarksEn(String.format(OrderAirTimeEnum.AIR_IN_WAREHOUSE_REMARK.getRemarksEn(), logisticsStartInfoDto.getStartTitleEn(), sumNum));
                    } else {
//                        orderTimeDO.setMark(1); // 入仓件数>=下单件数，字体标红
                        // %s ctns have been arrived at E&C %s warehouse，TTL ctns are %s.
                        orderTimeDO.setRemarksZh(String.format(orderAirTimeEnum.getRemarksZh(), logisticsStartInfoDto.getStartTitleZh(), currentTotalNum, sumNum));
//                        orderTimeDO.setRemarksZh(String.format(orderAirTimeEnum.getRemarksZh(), logisticsStartInfoDto.getStartTitleZh(),currentTotalNum, sumNum));
                        orderTimeDO.setRemarksEn(String.format(orderAirTimeEnum.getRemarksEn(), currentTotalNum, logisticsStartInfoDto.getStartQianzhui(), sumNum));
//                        orderTimeDO.setRemarksEn(String.format(orderAirTimeEnum.getRemarksEn(), currentTotalNum, logisticsStartInfoDto.getStartTitleEn(), sumNum));
                    }
                    orderTimeDO.setTotalNum(sumNum);// 更新当前入仓总件数;
                }
                orderTimeDO.setMark(1);
                break;
            case AIR_WAREHOUSED:
                orderTimeDO.setRemarksZh(orderAirTimeEnum.getRemarksZh());
                orderTimeDO.setRemarksEn(orderAirTimeEnum.getRemarksEn());
                orderTimeDO.setMark(1);
                break;
            case AIR_CUSTOMS_IN_PROGRESS:
                orderTimeDO.setRemarksZh(String.format(orderAirTimeEnum.getRemarksZh(), reasonZh));
                orderTimeDO.setRemarksEn(String.format(orderAirTimeEnum.getRemarksEn(), reasonEn));
                break;
            case AIR_HAS_TAKEN_OFF:
                LogisticsInfoDto logisticsCountryInfoDto1 = warehouseLineMapper.getStartInfoAndDestInfoByLineId(orderDO.getLineId());
                if (Objects.nonNull(logisticsCountryInfoDto1)) {
                    orderTimeDO.setRemarksZh(String.format(orderAirTimeEnum.getRemarksZh(), Objects.nonNull(estTime) ? DateUtil.formatDateTime(estTime) : "", logisticsCountryInfoDto1.getDestCountryTitleZh()));
                    orderTimeDO.setRemarksEn(String.format(orderAirTimeEnum.getRemarksEn(), logisticsCountryInfoDto1.getDestCountryTitleEn(), Objects.nonNull(estTime) ? DateUtil.formatDateTime(estTime) : ""));
                }
                break;
            case AIR_HAS_TAKEN_OFF_DELAY:
                orderTimeDO.setRemarksZh(String.format(orderAirTimeEnum.getRemarksZh(), reasonZh));
                orderTimeDO.setRemarksEn(String.format(orderAirTimeEnum.getRemarksEn(), reasonEn));
                break;
            case AIR_ARRIVED:
                LogisticsInfoDto logisticsCountryInfoDto2 = warehouseLineMapper.getStartInfoAndDestInfoByLineId(orderDO.getLineId());
                if (Objects.nonNull(logisticsCountryInfoDto2)) {
                    orderTimeDO.setMark(1);
                    orderTimeDO.setRemarksZh(String.format(orderAirTimeEnum.getRemarksZh(), logisticsCountryInfoDto2.getDestCountryTitleZh()));
                    orderTimeDO.setRemarksEn(String.format(orderAirTimeEnum.getRemarksEn(), logisticsCountryInfoDto2.getDestCountryTitleEn()));
                }
                break;
            case AIR_ARRIVED_DELAY:
                orderTimeDO.setRemarksZh(String.format(orderAirTimeEnum.getRemarksZh(), reasonZh));
                orderTimeDO.setRemarksEn(String.format(orderAirTimeEnum.getRemarksEn(), reasonEn));
                break;
            case AIR_CLEARED:
                orderTimeDO.setMark(1);
                orderTimeDO.setRemarksZh(orderAirTimeEnum.getRemarksZh());
                orderTimeDO.setRemarksEn(orderAirTimeEnum.getRemarksEn());
                break;
            case AIR_CLEARED_DELAY:
                orderTimeDO.setMark(1);
                orderTimeDO.setRemarksZh(String.format(orderAirTimeEnum.getRemarksZh(), reasonZh));
                orderTimeDO.setRemarksEn(String.format(orderAirTimeEnum.getRemarksEn(), reasonEn));
                break;
            case AIR_UNLOADED_CABINET:
                orderTimeDO.setMark(1);
                OrderObjectiveDO objectiveDO = orderObjectiveService.getByOrderId(orderDO.getOrderId());
                RegionDO objective = JSONObject.parseObject(objectiveDO.getObjective(), RegionDO.class);
                if (Objects.nonNull(objective)) {
                    orderTimeDO.setRemarksZh(String.format(orderAirTimeEnum.getRemarksZh(), objective.getTitleZh()));
                    orderTimeDO.setRemarksEn(String.format(orderAirTimeEnum.getRemarksEn(), objective.getTitleEn()));
                }
                // TODO 这里更新订单卸柜/到仓时间，同时对控货订单的限制修改收货人锁定到期时间进行更新，当前默认使用14D处理，待仓库业务添加该时间配置在做处理

                LogisticsInfoDto logisticsDestInfoDto = warehouseLineMapper.getStartInfoAndDestInfoByLineId(orderDO.getLineId());
                int lockConsigneeDay = Objects.nonNull(logisticsDestInfoDto) && Objects.nonNull(logisticsDestInfoDto.getDestLockRecipientDays()) ? logisticsDestInfoDto.getDestLockRecipientDays() : 0;
                Date lockConsigneeTime = null;
                if (orderDO.getIsCargoControl()) {
                    // TODO 获取卸柜/到仓业务时间的锁定收货人时间当天的结束时间
                    lockConsigneeTime = DateUtil.endOfDay(DateUtil.offsetDay(businessTime, lockConsigneeDay));
                }
                orderMapper.update(null, new LambdaUpdateWrapper<OrderDO>()
                        .set(OrderDO::getUnloadTime, businessTime)
                        .set(OrderDO::getLockConsigneeTime, lockConsigneeTime)
                        .set(OrderDO::getLockConsigneeDay, lockConsigneeDay)
                        .eq(OrderDO::getOrderId, orderDO.getOrderId()));
                break;
            case AIR_UNLOADED_CABINET_DELAY:
                orderTimeDO.setRemarksZh(String.format(orderAirTimeEnum.getRemarksZh(), reasonZh));
                orderTimeDO.setRemarksEn(String.format(orderAirTimeEnum.getRemarksEn(), reasonEn));
                break;
            case AIR_PICKED_UP:
                // 提货封装参数单独处理，reasonZh为本次提货件数，reasonEn为剩余提货件数
                orderTimeDO.setRemarksZh(String.format(orderAirTimeEnum.getRemarksZh(), reasonZh, reasonEn));
                orderTimeDO.setRemarksEn(String.format(orderAirTimeEnum.getRemarksEn(), reasonZh, reasonEn));
                break;
            default:
                orderTimeDO.setRemarksZh(orderAirTimeEnum.getRemarksZh());
                orderTimeDO.setRemarksEn(orderAirTimeEnum.getRemarksEn());
                break;
        }
        orderTimeDO.setTitleZh(orderAirTimeEnum.getNameZh());
        orderTimeDO.setTitleEn(orderAirTimeEnum.getNameEn());
        if (Objects.isNull(orderTimeDO.getId())) {
            orderTimeMapper.insert(orderTimeDO);
        } else {
            orderTimeMapper.updateById(orderTimeDO);
        }
    }


    @Override
    public void addSeaOrderTimeLog(OrderDO orderDO, OrderSeaTimeEnum orderSeaTimeEnum, String reasonZh, String
            reasonEn, Date estTime, Date businessTime, Date now, Long timeId) {
        if (Objects.isNull(now)) {
            now = new Date();
        }
        if (Objects.isNull(reasonEn)) {
            reasonEn = "[]";
        }
        if (Objects.isNull(reasonZh)) {
            reasonZh = "[]";
        }
        Integer value = orderSeaTimeEnum.getValue();
        OrderTimeDO orderTimeDO = new OrderTimeDO();
        if (Objects.nonNull(timeId)) {
            orderTimeDO.setId(timeId);
        }
        if (value != 200 && value != 520201) {
            // 非入仓和下单动态，则根据入仓动态次数来校验其他动态
            List<OrderTimeDO> orderTimeDOList = orderTimeMapper.selectList(new LambdaQueryWrapper<OrderTimeDO>().eq(OrderTimeDO::getOrderId, orderDO.getOrderId()).eq(OrderTimeDO::getStatus, value).orderByDesc(OrderTimeDO::getId));
            // 如果是退场从新入仓的订单业务线允许重置
            if (CollectionUtil.isNotEmpty(orderTimeDOList) && orderTimeDOList.size() > 0) {
                OrderTimeDO newOrderTime = orderTimeDOList.get(0);
                if (orderDO.getHasExitAndEntry()) {
                    // 入仓动态添加次数
                    long inWarehouseCount = orderTimeMapper.selectCount(new LambdaQueryWrapper<OrderTimeDO>().eq(OrderTimeDO::getOrderId, orderDO.getOrderId()).eq(OrderTimeDO::getStatus, 520201));
                    if (orderTimeDOList.size() == inWarehouseCount) {
                        // 出货及其他动态不允许超出入仓动态次数,如果一致了，则更新信息
                        orderTimeDO.setId(newOrderTime.getId());
                    }
                } else {
                    orderTimeDO.setId(newOrderTime.getId());
                }
            }
        }
        // 主订单状态发生改变时存入日志
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        orderTimeDO.setStatus(value);
        orderTimeDO.setType(0);
        orderTimeDO.setOrderId(orderDO.getOrderId());
        orderTimeDO.setBusinessTime(Objects.isNull(businessTime) ? now : businessTime);
        if (Objects.isNull(orderTimeDO.getId())) {
            orderTimeDO.setCreateTime(now);
            orderTimeDO.setCreator(String.valueOf(userId));
        }
        orderTimeDO.setUpdateTime(now);
        orderTimeDO.setUpdater(String.valueOf(userId));
        switch (orderSeaTimeEnum) {
            case SEA_IN_WAREHOUSE:
                CostVO costVO = JSONObject.parseObject(orderDO.getCost(), CostVO.class);
                int placeOrderNum = Objects.nonNull(costVO) && Objects.nonNull(costVO.getTotalNum()) ? costVO.getTotalNum() : 0;// 下单件数
                int sumNum = Objects.nonNull(orderDO.getSumNum()) ? orderDO.getSumNum() : 0; // 入仓件数
                int timeTotalNum = Objects.nonNull(orderDO.getLastTimeTotalNum()) ? orderDO.getLastTimeTotalNum() : 0;
                int currentTotalNum = sumNum - timeTotalNum;
                if (currentTotalNum < 0) {
                    // 当因为拆单、退仓导致当次更新的入仓箱数为负数时，此值默认为0，只更新总入仓箱数
                    currentTotalNum = 0;
                }
                LogisticsInfoDto logisticsStartInfoDto = warehouseLineMapper.getStartInfoAndDestInfoByLineId(orderDO.getLineId());
                if (Objects.nonNull(logisticsStartInfoDto)) {
                    if (sumNum < placeOrderNum) {
                        // 入仓件数<下单件数
                        orderTimeDO.setRemarksZh(String.format(OrderSeaTimeEnum.SEA_IN_WAREHOUSE_REMARK.getRemarksZh(), logisticsStartInfoDto.getStartTitleZh(), currentTotalNum, sumNum));
//                        orderTimeDO.setRemarksZh(String.format(OrderSeaTimeEnum.SEA_IN_WAREHOUSE_REMARK.getRemarksZh(), logisticsStartInfoDto.getStartTitleZh(), sumNum));
                        orderTimeDO.setRemarksEn(String.format(OrderSeaTimeEnum.SEA_IN_WAREHOUSE_REMARK.getRemarksEn(), currentTotalNum, logisticsStartInfoDto.getStartQianzhui(), sumNum));
//                        orderTimeDO.setRemarksEn(String.format(OrderSeaTimeEnum.SEA_IN_WAREHOUSE_REMARK.getRemarksEn(), logisticsStartInfoDto.getStartTitleEn(), sumNum));
                    } else {
                        orderTimeDO.setMark(1); // 入仓件数>=下单件数，字体标红
                        orderTimeDO.setRemarksZh(String.format(orderSeaTimeEnum.getRemarksZh(), logisticsStartInfoDto.getStartTitleZh(), currentTotalNum, sumNum));
//                        orderTimeDO.setRemarksZh(String.format(orderSeaTimeEnum.getRemarksZh(), logisticsStartInfoDto.getStartTitleZh(), sumNum));
                        orderTimeDO.setRemarksEn(String.format(orderSeaTimeEnum.getRemarksEn(), currentTotalNum, logisticsStartInfoDto.getStartQianzhui(), sumNum));
//                        orderTimeDO.setRemarksEn(String.format(orderSeaTimeEnum.getRemarksEn(), logisticsStartInfoDto.getStartTitleEn(), sumNum));
                    }
                    orderTimeDO.setTotalNum(sumNum);// 更新当前入仓总件数;
                }
                break;
            case SEA_INSTALLED_CABINET:
                orderTimeDO.setMark(1); // 装柜字体标红
                orderTimeDO.setRemarksZh(String.format(orderSeaTimeEnum.getRemarksZh(), Objects.nonNull(estTime) ? DateUtil.formatDateTime(estTime) : ""));
                orderTimeDO.setRemarksEn(String.format(orderSeaTimeEnum.getRemarksEn(), Objects.nonNull(estTime) ? DateUtil.formatDateTime(estTime) : ""));
                break;
            case SEA_CUSTOMS_PASS_SEA:
                orderTimeDO.setRemarksZh(String.format(orderSeaTimeEnum.getRemarksZh(), Objects.nonNull(estTime) ? DateUtil.formatDateTime(estTime) : ""));
                orderTimeDO.setRemarksEn(String.format(orderSeaTimeEnum.getRemarksEn(), Objects.nonNull(estTime) ? DateUtil.formatDateTime(estTime) : ""));
                break;
            case SEA_HAS_TAKEN_OFF:
                orderTimeDO.setRemarksZh(String.format(orderSeaTimeEnum.getRemarksZh(), Objects.nonNull(estTime) ? DateUtil.formatDateTime(estTime) : ""));
                orderTimeDO.setRemarksEn(String.format(orderSeaTimeEnum.getRemarksEn(), Objects.nonNull(estTime) ? DateUtil.formatDateTime(estTime) : ""));
                break;
            case SEA_CLEARED:
                orderTimeDO.setMark(1); // 清关字体标红
                orderTimeDO.setRemarksZh(orderSeaTimeEnum.getRemarksZh());
                orderTimeDO.setRemarksEn(orderSeaTimeEnum.getRemarksEn());
                break;
            case SEA_UNLOADED_CABINET:
                orderTimeDO.setMark(1); // 到仓字体标红
                OrderObjectiveDO objectiveDO = orderObjectiveService.getByOrderId(orderDO.getOrderId());
                RegionDO objective = JSONObject.parseObject(objectiveDO.getObjective(), RegionDO.class);
                if (Objects.nonNull(objective)) {
                    orderTimeDO.setRemarksZh(String.format(orderSeaTimeEnum.getRemarksZh(), objective.getTitleZh()));
                    orderTimeDO.setRemarksEn(String.format(orderSeaTimeEnum.getRemarksEn(), objective.getTitleEn()));
                }
                // TODO 这里更新订单卸柜/到仓时间，同时对控货订单的限制修改收货人锁定到期时间进行更新，当前默认使用14D处理，待仓库业务添加该时间配置在做处理
                LogisticsInfoDto logisticsDestInfoDto = warehouseLineMapper.getStartInfoAndDestInfoByLineId(orderDO.getLineId());
                int lockConsigneeDay = Objects.nonNull(logisticsDestInfoDto) && Objects.nonNull(logisticsDestInfoDto.getDestLockRecipientDays()) ? logisticsDestInfoDto.getDestLockRecipientDays() : 0;
                Date lockConsigneeTime = null;
                if (orderDO.getIsCargoControl()) {
                    // TODO 获取卸柜/到仓业务时间的锁定收货人时间当天的结束时间
                    lockConsigneeTime = DateUtil.endOfDay(DateUtil.offsetDay(businessTime, lockConsigneeDay));
                }
                orderMapper.update(null, new LambdaUpdateWrapper<OrderDO>()
                        .set(OrderDO::getUnloadTime, businessTime)
                        .set(OrderDO::getLockConsigneeTime, lockConsigneeTime)
                        .set(OrderDO::getLockConsigneeDay, lockConsigneeDay)
                        .eq(OrderDO::getOrderId, orderDO.getOrderId()));
                break;
            case SEA_PICKED_UP:
                // 提货节点动态的原因参数分别为提货件数和提货剩余件数
                orderTimeDO.setRemarksZh(String.format(orderSeaTimeEnum.getRemarksZh(), reasonZh, reasonEn));
                orderTimeDO.setRemarksEn(String.format(orderSeaTimeEnum.getRemarksEn(), reasonZh, reasonEn));
                break;
            default:
                orderTimeDO.setRemarksZh(orderSeaTimeEnum.getRemarksZh());
                orderTimeDO.setRemarksEn(orderSeaTimeEnum.getRemarksEn());
                break;
        }
        orderTimeDO.setTitleZh(orderSeaTimeEnum.getNameZh());
        orderTimeDO.setTitleEn(orderSeaTimeEnum.getNameEn());
        if (Objects.isNull(orderTimeDO.getId())) {
            orderTimeMapper.insert(orderTimeDO);
        } else {
            orderTimeMapper.updateById(orderTimeDO);
        }
    }

    @Override
    public void addSeaOrderTimeLog(Collection<Long> orderIdList, OrderSeaTimeEnum orderSeaTimeEnum, String
            reasonZh, String reasonEn, Date estTime, Date businessTime, Date now) {
        List<OrderDO> orderDOList = orderMapper.selectList(new LambdaQueryWrapper<OrderDO>().in(OrderDO::getOrderId, orderIdList));
        if (CollectionUtil.isNotEmpty(orderDOList)) {
            for (OrderDO orderDO : orderDOList) {
                this.addSeaOrderTimeLog(orderDO, orderSeaTimeEnum, reasonZh, reasonEn, estTime, businessTime, now, null);
            }
        }
    }

    @Override
    public void addAirOrderTimeLog(Collection<Long> orderIdList, OrderAirTimeEnum orderAirTimeEnum, String
            reasonZh, String reasonEn, Date estTime, Date businessTime, Date now) {
        List<OrderDO> orderDOList = orderMapper.selectList(new LambdaQueryWrapper<OrderDO>().in(OrderDO::getOrderId, orderIdList));
        if (CollectionUtil.isNotEmpty(orderDOList)) {
            for (OrderDO orderDO : orderDOList) {
                this.addAirOrderTimeLog(orderDO, orderAirTimeEnum, reasonZh, reasonEn, estTime, businessTime, now, null);
            }
        }
    }

    @Override
    public void addAirOrderTimeLog(String containerNumber, OrderAirTimeEnum orderAirTimeEnum, String
            reasonZh, String reasonEn, Date estTime, Date businessTime, Date now) {
        List<OrderDO> orderDOList = orderMapper.selectList(new LambdaQueryWrapper<OrderDO>().eq(OrderDO::getContainerNumber, containerNumber));
        if (CollectionUtil.isNotEmpty(orderDOList)) {
            for (OrderDO orderDO : orderDOList) {
                this.addAirOrderTimeLog(orderDO, orderAirTimeEnum, reasonZh, reasonEn, estTime, businessTime, now, null);
            }
        }
    }


    public void addOrderTimeLog(Integer status, OrderDO orderDO, Integer type, Date businessTime) {
        Date now = new Date();
        this.addOrderTimeLogAndTime(status, orderDO, type, businessTime, now);
    }


    public void addOrderTimeLog(Integer status, OrderDO orderDO, Integer type, Date businessTime, Date now) {
        if (Objects.isNull(now)) {
            now = new Date();
        }
        this.addOrderTimeLogAndTime(status, orderDO, type, businessTime, now);
    }


    private void addOrderTimeLogAndTime(Integer status, OrderDO orderDO, Integer type, Date businessTime, Date now) {
        if (!Objects.equals(orderDO.getTransportId(), TransportTypeShortEnum.AIR_FREIGHT_LINE.getValue()) && !Objects.equals(orderDO.getTransportId(), TransportTypeShortEnum.SEA_CONTAINER.getValue())) {
            if (type != 0) {
                return;
            }
            // 主订单状态发生改变时存入日志
            OrderTimeDO orderTimeDO = new OrderTimeDO();
            orderTimeDO.setStatus(status);
            orderTimeDO.setType(0);
            orderTimeDO.setOrderId(orderDO.getOrderId());
            orderTimeDO.setBusinessTime(Objects.isNull(businessTime) ? now : businessTime);
            orderTimeDO.setCreateTime(now);
            orderTimeDO.setCreator(String.valueOf(SecurityFrameworkUtils.getLoginUserId()));
            orderTimeDO.setUpdateTime(now);
            OrderStatusEnum orderStatusEnum = OrderStatusEnum.valueOf(status);
            // 封装状态备注
            BoxOrderDynamicEstTimeEvent event = new BoxOrderDynamicEstTimeEvent(orderDO.getContainerNumber(), 0, null);
            String estTime = "";
            switch (orderStatusEnum) {
                case INSTALLED_CABINET:
                    // 查询出货订舱表 ecw_box_book_sea 获取预计开船时间
                    event.setType(10);
                    applicationContext.publishEvent(event);
                    estTime = Objects.nonNull(event.getEstTime()) ? DateUtil.formatDateTime(event.getEstTime()) : "";
                    break;
                case IN_SHIPPING:
                    // 查询出货起运表 ecw_box_shipping 获取预计到港时间
                    event.setType(11);
                    applicationContext.publishEvent(event);
                    estTime = Objects.nonNull(event.getEstTime()) ? DateUtil.formatDateTime(event.getEstTime()) : "";
                    break;
//            case ARRIVED:
//                // 查询出货清关表 ecw_box_clearance 获取预计清关时间
//                event.setType(12);
//                applicationContext.publishEvent(event);
//                break;
                case PART_PICKED_UP:
                    // 部分提货
                    estTime = Objects.nonNull(businessTime) ? DateUtil.formatDateTime(businessTime) : "";
                    break;
                case PICKED_UP:
                    // 全部提货
                    estTime = Objects.nonNull(businessTime) ? DateUtil.formatDateTime(businessTime) : "";
                    break;
                default:
                    break;
            }
            if (StringUtils.isNotBlank(estTime) && (StringUtils.isNotBlank(orderStatusEnum.getRemarksZh()) || StringUtils.isNotBlank(orderStatusEnum.getRemarksEn()))) {
                orderTimeDO.setRemarksZh(orderStatusEnum.getRemarksZh() + estTime);
                orderTimeDO.setRemarksEn(orderStatusEnum.getRemarksEn() + estTime);
            }
            orderTimeDO.setTitleZh((Objects.nonNull(orderDO.getPrefixStatusZh()) ? orderDO.getPrefixStatusZh() : "") + orderStatusEnum.getNameZh());
            orderTimeDO.setTitleEn((Objects.nonNull(orderDO.getPrefixStatusEn()) ? orderDO.getPrefixStatusEn() : "") + orderStatusEnum.getNameEn());
            orderTimeMapper.insert(orderTimeDO);
        }
    }


    private void handleOrderCargoControl(OrderConsignorDO consignorDO, OrderDO orderDO) {
        if (orderDO.getIsCargoControl()) {
            // 控货订单
            long count = orderCargoControlMapper.selectCount(new LambdaQueryWrapper<OrderCargoControlDO>()
                    .eq(OrderCargoControlDO::getOrderId, orderDO.getOrderId())
                    .eq(OrderCargoControlDO::getIsActual, 1));
            if (count == 0) {
                // 没有控货人，则新增发货人为默认控货人
                OrderCargoControlDO orderCargoControlDO = new OrderCargoControlDO();
                BeanUtils.copyProperties(consignorDO, orderCargoControlDO);
                orderCargoControlDO.setId(null); // 置空主键ID
                orderCargoControlDO.setDialCode(Integer.valueOf(consignorDO.getCountryCode()));
                orderCargoControlDO.setIso2(consignorDO.getCountryAbbreviation());
                orderCargoControlDO.setOrderNo(orderDO.getOrderNo());
                orderCargoControlDO.setTidanNo(orderDO.getTidanNo());
                orderCargoControlDO.setCreator(orderDO.getUpdater());
                orderCargoControlDO.setCreateTime(new Date());
                orderCargoControlDO.setIsActual(Boolean.TRUE);
                orderCargoControlMapper.insert(orderCargoControlDO);
            }
        } else {
            // 非控货订单
            long count = orderCargoControlMapper.selectCount(new LambdaQueryWrapper<OrderCargoControlDO>()
                    .eq(OrderCargoControlDO::getOrderId, orderDO.getOrderId()));
            if (count > 0) {
                // 有控货人，则删除控货人信息
                orderCargoControlMapper.update(null, new LambdaUpdateWrapper<OrderCargoControlDO>()
                        .set(OrderCargoControlDO::getDeleted, Boolean.TRUE)
                        .eq(OrderCargoControlDO::getOrderId, orderDO.getOrderId()));
            }
        }
    }


    @Override
    public void handleOrderRemindException(Long orderId, List<OrderRemindExceptionDto> remindExceptionDtoList) {
        OrderDO orderDO = orderMapper.selectById(orderId);
        if (orderDO == null) {
            throw exception(ORDER_NOT_EXISTS);
        }
        String exceptionReason = Objects.isNull(remindExceptionDtoList) || CollectionUtil.isEmpty(remindExceptionDtoList) ? null : JSONObject.toJSONString(remindExceptionDtoList);
        this.update(new LambdaUpdateWrapper<OrderDO>().set(OrderDO::getExceptionReason, exceptionReason)
                .set(OrderDO::getIsException, Objects.nonNull(exceptionReason))
                .eq(OrderDO::getOrderId, orderId));
        if (orderDO.getIsException() != Objects.nonNull(exceptionReason)) {
            // 更新订单操作日志
            this.addOrderOperateLog(orderId, "订单异常说明更新", null);
        }
    }

    @Override
    public void updateOrderCustomer(List<String> orderNumbers) {
        List<OrderDO> list = orderMapper.selectList(new LambdaQueryWrapper<OrderDO>()
                .in(CollectionUtil.isNotEmpty(orderNumbers), OrderDO::getOrderNo, orderNumbers)
                .eq(OrderDO::getDeleted, 0).ne(OrderDO::getStatus, 88));
//        List<OrderDO> list = orderMapper.selectList(new LambdaQueryWrapper<OrderDO>()
//                .and(we -> we.eq(OrderDO::getSalesmanId, 0)
//                        .or().isNull(OrderDO::getSalesmanId))
//                .eq(OrderDO::getDeleted, 0).notIn(OrderDO::getStatus, 0,88));
        log.info(JSONObject.toJSONString(list));
        List<String> bugList = new ArrayList<>();
        for (OrderDO orderDO : list) {
            OrderConsignorDO orderConsignorDO = orderConsignorService.getOne(new LambdaQueryWrapper<OrderConsignorDO>().eq(OrderConsignorDO::getOrderId, orderDO.getOrderId()).orderByDesc(OrderConsignorDO::getId).last("limit 1"));
            OrderConsigneeDO orderConsigneeDO = orderConsigneeService.getOne(new LambdaQueryWrapper<OrderConsigneeDO>().eq(OrderConsigneeDO::getOrderId, orderDO.getOrderId()).orderByDesc(OrderConsigneeDO::getId).last("limit 1"));
            updateConsignorAndConsignee(orderConsignorDO, orderConsigneeDO, orderDO, bugList);
            // TODO 判断是否需要更新业绩日志
            // TODO 判断是否需要更新操作日志
        }
        log.info("变更订单有：【{}】", JSONObject.toJSONString(bugList));
    }


    @Override
    public void updateReceivable(String orderNo) {
        log.info("手动创建或更新订单【{}】运费与清关费的应收单", orderNo);
        OrderDO orderDO = orderMapper.selectOne(new LambdaQueryWrapper<OrderDO>()
                .eq(OrderDO::getOrderNo, orderNo));
        List<OrderItemDO> orderItemDOList = orderItemMapper.selectList(new LambdaQueryWrapper<OrderItemDO>().eq(OrderItemDO::getOrderId, orderDO.getOrderId()));
        for (OrderItemDO orderItemDO : orderItemDOList) {
            if (Objects.isNull(orderItemDO.getWarehouseInInfoVO()) || orderItemDO.getWarehouseInInfoVO().getCartonsNum() == 0) {
                continue;
            }
            ReceivableDO freightReceivable = receivableService.getReceivableByOrderItemId(orderItemDO.getOrderItemId(), 1);
            if (Objects.isNull(freightReceivable)) {
                this.createReceivable(orderDO, orderItemDO, 1, orderItemDO.getOneSeaFreight(), orderItemDO.getSeaFreight(), orderItemDO.getSeaFreightCurrency());
            }
            if (orderItemDO.getCharging() == 0) {
                ReceivableDO clearanceReceivable = receivableService.getReceivableByOrderItemId(orderItemDO.getOrderItemId(), 2);
                if (Objects.isNull(clearanceReceivable)) {
                    this.createReceivable(orderDO, orderItemDO, 2, orderItemDO.getOneClearanceFreight(), orderItemDO.getClearanceFreight(), orderItemDO.getClearanceFreightCurrency());
                }
            }
        }
    }

    @Override
    public void updateOrderPrice(List<String> orderNumbers, Boolean isResetPrice) {
        Long userId = SecurityFrameworkUtils.getLoginUserId();
//        List<ReceivableDO> receivableDOList = receivableService.list(new LambdaQueryWrapper<ReceivableDO>()
//                .eq(ReceivableDO::getTotalAmount, BigDecimal.ZERO)
//                .eq(ReceivableDO::getFeeSource, 1));
//        if (Objects.nonNull(receivableDOList) && CollectionUtil.isNotEmpty(receivableDOList)) {
//            orderNumbers = receivableDOList.stream().map(ReceivableDO::getOrderNo).distinct().collect(Collectors.toList());
        List<OrderDO> list = orderMapper.selectList(new LambdaQueryWrapper<OrderDO>()
                .in(CollectionUtil.isNotEmpty(orderNumbers), OrderDO::getOrderNo, orderNumbers)
//                        .isNotNull(OrderDO::getParentOrderId) // 子订单
//                        .ne(OrderDO::getParentOrderId, 0)
//                        .between(OrderDO::getCreateTime, "2023-01-25 00:00:00", "2023-02-14 00:00:00")
                .eq(OrderDO::getDeleted, 0).notIn(OrderDO::getStatus, 0, 88));
//        List<OrderDO> list = orderMapper.selectList(new LambdaQueryWrapper<OrderDO>()
//                        .and(we -> we.gt(OrderDO::getMinMeteringVolume, 0)
//                                .or().gt(OrderDO::getMinMeteringWeight, 0)
//                                .or().gt(OrderDO::getMinMeteringQuantity, 0))
//                .eq(OrderDO::getDeleted, 0).notIn(OrderDO::getStatus, 0,88));
        log.info(JSONObject.toJSONString(list));

        for (OrderDO orderDO : list) {
            OrderConsignorDO orderConsignorDO = orderConsignorService.getOne(new LambdaQueryWrapper<OrderConsignorDO>().eq(OrderConsignorDO::getOrderId, orderDO.getOrderId()).orderByDesc(OrderConsignorDO::getId).last("limit 1"));
            OrderConsigneeDO orderConsigneeDO = orderConsigneeService.getOne(new LambdaQueryWrapper<OrderConsigneeDO>().eq(OrderConsigneeDO::getOrderId, orderDO.getOrderId()).orderByDesc(OrderConsigneeDO::getId).last("limit 1"));
            List<OrderItemDO> orderItemDOList = orderItemMapper.selectList(new LambdaQueryWrapper<OrderItemDO>().eq(OrderItemDO::getOrderId, orderDO.getOrderId()));
            this.costCalculation(userId.toString(), orderDO, orderConsignorDO.getCustomerId(), Objects.isNull(orderConsigneeDO) ? 0L : orderConsigneeDO.getCustomerId(),
                    orderConsignorDO.getCustomerContactsId(), Objects.isNull(orderConsigneeDO) ? 0L : orderConsigneeDO.getCustomerContactsId(), orderItemDOList, isResetPrice ? 20 : 8);
            // TODO 此处是否需要更新操作日志
        }
//        }
    }

    private void updateConsignorAndConsignee(OrderConsignorDO orderConsignorDO, OrderConsigneeDO
            orderConsigneeDO, OrderDO orderDO, List<String> bugList) {
        boolean flag = false;
        CustomerDO consignorDO = null;
        CustomerDO consigneeDO = null;
        CustomerContactsDO consignorContactsDO = customerContactsService.getCustomerContacts(orderConsignorDO.getCustomerContactsId());
        if (Objects.isNull(consignorContactsDO)) {
            CustomerContactsDO newConsignorContactsDO = customerContactsService.getOne(new LambdaQueryWrapper<CustomerContactsDO>()
                    .eq(Objects.isNull(orderDO.getUserId()) || 0L == orderDO.getUserId(), CustomerContactsDO::getPhoneNew, orderConsignorDO.getPhone())
                    .eq(Objects.nonNull(orderDO.getUserId()) && orderDO.getUserId() > 0, CustomerContactsDO::getUserid, orderDO.getUserId())
                    .eq(CustomerContactsDO::getDeleted, 0)
                    .orderByDesc(CustomerContactsDO::getId)
                    .last("limit 1"));
            if (Objects.nonNull(newConsignorContactsDO)) {
                consignorDO = customerService.getCustomer(newConsignorContactsDO.getCustomerId());
                log.info("订单【{}】，更新发货人联系人id-[{}]->[{}]和客户id-[{}]->[{}]",
                        orderDO.getOrderNo(), orderConsignorDO.getCustomerContactsId(), newConsignorContactsDO.getId(),
                        orderConsignorDO.getCustomerId(), newConsignorContactsDO.getCustomerId());
                if (Objects.nonNull(consignorDO)) {
                    orderConsignorDO.setCompany(consignorDO.getCompany());
                    CountryDO consignorCountryDO = countryService.getById(consignorDO.getCountry());
                    orderConsignorDO.setCountryAbbreviation(Objects.isNull(consignorCountryDO) ? null : consignorCountryDO.getNameShort());
                }
                orderConsignorDO.setName(newConsignorContactsDO.getName());
                orderConsignorDO.setCountryCode(newConsignorContactsDO.getAreaCode());
                orderConsignorDO.setEmail(newConsignorContactsDO.getEmail());
                orderConsignorDO.setPhone(newConsignorContactsDO.getPhoneNew());
                orderConsignorDO.setCustomerContactsId(newConsignorContactsDO.getId());
                orderConsignorDO.setCustomerId(newConsignorContactsDO.getCustomerId());
                orderConsignorService.updateById(orderConsignorDO);
                flag = true;
            } else {
                String msg = MessageFormat.format("订单【{0}】未找到对应的发货人信息", orderDO.getOrderNo());
                bugList.add(msg);
                log.error(msg);
            }
        } else {
            if (!StringUtils.equals(consignorContactsDO.getPhoneNew(), orderConsignorDO.getPhone())) {
                CustomerContactsDO newConsignorContactsDO = customerContactsService.getOne(new LambdaQueryWrapper<CustomerContactsDO>()
                        .eq(Objects.isNull(orderDO.getUserId()) || 0L == orderDO.getUserId(), CustomerContactsDO::getPhoneNew, orderConsignorDO.getPhone())
                        .eq(Objects.nonNull(orderDO.getUserId()) && orderDO.getUserId() > 0, CustomerContactsDO::getUserid, orderDO.getUserId())
                        .eq(CustomerContactsDO::getDeleted, 0)
                        .orderByDesc(CustomerContactsDO::getId)
                        .last("limit 1"));
                if (Objects.nonNull(newConsignorContactsDO)) {
                    consignorDO = customerService.getCustomer(newConsignorContactsDO.getCustomerId());
                    log.info("订单【{}】，更新发货人联系人id-[{}]->[{}]和客户id-[{}]->[{}]",
                            orderDO.getOrderNo(), orderConsignorDO.getCustomerContactsId(), newConsignorContactsDO.getId(),
                            orderConsignorDO.getCustomerId(), newConsignorContactsDO.getCustomerId());
                    if (Objects.nonNull(consignorDO)) {
                        orderConsignorDO.setCompany(consignorDO.getCompany());
                        CountryDO consignorCountryDO = countryService.getById(consignorDO.getCountry());
                        orderConsignorDO.setCountryAbbreviation(Objects.isNull(consignorCountryDO) ? null : consignorCountryDO.getNameShort());
                    }
                    orderConsignorDO.setName(newConsignorContactsDO.getName());
                    orderConsignorDO.setCountryCode(newConsignorContactsDO.getAreaCode());
                    orderConsignorDO.setEmail(newConsignorContactsDO.getEmail());
                    orderConsignorDO.setPhone(newConsignorContactsDO.getPhoneNew());
                    orderConsignorDO.setCustomerContactsId(newConsignorContactsDO.getId());
                    orderConsignorDO.setCustomerId(newConsignorContactsDO.getCustomerId());
                    orderConsignorService.updateById(orderConsignorDO);
                    flag = true;
                } else {
                    String msg = MessageFormat.format("订单【{0}】未找到对应的发货人信息", orderDO.getOrderNo());
                    bugList.add(msg);
                    log.error(msg);
                }
            } else {
                if (!Objects.equals(consignorContactsDO.getCustomerId(), orderConsignorDO.getCustomerId())) {
                    consignorDO = customerService.getCustomer(consignorContactsDO.getCustomerId());
                    log.info("订单【{}】，更新发货人客户id-[{}]->[{}]",
                            orderDO.getOrderNo(), orderConsignorDO.getCustomerId(), consignorContactsDO.getCustomerId());
                    if (Objects.nonNull(consignorDO)) {
                        orderConsignorDO.setCompany(consignorDO.getCompany());
                        CountryDO consignorCountryDO = countryService.getById(consignorDO.getCountry());
                        orderConsignorDO.setCountryAbbreviation(Objects.isNull(consignorCountryDO) ? null : consignorCountryDO.getNameShort());
                    }
                    orderConsignorService.updateById(orderConsignorDO);
                    flag = true;
                }
            }
        }


        if (orderDO.getIsCargoControl() && flag && !Objects.equals(orderDO.getStatus(), OrderStatusEnum.DRAFT.getValue())) {
            OrderCargoControlDO orgOrderCargoControlDO = orderCargoControlMapper.selectOne(new LambdaQueryWrapper<OrderCargoControlDO>().eq(OrderCargoControlDO::getOrderId, orderDO.getOrderId()).eq(OrderCargoControlDO::getIsActual, Boolean.TRUE).last("limit 1"));
            if (Objects.nonNull(orgOrderCargoControlDO)) {
                log.info("更新订单【{}】的控货信息", orderDO.getOrderNo());
                // 控货订单 添加控货人信息
                OrderCargoControlDO orderCargoControlDO = new OrderCargoControlDO();
                orderConsignorDO.setId(null);
                BeanUtils.copyProperties(orderConsignorDO, orderCargoControlDO);
                orderCargoControlDO.setDialCode(Integer.valueOf(orderConsignorDO.getCountryCode()));
                orderCargoControlDO.setIso2(orderConsignorDO.getCountryAbbreviation());
                orderCargoControlDO.setOrderNo(orderDO.getOrderNo());
                orderCargoControlDO.setTidanNo(orderDO.getTidanNo());
                orderCargoControlDO.setIsActual(Boolean.TRUE);
                orderCargoControlDO.setId(orgOrderCargoControlDO.getId());
                orderCargoControlMapper.updateById(orderCargoControlDO);
            }
        }

        CustomerContactsDO consigneeContactsDO = customerContactsService.getCustomerContacts(Objects.isNull(orderConsigneeDO) ? 0L : orderConsigneeDO.getCustomerContactsId());
        if (Objects.isNull(consigneeContactsDO) && Objects.nonNull(orderConsigneeDO)) {
            CustomerContactsDO newConsigneeContactsDO = customerContactsService.getUniqueOneAndValidate(orderConsigneeDO.getCountryCode(), orderConsigneeDO.getPhone(), null);
            if (Objects.nonNull(newConsigneeContactsDO)) {
                consigneeDO = customerService.getCustomer(newConsigneeContactsDO.getCustomerId());
                log.info("订单【{}】，更新收货人联系人id-[{}]->[{}]和客户id-[{}]->[{}]",
                        orderDO.getOrderNo(), orderConsigneeDO.getCustomerContactsId(), newConsigneeContactsDO.getId(),
                        orderConsigneeDO.getCustomerId(), newConsigneeContactsDO.getCustomerId());
                if (Objects.nonNull(consigneeDO)) {
                    orderConsigneeDO.setCompany(consigneeDO.getCompany());
                    CountryDO consigneeCountryDO = countryService.getById(consigneeDO.getCountry());
                    orderConsigneeDO.setCountryAbbreviation(Objects.isNull(consigneeCountryDO) ? null : consigneeCountryDO.getNameShort());
                }
                orderConsigneeDO.setName(newConsigneeContactsDO.getName());
                orderConsigneeDO.setCountryCode(newConsigneeContactsDO.getAreaCode());
                orderConsigneeDO.setEmail(newConsigneeContactsDO.getEmail());
                orderConsigneeDO.setPhone(newConsigneeContactsDO.getPhoneNew());
                orderConsigneeDO.setCustomerContactsId(newConsigneeContactsDO.getId());
                orderConsigneeDO.setCustomerId(newConsigneeContactsDO.getCustomerId());
                orderConsigneeService.updateById(orderConsigneeDO);
            } else {
                String msg = MessageFormat.format("订单【{0}】未找到对应的收货人信息", orderDO.getOrderNo());
                bugList.add(msg);
                log.error(msg);
            }
        } else {
            if (Objects.nonNull(orderConsigneeDO) && !StringUtils.equals(consigneeContactsDO.getPhoneNew(), orderConsigneeDO.getPhone())) {
                CustomerContactsDO newConsigneeContactsDO = customerContactsService.getUniqueOneAndValidate(orderConsigneeDO.getCountryCode(), orderConsigneeDO.getPhone(), null);
                if (Objects.nonNull(newConsigneeContactsDO)) {
                    consigneeDO = customerService.getCustomer(newConsigneeContactsDO.getCustomerId());
                    log.info("订单【{}】，更新收货人联系人id-[{}]->[{}]和客户id-[{}]->[{}]",
                            orderDO.getOrderNo(), orderConsigneeDO.getCustomerContactsId(), newConsigneeContactsDO.getId(),
                            orderConsigneeDO.getCustomerId(), newConsigneeContactsDO.getCustomerId());
                    if (Objects.nonNull(consigneeDO)) {
                        orderConsigneeDO.setCompany(consigneeDO.getCompany());
                        CountryDO consigneeCountryDO = countryService.getById(consigneeDO.getCountry());
                        orderConsigneeDO.setCountryAbbreviation(Objects.isNull(consigneeCountryDO) ? null : consigneeCountryDO.getNameShort());
                    }
                    orderConsigneeDO.setName(newConsigneeContactsDO.getName());
                    orderConsigneeDO.setCountryCode(newConsigneeContactsDO.getAreaCode());
                    orderConsigneeDO.setEmail(newConsigneeContactsDO.getEmail());
                    orderConsigneeDO.setPhone(newConsigneeContactsDO.getPhoneNew());
                    orderConsigneeDO.setCustomerContactsId(newConsigneeContactsDO.getId());
                    orderConsigneeDO.setCustomerId(newConsigneeContactsDO.getCustomerId());
                    orderConsigneeService.updateById(orderConsigneeDO);
                } else {
                    String msg = MessageFormat.format("订单【{0}】未找到对应的收货人信息", orderDO.getOrderNo());
                    bugList.add(msg);
                    log.error(msg);
                }
            } else {
                if (Objects.isNull(orderConsigneeDO) || !Objects.equals(consigneeContactsDO.getCustomerId(), orderConsigneeDO.getCustomerId())) {
                    consigneeDO = customerService.getCustomer(consigneeContactsDO.getCustomerId());
                    log.info("订单【{}】，更新收货人客户id-[{}]->[{}]",
                            orderDO.getOrderNo(), Objects.isNull(orderConsigneeDO) ? 0L : orderConsigneeDO.getCustomerId(), consigneeContactsDO.getCustomerId());
                    if (Objects.nonNull(consigneeDO)) {
                        orderConsigneeDO.setCompany(consigneeDO.getCompany());
                        CountryDO consigneeCountryDO = countryService.getById(consigneeDO.getCountry());
                        orderConsigneeDO.setCountryAbbreviation(Objects.isNull(consigneeCountryDO) ? null : consigneeCountryDO.getNameShort());
                    }
                    orderConsigneeService.updateById(orderConsigneeDO);
                }
            }

        }
        OrderAssociationOfferInfoEvent event = new OrderAssociationOfferInfoEvent(orderDO.getOrderId(), null);
        applicationContext.publishEvent(event);
        checkOrderSalesman(orderDO, event.getOfferId(), consignorDO, consigneeDO, orderConsignorDO, orderConsigneeDO);

        // 判断该订单、该客户是否有未分配客户异常，如果有，则这个订单不计算业绩
        List<OrderExceptionDO> orderExceptionDOList =
                orderExceptionService.getOrderExceptionByCustomerId(
                        orderDO.getCustomerId());
        // 获取当前订单的异常
        OrderExceptionDO currentOrderException = orderExceptionDOList.stream()
                .filter(orderExceptionDO -> Objects.equals(orderExceptionDO.getOrderId(), orderDO.getOrderId())).findFirst().orElse(null);
        if (Objects.isNull(currentOrderException) && Objects.nonNull(orderDO.getCustomerId()) && orderDO.getCustomerId() > 0) {
            CustomerDO customerDO = customerService.getById(orderDO.getCustomerId());
            orderDO.setIsInOpenSea(customerDO.getIsInOpenSea());
            orderDO.setYejiType(customerDO.getIsNew() ? 1 : 0);
            // 订单所属客户变更，则需要变更业绩归属
            // 更新所属客户经理(业务员)
            if (Objects.nonNull(customerDO) && Objects.nonNull(customerDO.getCustomerService()) && customerDO.getIsCustomerServiceConfirmed() && !customerDO.getIsInOpenSea()) {
                log.info("订单【{}】,客户经理变动[{}]->[{}]", orderDO.getOrderNo(), orderDO.getSalesmanId(), customerDO.getCustomerService());
                orderDO.setSalesmanId(customerDO.getIsInOpenSea() ? 0L : customerDO.getCustomerService());
                AdminUserRespDTO adminUserRespDTO = adminUserApi.getUser(customerDO.getCustomerService());
                if (Objects.nonNull(adminUserRespDTO)) {
                    orderDO.setDeptId(adminUserRespDTO.getDeptId());
                } else {
                    orderDO.setDeptId(0L);
                }
            } else {
                orderDO.setSalesmanId(0L);
                orderDO.setDeptId(0L);
            }
        }
        orderMapper.updateById(orderDO);
    }

    public int checkOrderSalesman(OrderDO order, Long offerId, CustomerDO consignorDO, CustomerDO consigneeDO, OrderConsignorDO orderConsignorDO, OrderConsigneeDO orderConsigneeDO) {
        int customerType = 1; //1-业绩归属发货人，2-业绩归属收货人
        if (Objects.isNull(orderConsigneeDO)) {//订单收货人
            orderConsigneeDO = orderConsigneeService.getOne(new LambdaQueryWrapper<OrderConsigneeDO>().eq(OrderConsigneeDO::getOrderId, order.getOrderId()).orderByDesc(OrderConsigneeDO::getId).last("limit 1"));
        }
        if (Objects.isNull(orderConsignorDO)) {//订单发货人
            orderConsignorDO = orderConsignorService.getOne(new LambdaQueryWrapper<OrderConsignorDO>().eq(OrderConsignorDO::getOrderId, order.getOrderId()).orderByDesc(OrderConsignorDO::getId).last("limit 1"));
        }
        if (Objects.isNull(consignorDO)) {//发货人客户
            consignorDO = customerService.getCustomer(orderConsignorDO.getCustomerId());
        }
        if (Objects.isNull(consigneeDO) && Objects.nonNull(orderConsigneeDO)) {
            consigneeDO = customerService.getCustomer(orderConsigneeDO.getCustomerId());//收货人客户
        }
        // 原客户经理

        Long orgCustomerId = Objects.isNull(order.getCustomerId()) ? 0L : order.getCustomerId();

        if (Objects.nonNull(order.getType()) && order.getType().contains("2")) {//层级1
            // 海外仓归属发货人
            order.setCustomerId(orderConsignorDO.getCustomerId());
        } else {
            if (consignorDO != null && !consignorDO.getNoConsignee() && !order.getHasConsignee()) {//发货人档案设置控货无收货人且订单无收获人，归属发货人业绩 -- 层级2
                order.setCustomerId(orderConsignorDO.getCustomerId());
            } else {
                if (order.getDrawee() == 1) {//发货人付款
                    if (order.getDrawee() == 1 && offerId != null) {//如果是发货人付款且关联报价单，业绩归属发货人 --层级3 第一个
                        order.setCustomerId(orderConsignorDO.getCustomerId());
                    } else if (order.getDrawee() == 1 && consignorDO.getDefaultPay()) {// 如果是发货人付款且档案设置默认付运费  --层级4 第一个
                        order.setCustomerId(orderConsignorDO.getCustomerId());
                    } else {
                        order.setCustomerId(Objects.nonNull(orderConsigneeDO) && orderConsigneeDO.getCustomerId() != null ? orderConsigneeDO.getCustomerId() : 0);
                        customerType = 2;
                    }
                } else if (order.getDrawee() == 2) {//收货人付款   层级5 第一个
                    if (consigneeDO != null) {
                        order.setCustomerId(orderConsigneeDO.getCustomerId());
                    } else {
                        //没有收货人
                        order.setCustomerId(0L);
                        order.setSalesmanId(0L);
                        order.setDeptId(0L);
                        customerType = 0;
                    }
                } else if (order.getDrawee() == 3) { //自定义付款
                    List<CustomDraweeVO> list = JSONObject.parseArray(order.getCustomDrawee(), CustomDraweeVO.class);
                    if (CollectionUtil.isNotEmpty(list)) {

                        List<CustomDraweeVO> freightList = list.stream().filter(s -> s.getName().equals("freight")).collect(Collectors.toList());
                        List<CustomDraweeVO> clearanceFeeList = list.stream().filter(s -> s.getName().equals("clearanceFee")).collect(Collectors.toList());
                        int freight = freightList.get(0).getValue();//运费
                        int clearanceFee = clearanceFeeList.get(0).getValue();//清关费
                        if (offerId != null && (order.getDrawee() == 3 && freight == 1)) {//层级3 第二个 订单关联报价单 && 自定义付款 且发货人付运费
                            order.setCustomerId(orderConsignorDO.getCustomerId());
                        } else if (offerId != null && (order.getDrawee() == 3 && clearanceFee == 1)) {//层级3 第三个 订单关联报价单 && 自定义付款 且发货人付清关费

                            order.setCustomerId(orderConsignorDO.getCustomerId());
                        } else if (consignorDO.getDefaultPay() && (order.getDrawee() == 3 && freight == 1)) { //层级4 第二个 发货人档案设置默认付运费 且发货人付运费 业绩归属 发货人
                            order.setCustomerId(orderConsignorDO.getCustomerId());
                        } else if (consignorDO.getDefaultPay() && (order.getDrawee() == 3 && clearanceFee == 1)) {// 层级4 第三个 发货人档案设置默认付运费 且发货人付清关费  业绩归属发货人
                            order.setCustomerId(orderConsignorDO.getCustomerId());
                        } else {
                            //去掉层级5、6 ，以上不符合的都归收货人
                            order.setCustomerId(Objects.nonNull(orderConsigneeDO) && orderConsigneeDO.getCustomerId() != null ? orderConsigneeDO.getCustomerId() : 0);
                            customerType = 2;
                        }
                    }
                } else {
                    //业绩归收货人
                    order.setCustomerId(Objects.nonNull(orderConsigneeDO) && orderConsigneeDO.getCustomerId() != null ? orderConsigneeDO.getCustomerId() : 0);
                    customerType = 2;
                }
            }
        }
        // 订单修改是否变动了归属客户，此字段用来判定订单是否需要重置归属客户经理，下单后归属客户的客户经理是固定的，除非订单归属客户变动，才需要重置客户经理
        order.setIsChargeCustomer(!Objects.equals(order.getCustomerId(), orgCustomerId));
        return customerType;
    }

    @Override
    public void updateOrderOrgWeightUnitAndOrgVolumeUnit(List<String> orderNumbers) {
        List<OrderDO> orderDOList = orderMapper.selectList(new LambdaQueryWrapper<OrderDO>()
                .in(CollectionUtil.isNotEmpty(orderNumbers), OrderDO::getOrderNo, orderNumbers)
                .eq(OrderDO::getDeleted, 0).notIn(OrderDO::getStatus, 0));
        if (CollectionUtil.isNotEmpty(orderDOList)) {
            for (OrderDO orderDO : orderDOList) {
                OrderConsignorDO orderConsignorDO = orderConsignorService.getOne(new LambdaQueryWrapper<OrderConsignorDO>().eq(OrderConsignorDO::getOrderId, orderDO.getOrderId()).orderByDesc(OrderConsignorDO::getId).last("limit 1"));
                OrderConsigneeDO orderConsigneeDO = orderConsigneeService.getOne(new LambdaQueryWrapper<OrderConsigneeDO>().eq(OrderConsigneeDO::getOrderId, orderDO.getOrderId()).orderByDesc(OrderConsigneeDO::getId).last("limit 1"));
                LogisticsInfoDto logisticsInfoDto = warehouseLineMapper.getStartInfoAndDestInfoByLineId(orderDO.getLineId());
                if (Objects.isNull(logisticsInfoDto)) {
                    throw exception(TRANSPORT_LINE_NOT_EXISTS);
                }
                CustomerZhongPaoQueryVO customerZhongPaoQueryVO = new CustomerZhongPaoQueryVO();
                customerZhongPaoQueryVO.setConsignorId(orderConsignorDO.getCustomerId());
                customerZhongPaoQueryVO.setConsigneeId(Objects.nonNull(orderConsigneeDO) ? orderConsigneeDO.getCustomerId() : 0L);
                customerZhongPaoQueryVO.setDepartureId(logisticsInfoDto.getStartCityId());
                customerZhongPaoQueryVO.setObjectiveId(logisticsInfoDto.getDestCityId());
                customerZhongPaoQueryVO.setStartWarehouseId(logisticsInfoDto.getStartWarehouseId());
                customerZhongPaoQueryVO.setDestWarehouseId(logisticsInfoDto.getDestWarehouseId());
                ZhongPaoBestVO zhongPaoBestVO = zhongPaoService.getCustomerBestZhongPao(customerZhongPaoQueryVO);
                // 判断订单是否入仓
                if (orderDO.getSumNum() > 0) {
                    if (Objects.isNull(orderDO.getOrgWeightUnit()) || orderDO.getOrgWeightUnit().compareTo(BigDecimal.ZERO) == 0) {
                        // 更新当前的重货标准为原始标准
                        orderDO.setOrgWeightUnit(zhongPaoBestVO.getZhongEdge());
                    }
                    if (Objects.isNull(orderDO.getOrgVolumeUnit()) || orderDO.getOrgVolumeUnit().compareTo(BigDecimal.ZERO) == 0) {
                        //更新当前的泡货标准为原始标准
                        orderDO.setOrgVolumeUnit(zhongPaoBestVO.getPaoEdge());
                    }
                }
            }
            this.updateBatch(orderDOList);
        }
    }

    @Override
    public void addOrderOperateLog(Long orderId, String msg, String note) {
        this.convertOrderOperateLog(orderId, "订单操作", msg, note);
    }

    @Override
    public void addOrderOperateLog(Long orderId, String type, String msg, String note) {
        convertOrderOperateLog(orderId, StringUtils.isNotBlank(type) ? type : "订单操作", msg, note);
    }

    @Override
    public void addOrderOperateLog(Long orderId, String type, String msg, List<ApplyInfoVO> applyInfoVOList) {
        convertOrderOperateLog(orderId, StringUtils.isNotBlank(type) ? type : "订单操作", msg, Objects.isNull(applyInfoVOList) ? null : JSONObject.toJSONString(applyInfoVOList));
    }

    private void convertOrderOperateLog(Long orderId,
                                        String type,
                                        String msg,
                                        String note) {
        OrderOperateLogCreateReqVO reqVO = new OrderOperateLogCreateReqVO();
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        // 获得 Request 对象
        HttpServletRequest request = ServletUtils.getRequest();
        if (Objects.nonNull(request)) {
            reqVO.setRequestUrl(request.getRequestURI());
        } else {
            reqVO.setRequestUrl("task/job");
        }
        if (StringUtils.isNotBlank(note)) {
            reqVO.setNote(note);
        }
        reqVO.setMsg(msg);
        reqVO.setType(type);
        reqVO.setOrderId(orderId);
        reqVO.setBody(JSONObject.toJSONString(orderQueryService.info(orderId)));
        reqVO.setCreator(String.valueOf(Objects.isNull(loginUser) ? "0" : loginUser.getId()));
        reqVO.setCreatorName(Objects.isNull(loginUser) ? "系统" : loginUser.getNickname());
        reqVO.setUserType(Objects.isNull(loginUser) ? 2 : loginUser.getUserType());
        orderOperateLogService.createOrderAsyncOperateLog(reqVO);
    }

    @Override
    public long getUnWriteOffCount(Collection<Long> orderIds) {
        return receivableService.count(new LambdaQueryWrapper<ReceivableDO>()
                .in(ReceivableDO::getOrderId, orderIds)
                .ne(ReceivableDO::getState, 2)

        );
    }


    public void createOrderControlLog(Long orderId, Integer typeKey, String type, String msg, Long approvalId) {
        OrderControlLogCreateReqVO reqVO = new OrderControlLogCreateReqVO();
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        // 获得 Request 对象
        HttpServletRequest request = ServletUtils.getRequest();
        if (Objects.nonNull(request)) {
            reqVO.setRequestUrl(request.getRequestURI());
        }
        reqVO.setMsg(msg);
        reqVO.setTypeKey(typeKey);
        reqVO.setType(type);
        reqVO.setOrderId(orderId);
        reqVO.setApprovalId(approvalId);
        reqVO.setCreator(String.valueOf(Objects.isNull(loginUser) ? "0" : loginUser.getId()));
        reqVO.setCreatorName(Objects.isNull(loginUser) ? "未知" : loginUser.getNickname());
        reqVO.setUserType(Objects.isNull(loginUser) ? 2 : loginUser.getUserType());
        orderControlLogService.createOrderControlLog(reqVO);
    }

    @Override
    public void createOrderControlLogs(List<OrderControlLogParam> controlLogParams) {

        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        // 获得 Request 对象
        HttpServletRequest request = ServletUtils.getRequest();
        List<OrderControlLogCreateReqVO> createReqVOList = new ArrayList<>();
        for (OrderControlLogParam controlLogParam : controlLogParams) {
            OrderControlLogCreateReqVO reqVO = new OrderControlLogCreateReqVO();
            if (Objects.nonNull(request)) {
                reqVO.setRequestUrl(request.getRequestURI());
            }
            reqVO.setCreator(String.valueOf(Objects.isNull(loginUser) ? "0" : loginUser.getId()));
            reqVO.setCreatorName(Objects.isNull(loginUser) ? "未知" : loginUser.getNickname());
            reqVO.setUserType(Objects.isNull(loginUser) ? 2 : loginUser.getUserType());
            reqVO.setMsg(controlLogParam.getMsg());
            reqVO.setType(controlLogParam.getType());
            reqVO.setOrderId(controlLogParam.getOrderId());
            reqVO.setApprovalId(controlLogParam.getApprovalId());
            createReqVOList.add(reqVO);
        }
        orderControlLogService.batchCreateOrderControlLogs(createReqVOList);
    }

    @Override
    public void orderCouponUpdate(OrderDO orderDO, String msg) {
        List<OrderItemDO> orderItemDOList = orderItemMapper.selectList(new LambdaQueryWrapper<OrderItemDO>().eq(OrderItemDO::getOrderId, orderDO.getOrderId()).eq(OrderItemDO::getDeleted, false));
        String userId = String.valueOf(SecurityFrameworkUtils.getLoginUserId());
        OrderConsignorDO orderConsignorDO = orderConsignorService.getOne(new LambdaQueryWrapper<OrderConsignorDO>().eq(OrderConsignorDO::getOrderId, orderDO.getOrderId()).orderByDesc(OrderConsignorDO::getId).last("limit 1"));
        OrderConsigneeDO orderConsigneeDO = orderConsigneeService.getOne(new LambdaQueryWrapper<OrderConsigneeDO>().eq(OrderConsigneeDO::getOrderId, orderDO.getOrderId()).orderByDesc(OrderConsigneeDO::getId).last("limit 1"));
        this.costCalculation(userId, orderDO,
                orderConsignorDO.getCustomerId(),
                Objects.isNull(orderConsigneeDO)? 0L : orderConsigneeDO.getCustomerId(),
                orderConsignorDO.getCustomerContactsId(),
                Objects.isNull(orderConsigneeDO)? 0L : orderConsigneeDO.getCustomerContactsId(),
                orderItemDOList, 50);
        this.addOrderOperateLog(orderDO.getOrderId(),
                "有活动更新订单计价", null);
    }


    //14 是批量加价
    //15 是费用计算
    //10 入仓更新
    //30 空运定时刷新价格
    public void costCalculation(String userId,
                                OrderDO orderDO,
                                Long consignorCustomerId,
                                Long consigneeCustomerId,
                                Long consignorCustomerContactsId,
                                Long consigneeCustomerContactsId,
                                List<OrderItemDO> orderItemDOList,
                                Integer type) {

        //2023-7月之前应收金额没有按四舍五入取整，之后都是按四舍五入取整处理的
        //空运运费根据产品阶梯价来取值，清关费根据路线和包装类型取值，谁大取谁

        LogisticsInfoDto logisticsInfoDto =
                warehouseLineMapper.getStartInfoAndDestInfoByLineId(
                        orderDO.getLineId());

        if (Objects.isNull(logisticsInfoDto)) {
            throw exception(TRANSPORT_LINE_NOT_EXISTS);
        }

        QueryChannelInfoEvent event = new QueryChannelInfoEvent();
        if (Objects.nonNull(orderDO.getChannelId()) && orderDO.getChannelId() > 0) {
            event.setChannelId(orderDO.getChannelId());
            applicationContext.publishEvent(event);
        }
        CustomerZhongPaoQueryVO customerZhongPaoQueryVO =
                new CustomerZhongPaoQueryVO();
        customerZhongPaoQueryVO.setDepartureId(logisticsInfoDto.getStartCityId());
        customerZhongPaoQueryVO.setObjectiveId(logisticsInfoDto.getDestCityId());
        customerZhongPaoQueryVO.setStartWarehouseId(logisticsInfoDto.getStartWarehouseId());
        customerZhongPaoQueryVO.setDestWarehouseId(logisticsInfoDto.getDestWarehouseId());
        // 先获取全局重泡货配置
        ZhongPaoBestVO orgZhongPaoBestVO =
                zhongPaoService.getCustomerBestZhongPao(customerZhongPaoQueryVO);
        customerZhongPaoQueryVO.setConsignorId(consignorCustomerId);
        customerZhongPaoQueryVO.setConsigneeId(consigneeCustomerId);
        // 获取全局重泡货与客户设置重泡货配置综合最优值
        ZhongPaoBestVO zhongPaoBestVO =
                zhongPaoService.getCustomerBestZhongPao(customerZhongPaoQueryVO);
        if (Objects.isNull(orgZhongPaoBestVO)) {
            throw exception(THIS_LINE_ZHONG_PAO_SET_NOT_NULL);
        }
        if (Objects.nonNull(orderDO.getWeightUnit()) &&
                orderDO.getWeightUnit().compareTo(BigDecimal.ZERO) > 0) {
            // 特价使用的
            zhongPaoBestVO.setZhongEdge(orderDO.getWeightUnit());
        }
        if (Objects.nonNull(orderDO.getVolumeUnit()) &&
                orderDO.getVolumeUnit().compareTo(BigDecimal.ZERO) > 0) {
            // 特价使用的
            zhongPaoBestVO.setPaoEdge(orderDO.getVolumeUnit());
        }
        // 拆单业务或者子订单，并且拆单未做运输方式变更的不能进行收费数据重算处理
        if ((type == 5 || (Objects.nonNull(orderDO.getParentOrderId())
                && orderDO.getParentOrderId() > 0L))
                && !orderDO.getSplitSeparateOrder()) {

            // 拆单订单不对收费数据进行重算，拆单子订单都做了收费数据分拆处理
            // 订单的重货方数和泡货重量取订单订单项的收费数据之和
            BigDecimal wVolume = orderItemDOList.stream().map(
                    OrderItemDO::getChargeVolume).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
            orderDO.setWVolume(wVolume);
            BigDecimal vWeight = orderItemDOList.stream().map(
                            OrderItemDO::getChargeWeight).filter(Objects::nonNull).
                    reduce(BigDecimal.ZERO, BigDecimal::add);

            if (orderDO.getTransportId() == 3) {
                vWeight = BigDecimalUtils.convertWv(vWeight);
            }
            orderDO.setVWeight(vWeight);
        } else {
            // 当订单开始入仓时，对订单进行原始重泡货基数初始化
            if (Objects.isNull(orderDO.getOrgWeightUnit()) ||
                    orderDO.getOrgWeightUnit().compareTo(BigDecimal.ZERO) == 0) {
                orderDO.setOrgWeightUnit(orgZhongPaoBestVO.getZhongEdge());
            }
            if (Objects.isNull(orderDO.getOrgVolumeUnit()) ||
                    orderDO.getOrgVolumeUnit().compareTo(BigDecimal.ZERO) == 0) {
                orderDO.setOrgVolumeUnit(orgZhongPaoBestVO.getPaoEdge());
            }
            //保存当前计价使用的
            orderDO.setUseWeightUnit(zhongPaoBestVO.getZhongEdge());
            orderDO.setUseVolumeUnit(zhongPaoBestVO.getPaoEdge());
            this.calculationOrderItem(orderDO, orderItemDOList,
                    zhongPaoBestVO, event.getBubbleWeightRatio());
        }


        //计算订单商品项
        //计算单种运输方式的商品费用，并批量插入
        CalculationItemFeeDto dto = this.insertOrderItemDOList(userId,
                orderItemDOList,
                orderDO,
                consignorCustomerId,
                consigneeCustomerId,
                consignorCustomerContactsId,
                consigneeCustomerContactsId,
                type);
        //订单中的商品列表
        List<OrderItemDO> newOrderItemDOList = dto.getOrderItemDOList();
        // 统计订单项品牌属性
        Set<Integer> typeSet = new HashSet<>();
        for (OrderItemDO it : newOrderItemDOList) {
            typeSet.add(StringUtils.isBlank(it.getWarehouseInInfo()) ? it.getBrandType() : it.getFeeType());
        }
        orderDO.setMinMeteringQuantity(newOrderItemDOList.stream().
                map(OrderItemDO::getMinMeteringQuantity).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        orderDO.setMinMeteringVolume(newOrderItemDOList.stream().
                map(OrderItemDO::getMinMeteringVolume).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        orderDO.setMinMeteringWeight(newOrderItemDOList.stream().
                map(OrderItemDO::getMinMeteringWeight).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        //预计运费与清关费
        CostVO newCostVO = dto.getCostVO();
        List<FeeDto> newFeeDtoList = newCostVO.getFeeDtoList();
        //新运费和清关费的金额与老运费和清关费的金额变动
        BigDecimal oldFreightAndClearanceFee = BigDecimal.ZERO;
        BigDecimal newFreightAndClearanceFee = BigDecimal.ZERO;

        if (StringUtils.isNotBlank(orderDO.getCost())) {
            CostVO oldCostVO = JSONObject.parseObject(orderDO.getCost(),
                    CostVO.class);
            List<FeeDto> oldFeeDtoList = oldCostVO.getFeeDtoList();
            Map<Long, ExchangeRateRespDTO> oldExchangeRateRespDTOMap = null;
            Map<Long, ExchangeRateRespDTO> newExchangeRateRespDTOMap = null;
            if (CollectionUtil.isNotEmpty(oldFeeDtoList) &&
                    CollectionUtil.isNotEmpty(newFeeDtoList)) {

                Set<Long> oldCurrencyIdList = oldFeeDtoList.stream().filter(
                        feeDto -> Objects.equals(feeDto.getFeeType(),
                                FeeTypeEnum.FREIGHT.getType()) || Objects.equals(feeDto.getFeeType(), FeeTypeEnum.CLEARANCE_FEE.getType())).map(FeeDto::getCurrencyId).map(c -> Long.parseLong(String.valueOf(c))).collect(Collectors.toSet());
                Set<Long> newCurrencyIdList = newFeeDtoList.stream().filter(
                        feeDto -> Objects.equals(feeDto.getFeeType(),
                                FeeTypeEnum.FREIGHT.getType()) || Objects.equals(feeDto.getFeeType(), FeeTypeEnum.CLEARANCE_FEE.getType())).map(FeeDto::getCurrencyId).map(c -> Long.parseLong(String.valueOf(c))).collect(Collectors.toSet());
                if (type == 10 && (oldCurrencyIdList.size() > 1 ||
                        newCurrencyIdList.size() > 1)) {
                    List<ExchangeRateRespDTO> oldExchangeRateRespDTOList =
                            currencyApi.getCurrencyRateList(oldCurrencyIdList,
                                    1L);
                    if (CollectionUtil.isNotEmpty(oldExchangeRateRespDTOList)) {
                        oldExchangeRateRespDTOMap =
                                oldExchangeRateRespDTOList.stream().collect(Collectors.toMap(ExchangeRateRespDTO::getSourceCurrencyId, v -> v, (v1, v2) -> v2));
                    }
                    List<ExchangeRateRespDTO> newExchangeRateRespDTOList =
                            currencyApi.getCurrencyRateList(newCurrencyIdList,
                                    1L);
                    if (CollectionUtil.isNotEmpty(newExchangeRateRespDTOList)) {
                        newExchangeRateRespDTOMap = newExchangeRateRespDTOList.stream().collect(Collectors.toMap(ExchangeRateRespDTO::getSourceCurrencyId, v -> v, (v1, v2) -> v2));
                    }
                }
            }
            if (CollectionUtil.isNotEmpty(oldFeeDtoList)) {
                Map<Integer, CurrencyRespDTO> currencyRespDTOMap =
                        currencyApi.getAllCurrency();
                for (FeeDto feeDto : oldFeeDtoList) {
                    if (type == 10 && (Objects.equals(feeDto.getFeeType(), FeeTypeEnum.FREIGHT.getType()) || Objects.equals(feeDto.getFeeType(), FeeTypeEnum.CLEARANCE_FEE.getType()))) {
                        if (Objects.nonNull(oldExchangeRateRespDTOMap)) {
                            ExchangeRateRespDTO exchangeRateRespDTO =
                                    oldExchangeRateRespDTOMap.get(Long.parseLong(String.valueOf(feeDto.getCurrencyId())));
                            if (Objects.isNull(exchangeRateRespDTO)) {
                                throw exception(EXCHANGE_RATE_NOT_EXISTS_PARAM, currencyRespDTOMap.get(feeDto.getCurrencyId()).getFuhao(), currencyRespDTOMap.get(1).getFuhao());
                            }
                            oldFreightAndClearanceFee =
                                    oldFreightAndClearanceFee.add(feeDto.getAmount().multiply(exchangeRateRespDTO.getCurrencyRate()));
                        } else {
                            oldFreightAndClearanceFee =
                                    oldFreightAndClearanceFee.add(feeDto.getAmount());
                        }
                    }
                    if (!Objects.equals(feeDto.getFeeType(), FeeTypeEnum.FREIGHT.getType()) &&
                            !Objects.equals(feeDto.getFeeType(), FeeTypeEnum.CLEARANCE_FEE.getType())
                            && !Objects.equals(feeDto.getFeeType(), FeeTypeEnum.INSURANCE_FEE.getType()) &&
                            !Objects.equals(feeDto.getFeeType(), FeeTypeEnum.WORTH.getType())) {
                        newFeeDtoList.add(feeDto);
                    }
                }
                if (CollectionUtil.isNotEmpty(newFeeDtoList)) {
                    for (FeeDto feeDto : newFeeDtoList) {
                        if (type == 10 && (Objects.equals(feeDto.getFeeType(), FeeTypeEnum.FREIGHT.getType()) || Objects.equals(feeDto.getFeeType(), FeeTypeEnum.CLEARANCE_FEE.getType()))) {
                            if (Objects.nonNull(newExchangeRateRespDTOMap)) {
                                ExchangeRateRespDTO exchangeRateRespDTO = newExchangeRateRespDTOMap.get(Long.parseLong(String.valueOf(feeDto.getCurrencyId())));
                                if (Objects.isNull(exchangeRateRespDTO)) {
                                    throw exception(EXCHANGE_RATE_NOT_EXISTS_PARAM, currencyRespDTOMap.get(feeDto.getCurrencyId()).getFuhao(), currencyRespDTOMap.get(1).getFuhao());
                                }
                                newFreightAndClearanceFee = newFreightAndClearanceFee.add(feeDto.getAmount().multiply(exchangeRateRespDTO.getCurrencyRate()));
                            } else {
                                newFreightAndClearanceFee = newFreightAndClearanceFee.add(feeDto.getAmount());
                            }
                        }
                    }
                }
            }
        }

        //计较体积

        BigDecimal chargeVolume =
                newOrderItemDOList.stream().map(OrderItemDO::getChargeVolume).
                        reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal sumVolume = newOrderItemDOList.stream().map(OrderItemDO::getWarehouseInInfoVO).filter(Objects::nonNull).map(WarehouseInInfoVO::getVolume).reduce(BigDecimal.ZERO, BigDecimal::add);
        orderDO.setSumVolume(sumVolume);

        //计价总重量

        BigDecimal chargeWeight =
                newOrderItemDOList.stream().map(OrderItemDO::getChargeWeight).
                        reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal sumWeight =
                newOrderItemDOList.stream().map(OrderItemDO::getWarehouseInInfoVO).
                        filter(Objects::nonNull).map(WarehouseInInfoVO::getWeight).
                        reduce(BigDecimal.ZERO, BigDecimal::add);

        orderDO.setSumWeight(sumWeight);
        Integer sumNum = newOrderItemDOList.stream().map(OrderItemDO::getWarehouseInInfoVO).filter(Objects::nonNull).mapToInt(WarehouseInInfoVO::getCartonsNum).sum();
        orderDO.setSumNum(sumNum);
        Integer sumQuantity = newOrderItemDOList.stream().map(OrderItemDO::getWarehouseInInfoVO).filter(vo -> Objects.nonNull(vo) && Objects.nonNull(vo.getQuantityAll())).mapToInt(WarehouseInInfoVO::getQuantityAll).sum();
        orderDO.setSumQuantity(sumQuantity);


        if (orderDO.getTransportId() == 3) {
            // 入仓时根据收费重量体积计算泡货比
            if (chargeVolume.compareTo(BigDecimal.ZERO) == 0) {
                orderDO.setWeightRatio(BigDecimal.ZERO);
            } else {
                orderDO.setWeightRatio(chargeWeight.divide(chargeVolume,
                        2, RoundingMode.HALF_UP));
            }
        } else {
            // 入仓时根据入仓重量体积计算货重比
            if (sumVolume.compareTo(BigDecimal.ZERO) == 0) {
                orderDO.setWeightRatio(BigDecimal.ZERO);
            } else {
                orderDO.setWeightRatio(sumWeight.divide(sumVolume,
                        2, RoundingMode.HALF_UP));
            }
        }
//        }
        newCostVO.setFeeDtoList(newFeeDtoList);
        newCostVO.setTotalVolume(newOrderItemDOList.stream().map(
                OrderItemDO::getVolume).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        newCostVO.setTotalWeight(newOrderItemDOList.stream().map(
                OrderItemDO::getWeight).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        newCostVO.setTotalNum(newOrderItemDOList.stream().mapToInt(
                OrderItemDO::getNum).filter(Objects::nonNull).sum());
        newCostVO.setTotalQuantity(newOrderItemDOList.stream().mapToInt(
                OrderItemDO::getQuantity).filter(Objects::nonNull).sum());


        if (typeSet.size() > 0) {
            int brandType = typeSet.stream().findFirst().get();
            orderDO.setProductRecord(typeSet.size() > 1 ? 4 : (brandType == 0 ? 2 : (brandType == 1 ? 1 : 3)));
        }
        orderDO.setCost(JSONObject.toJSONString(newCostVO));
        orderDO.setUpdater(userId);
        orderDO.setUpdateTime(new Date());

        OrderDO updateOrder = new OrderDO();
        BeanUtils.copyProperties(orderDO, updateOrder);

        // 为保证订单状态不会因为并发被覆盖，这里不能对订单状态进行更新，需要将订单所有状态置null
        updateOrder.setStatus(null);
        updateOrder.setAbnormalState(null);
        updateOrder.setAirShipment(null);
        updateOrder.setInWarehouseState(null);
        updateOrder.setShipmentState(null);
        updateOrder.setAuditType(null);
        updateOrder.setAuditResult(null);
        updateOrder.setOldInWarehouseState(null);
        updateOrder.setOldStatus(null);
        updateOrder.setOldShipmentState(null);
        updateOrder.setGuanLianOrderStatus(null);
        updateOrder.setExceptionReason(null);
        // 这里不需要对可能的柜号或提单号进行更新
        updateOrder.setContainerNumber(null);
        updateOrder.setTidanNo(null);
        orderMapper.updateById(updateOrder);

        orderDO.setOrderItemDOList(newOrderItemDOList);
        //空运的每日刷新价格业务不执行后面的异常及状态业务修正，只更新前面的价格数据
        if (type != 30) {
            // 更新完订单所有计价信息后，对未报价的订单项去生成未报价异常(待确认商品不予生成未报价异常)
            // 只对非拆单子订单进行校验
            int noQuoteOrAutomaticNoQuote = 0;
            // 0 没有未报价 1 有未报价 2 自动处理了未报价
            if (Objects.isNull(orderDO.getParentOrderId()) ||
                    orderDO.getParentOrderId() == 0 ||
                    orderDO.getSplitSeparateOrder()) {
                // 查询待处理的不可出渠道异常
                List<OrderExceptionDO> orderNoCanShipmentChannelExceptionDOList =
                        orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderDO.getOrderId(),
                                null,
                                OrderExceptionEnum.NOT_SHIPPING_CHANNEL_EXCEPTION.getKey());
                orderDO.setIsAutomaticHandleNoCanShipmentChannelException(false);
                // 拆单子订单如果被标记为独立订单，则与非拆单订单一样的处理逻辑
                if (orderDO.getStatus() > OrderStatusEnum.DRAFT.getValue()) {
                    for (OrderItemDO orderItemDO : newOrderItemDOList) {
                        WarehouseInInfoVO warehouseInInfoVO =
                                orderItemDO.getWarehouseInInfoVO();
                        //生成未报价异常 (草稿订单除外)
                        //创建未报价异常  type=6,是处理价格异常
                        noQuoteOrAutomaticNoQuote =
                                this.createOrderNoQuoteException(orderDO,
                                        noQuoteOrAutomaticNoQuote,
                                        orderItemDO, type);

                        //专线空运，海空联运
                        if (Objects.equals(TransportTypeShortEnum.AIR_FREIGHT_LINE.getValue(),
                                orderDO.getTransportId())
                                || Objects.equals(TransportTypeShortEnum.AIR_SEA_COMBINED_TRANSPORT.getValue(),
                                orderDO.getTransportId())) {

                            //没有待处理的清关费未报价异常，则需要生成
                            //生成清关费异常  添加参数type=6,是处理价格异常
                            noQuoteOrAutomaticNoQuote =
                                    this.createClearanceFeeNoQuiteException(orderDO,
                                            noQuoteOrAutomaticNoQuote,
                                            orderItemDO, type);
                            // 这里可能因为自动处理未报价异常(包括未报价清关费异常)时，
                            // 已经对此业务进行过校验更新，所以需要对品名进行数据再查询，以保证获取的是最新状态
                            OrderItemDO item =
                                    orderItemMapper.selectById(
                                            orderItemDO.getOrderItemId());
                            // 非拆单订单完成入仓后，如果是已入仓的品名，线路价格设置了单询，
                            // 且未生成过单询异常，则去生成单询异常
                            this.createOrderInquiryException(orderDO,
                                    item, warehouseInInfoVO, type);

                            // 入仓订单，当没有未报价异常(包括未报价清关费异常)
                            // 时才判断是否需要生成不可出渠道异常和单询异常
                            if (noQuoteOrAutomaticNoQuote != 1 &&
                                    Objects.nonNull(warehouseInInfoVO) &&
                                    warehouseInInfoVO.getCartonsNum() > 0) {

                                //不可出渠道异常
                                this.createNoCanShipmentChannelException(orderDO,
                                        event, item, warehouseInInfoVO,
                                        type, orderNoCanShipmentChannelExceptionDOList);
                            } else {
                                String s = orderDO.getOrderNo() +
                                        "不可出渠道异常逻辑点 noQuoteOrAutomaticNoQuote:" +
                                        noQuoteOrAutomaticNoQuote;
                                if (Objects.isNull(warehouseInInfoVO)) {
                                    s += " warehouseInInfoVO 为空，";
                                }
                                if (Objects.isNull(warehouseInInfoVO) == false) {
                                    s += "getCartonsNum:" +
                                            warehouseInInfoVO.getCartonsNum();
                                }
                                zTest m = new zTest();
                                m.setTestname(s);
                                m.setCreatedate(new Date());
                                zTestMapper.insert(m);
                            }
                        } else {
                            //海运也需要判断单询价异常逻辑
                            OrderItemDO item =
                                    orderItemMapper.selectById(
                                            orderItemDO.getOrderItemId());
                            // 非拆单订单完成入仓后，如果是已入仓的品名，线路价格设置了单询，
                            // 且未生成过单询异常，则去生成单询异常
                            this.createOrderInquiryException(orderDO,
                                    item, warehouseInInfoVO, type);
                        }
                        // 当订单未报价、或待确认商品时，都需要将预付状态置null
                        if (orderItemDO.getItemStatus() == -1 ||
                                orderItemDO.getIsProd()) {
                            // 因为调用updateById时无法更新置null的数据，所以当订单项未报价时需要单独将是否预付置为null
                            orderItemMapper.update(null,
                                    new LambdaUpdateWrapper<OrderItemDO>().set(OrderItemDO::getIsPayAdvance, null).eq(OrderItemDO::getOrderItemId, orderItemDO.getOrderItemId()));
                        }
                    }
                }
                if (orderDO.getIsAutomaticHandleNoCanShipmentChannelException()) {
                    // 补充判断异常不为空,但是处理中状态时,不需要执行删除业务
                    if (CollectionUtil.isNotEmpty(orderNoCanShipmentChannelExceptionDOList)) {
                        for (OrderExceptionDO orderExceptionDO : orderNoCanShipmentChannelExceptionDOList) {
                            // 特性被修改后删除此异常
                            if (orderExceptionDO.getOrderExceptionStatus() == 0) {
                                orderExceptionService.handlerRemoveNotShippingChannelExceptionById(orderExceptionDO.getId());
                            }
                        }
                    }
                }
            }
            // 创建订单费用变动异常,生成了未报价异常、处理未报价异常、
            // 自动处理未报价异常造成的费用变动都不产生费用异常
            if (noQuoteOrAutomaticNoQuote == 0 && type != 6) {
                this.createFeeChangeException(orderDO, type,
                        oldFreightAndClearanceFee,
                        newFreightAndClearanceFee);
            }
            boolean isPayAdvanceException = false;
            if ((Objects.nonNull(orderDO.getSumNum()) && orderDO.getSumNum() > 0)
                    || (Objects.nonNull(orderDO.getSumVolume()) && orderDO.getSumVolume().compareTo(BigDecimal.ZERO) > 0)
                    || (Objects.nonNull(orderDO.getSumWeight()) && orderDO.getSumWeight().compareTo(BigDecimal.ZERO) > 0)
                    || (Objects.nonNull(orderDO.getSumQuantity()) && orderDO.getSumQuantity() > 0)) {

                if (type == 3 && (Objects.nonNull(orderDO.getParentOrderId()) && orderDO.getParentOrderId() != 0L)) {
                    // 拆单后的子订单直接去生成应收
                    isPayAdvanceException = this.addOrderReceivable(orderDO, 1);
                } else {
                    if (type == 6 && Objects.equals(orderDO.getInWarehouseState(), OrderWarehouseInStatusEnum.warehouse_finished.getValue())) {
                        // 处理未报价时，如果是已入仓产品去生成应收
                        isPayAdvanceException = this.addOrderReceivable(orderDO,
                                1);
                    } else {
                        isPayAdvanceException = this.addOrderReceivable(orderDO,
                                2);
                    }
                }
            }
            if ((type == 6 || type == 10 || type == 12) && isPayAdvanceException) {
                // TODO 待确定,订单之前处理过预付异常，这时入仓修改产生的新预付异常是否重复生成
                List<OrderExceptionDO> orderExceptionDOList =
                        orderExceptionService.getOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderDO.getOrderId(),
                                null,
                                OrderExceptionEnum.ORDER_PAY_EXCEPTION.getKey());
                log.info("订单【{}】生成预付异常数量：{}", orderDO.getOrderNo(),
                        CollectionUtil.isEmpty(orderExceptionDOList) ? 0 : orderExceptionDOList.size());
                if (CollectionUtil.isEmpty(orderExceptionDOList)) {
                    log.info("订单【{}】生成预付异常", orderDO.getOrderNo());
                    OrderExceptionCreateReqVO orderExceptionCreateReqVO =
                            this.genOrderException(orderDO.getOrderId(),
                                    orderDO,
                                    null,
                                    null,
                                    OrderExceptionEnum.ORDER_PAY_EXCEPTION,
                                    OrderExceptionEnum.ORDER_PAY_EXCEPTION.getZhValueDesc(),
                                    OrderExceptionEnum.ORDER_PAY_EXCEPTION.getEnValueDesc());
                    orderExceptionService.createOrderException(orderExceptionCreateReqVO);
                }
            }
            //获取订单最新数据状态
            OrderDO newOrder = orderMapper.selectById(orderDO.getOrderId());
            // 判断空运已入仓订单状态如果是默认出货状态0，且无异常、无审批，那么标记为可出
            this.airShipmentStateUpdate(type, newFeeDtoList, newOrder);

            //setWareHouseIsZero(orderDO);

        }

    }

    //处理订单入仓数为0的单价
    //先判断订单项入仓记录是否为空，为空就改为不为空的单机
    private void setWareHouseIsZero(OrderDO orderDO) {
        if (orderDO == null) return;
        LambdaUpdateWrapper q1 =
                new LambdaUpdateWrapper<OrderItemDO>().eq(OrderItemDO::getOrderId,
                        orderDO.getOrderId());
        List<OrderItemDO> listItem = orderItemMapper.selectList(q1);
        if (CollectionUtil.isEmpty(listItem) == true) return;

        for (OrderItemDO o : listItem
        ) {

        }

    }

    private void airShipmentStateUpdate(Integer type,
                                        List<FeeDto> newFeeDtoList,
                                        OrderDO newOrder) {
        if ((Objects.equals(TransportTypeShortEnum.AIR_FREIGHT_LINE.getValue(),
                newOrder.getTransportId())
                || Objects.equals(TransportTypeShortEnum.AIR_SEA_COMBINED_TRANSPORT.getValue(),
                newOrder.getTransportId()))) {

            // 检查订单是否有关联报价单
            OrderAssociationOfferCostEvent offerCostEvent =
                    new OrderAssociationOfferCostEvent(newOrder.getOrderId(),
                            BigDecimal.ZERO, 0, BigDecimal.ZERO,
                            0, false);
            applicationContext.publishEvent(offerCostEvent);

            // 默认出货状态0或者待出状态1时，无异常、无审批，那么标记为可出2，否则为待出1
            if ((type == 3 || type == 4 || type == 5 ||
                    newOrder.getStatus() == 5) &&
                    (newOrder.getAirShipment() == 0 ||
                            newOrder.getAirShipment() == 1)) {

                // 默认设置运费与清关费的比较结果为true，因为当订单没有关联报价单时，是不用判断这个条件的，直接跳过
                boolean isEqFreight = false;
                boolean isEqClearance = false;
                if (offerCostEvent.isAssociationOffer()) {
                    FeeDto freightFeeDto = newFeeDtoList.stream().filter(feeDto -> Objects.equals(feeDto.getFeeType(), FeeTypeEnum.FREIGHT.getType())).findFirst().orElse(null);
                    FeeDto clearanceFeeDto = newFeeDtoList.stream().filter(feeDto -> Objects.equals(feeDto.getFeeType(), FeeTypeEnum.CLEARANCE_FEE.getType())).findFirst().orElse(null);
                    // 比较订单与关联报价单的运费是否一致，包含了货币与金额(注：金额为0，货重货币不存在的排除)
                    isEqFreight = Objects.nonNull(freightFeeDto) && Objects.nonNull(freightFeeDto.getCurrencyId()) && freightFeeDto.getCurrencyId() > 0 && freightFeeDto.getAmount().compareTo(BigDecimal.ZERO) > 0
                            && offerCostEvent.getFreightCurrencyId() > 0 && offerCostEvent.getFreight().compareTo(BigDecimal.ZERO) > 0 && Objects.equals(freightFeeDto.getCurrencyId(), offerCostEvent.getFreightCurrencyId())
                            && freightFeeDto.getAmount().compareTo(offerCostEvent.getFreight()) == 0;
                    // 比较订单与关联报价单的清关费是否一致，包含了货币与金额(注：清关费可能为0)
                    isEqClearance = ((Objects.isNull(clearanceFeeDto) || clearanceFeeDto.getAmount().compareTo(BigDecimal.ZERO) == 0) && offerCostEvent.getClearance().compareTo(BigDecimal.ZERO) == 0)
                            || (Objects.nonNull(clearanceFeeDto) && clearanceFeeDto.getAmount().compareTo(BigDecimal.ZERO) > 0 && Objects.nonNull(clearanceFeeDto.getCurrencyId()) && offerCostEvent.getClearance().compareTo(BigDecimal.ZERO) > 0
                            && clearanceFeeDto.getAmount().compareTo(offerCostEvent.getClearance()) == 0 && Objects.equals(clearanceFeeDto.getCurrencyId(), offerCostEvent.getClearanceCurrencyId()));
                }
                // 初始化判断条件，是否自动可出
                boolean isAutomaticCan = false;
                // 每次计价都校验一遍订单的可出状态
                if (isEqFreight && isEqClearance &&
                        newOrder.getAbnormalState() == 0 &&
                        newOrder.getAuditType() == 0 &&
                        Objects.equals(newOrder.getStatus(),
                                OrderStatusEnum.IN_WAREHOUSE.getValue())) {
                    // 关联报价单检查结果通过，且无异常、无审批的已入仓订单，那么标记为可出2
                    newOrder.setAirShipment(2);
                    //  自动可出需要补充订单日志
                    isAutomaticCan = true;
                } else {
                    // 待出
                    newOrder.setAirShipment(1);
                }
                orderMapper.update(null, new LambdaUpdateWrapper<OrderDO>()
                        .set(OrderDO::getAirShipment, newOrder.getAirShipment())
                        .eq(OrderDO::getOrderId, newOrder.getOrderId()));
                if (isAutomaticCan) {
                    String note = null;
                    if (offerCostEvent.isAssociationOffer()) {
                        ApplyInfoVO infoVO = new ApplyInfoVO();
                        infoVO.setName("总运费、总清关费与报价单一致，自动可出");
                        note = JSONObject.toJSONString(Collections.singletonList(infoVO));
                    }
                    this.addOrderOperateLog(newOrder.getOrderId(),
                            "自动可出", note);
                }
            }
        } else {
            // 如果非空运订单计价结束，订单可出状态不为默认状态0，则改为默认0
            if (newOrder.getAirShipment() != 0) {
                // 每次计价都校验一遍订单的可出状态
                orderMapper.update(null, new LambdaUpdateWrapper<OrderDO>()
                        .set(OrderDO::getAirShipment, 0)
                        .eq(OrderDO::getOrderId, newOrder.getOrderId()));
            }
        }
    }

    private int createOrderNoQuoteException(OrderDO orderDO,
                                            int noQuoteOrAutomaticNoQuote,
                                            OrderItemDO orderItemDO,
                                            Integer type) {
        zTest z22 = new zTest();
        z22.setTestname("处理25 createOrderNoQuoteException");
        z22.setCreatedate(new Date());
        zTestMapper.insert(z22);

        if (orderDO == null) {
            zTest z = new zTest();
            z.setTestname("orderDO 为空");
            z.setCreatedate(new Date());
            zTestMapper.insert(z);
            return noQuoteOrAutomaticNoQuote;
        }
        if (orderItemDO == null) {
            zTest z = new zTest();
            z.setTestname("orderItemDO 为空");
            z.setCreatedate(new Date());
            zTestMapper.insert(z);
            return noQuoteOrAutomaticNoQuote;
        }

        //查询有无未报价异常
        List<OrderExceptionDO> orderNoQuoteExceptionDOList =
                orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndProdIdAndExceptionKey(
                        orderDO.getOrderId(),
                        null,
                        orderItemDO.getProdId(),
                        OrderExceptionEnum.ORDER_NO_QUOTE_EXCEPTION.getKey());

        if (orderItemDO.getNeedOrderInquiry() != null) {

            String sNo = "";
            if (orderDO.getOrderNo() != null) sNo = orderDO.getOrderNo();

            String s = sNo + "未报价日志24，type=" + type.toString() +
                    "getTransportId=" + orderDO.getTransportId().toString() +
                    "getNeedOrderInquiry=" + orderItemDO.getNeedOrderInquiry();

            // 添加的逻辑点 海运和空运只要是单询价都按同一套逻辑来处理
            if (orderItemDO.getNeedOrderInquiry() == 1) {
                //处理未报价异常，且是空运,且是单询价
                if (CollectionUtil.isNotEmpty(orderNoQuoteExceptionDOList)) {
                    orderExceptionService.autoProcessException(orderDO.getOrderId(),
                            orderItemDO.getOrderItemId(),
                            OrderExceptionEnum.ORDER_NO_QUOTE_EXCEPTION,
                            "单询价，自动处理未报价异常",
                            OrderExceptionResult.ORDER_NO_QUOTE_EXCEPTION_RESULT.PROCESSED);
                    noQuoteOrAutomaticNoQuote = 2;
                    return noQuoteOrAutomaticNoQuote;
                }
                zTest z = new zTest();
                z.setTestname(s);
                z.setCreatedate(new Date());
                zTestMapper.insert(z);

                noQuoteOrAutomaticNoQuote = 2;
                return noQuoteOrAutomaticNoQuote;
            } else {

                zTest z = new zTest();
                z.setTestname(s);
                z.setCreatedate(new Date());
                zTestMapper.insert(z);
            }
        } else {
            zTest z = new zTest();
            z.setTestname("单询价为空 createOrderNoQuoteException");
            z.setCreatedate(new Date());
            zTestMapper.insert(z);
        }
        zTest z2 = new zTest();
        z2.setTestname("处理24");
        z2.setCreatedate(new Date());
        zTestMapper.insert(z2);

        //
        if (orderItemDO.getItemStatus() == -1 && !orderItemDO.getIsProd()) {
            if (CollectionUtil.isEmpty(orderNoQuoteExceptionDOList)) {
                OrderExceptionCreateReqVO orderExceptionCreateReqVO =
                        this.genOrderException(orderDO.getOrderId(),
                                orderDO,
                                orderItemDO,
                                null,
                                OrderExceptionEnum.ORDER_NO_QUOTE_EXCEPTION,
                                String.format("订单【%s】中的商品【%s】未报价",
                                        orderDO.getOrderNo(),
                                        orderItemDO.getProdTitleZh()),
                                String.format("The goods 【%s】 in the order 【%s】 are not quoted",
                                        orderItemDO.getProdTitleEn(),
                                        orderDO.getOrderNo()));
                // TODO 同一个订单相同品名有相同未报价异常时,不重复产生
                orderExceptionService.createOrderException(orderExceptionCreateReqVO);
            }
            //noQuoteOrAutomaticNoQuote = 1;
        } else {
            if (CollectionUtil.isNotEmpty(orderNoQuoteExceptionDOList)) {
                zTest z = new zTest();
                z.setTestname("autoProcessException 执行");
                z.setCreatedate(new Date());
                zTestMapper.insert(z);
                // TODO 当其他业务补充了品名价格后，如果还有待处理的未报价异常，需要同步处理掉
                orderExceptionService.autoProcessException(orderDO.getOrderId(),
                        orderItemDO.getOrderItemId(),
                        OrderExceptionEnum.ORDER_NO_QUOTE_EXCEPTION,
                        "设置价格自动处理",
                        OrderExceptionResult.ORDER_NO_QUOTE_EXCEPTION_RESULT.PROCESSED);
                noQuoteOrAutomaticNoQuote = 2;
            } else {
                zTest z = new zTest();
                z.setTestname("orderNoQuoteExceptionDOList 为空");
                z.setCreatedate(new Date());
                zTestMapper.insert(z);
            }
        }
        return noQuoteOrAutomaticNoQuote;
    }


    private void saveLog(OrderDO orderDO,
                         OrderItemDO orderItemDO,
                         WarehouseInInfoVO warehouseInInfoVO,
                         Integer type) {
        zTest z = new zTest();
        z.setCreatedate(new Date());
        if (orderDO == null) {
            //订单信息为空
            z.setTestname("orderDO为空");
            zTestMapper.insert(z);
            return;
        }

        if (orderItemDO == null) {
            //订单明细为空
            z.setTestname("orderItemDO为空");
            zTestMapper.insert(z);
            return;
        }

        if (warehouseInInfoVO == null) {
            //入仓信息为空
            z.setTestname("warehouseInInfoVO为空");
            zTestMapper.insert(z);
            return;
        }

        String s = "单询价日志，type=" + type.toString() + "Status=" +
                orderDO.getStatus().toString();

        if (Objects.nonNull(orderItemDO.getNeedOrderInquiry())) {
            s += "NeedOrderInquiry为空";
        } else {
            //单询价
            s += "NeedOrderInquiry=" + orderItemDO.getNeedOrderInquiry();
        }

        if (Objects.nonNull(warehouseInInfoVO)) {
            s += "warehouseInInfo为空";
        } else {
            s += "CartonsNum="
                    + warehouseInInfoVO.getCartonsNum().toString();
        }

        if (Objects.nonNull(orderItemDO.getIsHandlerOrderInquiryException())) {
            s += "处理过单询价为空";
        } else {
            s += "处理过单询价为空=" + orderItemDO.getIsHandlerOrderInquiryException();
        }
        z.setTestname(s);
        zTestMapper.insert(z);
    }

    /*
     生成单询价异常
     */
    private void createOrderInquiryException(OrderDO orderDO,
                                             OrderItemDO orderItemDO,
                                             WarehouseInInfoVO warehouseInInfoVO,
                                             Integer type) {

        List<OrderExceptionDO> orderInquiryExceptionDOList =
                orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderDO.getOrderId(),
                        orderItemDO.getOrderItemId(),
                        OrderExceptionEnum.LINE_LOOP_EXCEPTION.getKey());

        saveLog(orderDO, orderItemDO, warehouseInInfoVO, type);

        // 避免在前面自动处理未报价异常和清关费未报价异常时的回调，
        // 优先创建了单询异常，造成并发的重复创建
        if (CollectionUtil.isEmpty(orderInquiryExceptionDOList)) {
            if ((Objects.equals(orderDO.getStatus(),
                    OrderStatusEnum.IN_WAREHOUSE.getValue()) ||
                    type == 15 || type == 10) &&
                    Objects.nonNull(warehouseInInfoVO)
                    && warehouseInInfoVO.getCartonsNum() > 0
                    && Objects.nonNull(orderItemDO.getNeedOrderInquiry())
                    && orderItemDO.getNeedOrderInquiry() == 1
                    && Objects.nonNull(orderItemDO.getIsHandlerOrderInquiryException())
                    && !orderItemDO.getIsHandlerOrderInquiryException()) {
                //getCartonsNum 入库箱数
                //getIsHandlerOrderInquiryException 是否处理过单询价异常
                // 产生单询异常
                OrderExceptionCreateReqVO orderExceptionCreateReqVO =
                        this.genOrderException(orderDO.getOrderId(),
                                orderDO, orderItemDO,
                                null, OrderExceptionEnum.LINE_LOOP_EXCEPTION,
                                String.format("商品【%s】线路单询异常",
                                        orderItemDO.getProdTitleZh()),
                                String.format("Line inquiry exception for product [%s]",
                                        orderItemDO.getProdTitleEn()));

                orderExceptionService.createOrderException(orderExceptionCreateReqVO);
                // 标记已产生过单询异常, 并更新到数据库
                orderItemDO.setIsHandlerOrderInquiryException(Boolean.TRUE);
                orderItemMapper.update(null,
                        new LambdaUpdateWrapper<OrderItemDO>().
                                set(OrderItemDO::getIsHandlerOrderInquiryException, true).
                                eq(OrderItemDO::getOrderItemId,
                                        orderItemDO.getOrderItemId()));
            } else {
                zTest z = new zTest();
                z.setTestname("不符合产生单询价条件");
                z.setCreatedate(new Date());
                zTestMapper.insert(z);
            }
        } else {
            zTest z = new zTest();
            z.setTestname("orderInquiryExceptionDOList 为空");
            z.setCreatedate(new Date());
            zTestMapper.insert(z);
        }
    }

    /*
     清关价异常处理
     */
    private int createClearanceFeeNoQuiteException(OrderDO orderDO,
                                                   int noQuoteOrAutomaticNoQuote,
                                                   OrderItemDO orderItemDO,
                                                   Integer type) {
        zTest z22 = new zTest();
        z22.setTestname("处理25 createClearanceFeeNoQuiteException");
        z22.setCreatedate(new Date());
        zTestMapper.insert(z22);

        // 添加的是否为空判断逻辑
        if (orderDO == null) {
            return noQuoteOrAutomaticNoQuote;
        }
        if (orderItemDO == null) {
            return noQuoteOrAutomaticNoQuote;
        }

        // 查询是否有重量超限异常，如果有则不生成清关费异常
        // TODO 查询是否有重量超限异常和渠道包装重量超限异常，如果有则不生成清关费异常
        List<OrderExceptionDO> goodsOverweightExceptionDOList =
                orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndProdIdAndExceptionKeys(orderDO.getOrderId(),
                        null,
                        orderItemDO.getProdId(),
                        CollectionUtil.newArrayList(OrderExceptionEnum.GOODS_OVERWEIGHT_EXCEPTION.getKey(), OrderExceptionEnum.LINE_WEIGHT_EXCEPTION.getKey()));

        if (orderItemDO.getNeedOrderInquiry() != null) {
            String sNo = "";
            if (orderDO.getOrderNo() != null) sNo = orderDO.getOrderNo();

            String s = sNo + "清关价日志，type=" + type.toString() + " TransportId=" +
                    orderDO.getTransportId().toString() +
                    " NeedOrderInquiry=" + orderItemDO.getNeedOrderInquiry().toString();

            //  海运和空运设置了单询价都用同一套逻辑
            if (orderItemDO.getNeedOrderInquiry() == 1) {

                //根据订单号查询是否有清关费异常
                List<OrderExceptionDO> orderClearanceFeeNoQuoteExceptionDOList =
                        orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(
                                orderDO.getOrderId(),
                                orderItemDO.getOrderItemId(),
                                OrderExceptionEnum.CUSTOMS_FEE_NOT_QUOTE_EXCEPTION.getKey());

                if (CollectionUtil.isNotEmpty(orderClearanceFeeNoQuoteExceptionDOList)) {
                    // 当其他业务补充了品名空运清关费价格后，如果还有待处理的清关费未报价异常，需要同步处理掉
                    orderExceptionService.autoProcessException(orderDO.getOrderId(),
                            orderItemDO.getOrderItemId(),
                            OrderExceptionEnum.CUSTOMS_FEE_NOT_QUOTE_EXCEPTION,
                            "单询价，自动处理清关价异常",
                            OrderExceptionResult.CUSTOMS_FEE_NOT_QUOTE_EXCEPTION_RESULT.PROCESSED);
                    noQuoteOrAutomaticNoQuote = 2;
                    return noQuoteOrAutomaticNoQuote;
                }
                zTest z = new zTest();
                z.setTestname(s);
                z.setCreatedate(new Date());
                zTestMapper.insert(z);
                noQuoteOrAutomaticNoQuote = 2;
                return noQuoteOrAutomaticNoQuote;
            } else {
                zTest z = new zTest();
                z.setTestname(s);
                z.setCreatedate(new Date());
            }

        } else {
            zTest z = new zTest();
            z.setTestname("单询价为空");
            z.setCreatedate(new Date());
        }
        //end添加的逻辑点

        // 渠道重量超限异常 channel_packaging_overweight_exception
        // List<OrderExceptionDO> channelPackagingOverweightExceptionDOList = orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderDO.getOrderId(), orderItemDO.getOrderItemId(), OrderExceptionEnum.CHANNEL_PACKAGING_OVERWEIGHT_EXCEPTION.getKey());
        // if (CollectionUtil.isEmpty(goodsOverweightExceptionDOList) && CollectionUtil.isEmpty(channelPackagingOverweightExceptionDOList)) {
        if (CollectionUtil.isEmpty(goodsOverweightExceptionDOList) ||
                goodsOverweightExceptionDOList.size() == 0) {

            List<OrderExceptionDO> orderClearanceFeeNoQuoteExceptionDOList =
                    orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderDO.getOrderId(),
                            orderItemDO.getOrderItemId(),
                            OrderExceptionEnum.CUSTOMS_FEE_NOT_QUOTE_EXCEPTION.getKey());
            //运费加清关价才生成清关费异常
            if (orderItemDO.getCharging() == 0 &&
                    (Objects.isNull(orderItemDO.getOriginalClearanceFreight()) ||
                            orderItemDO.getOriginalClearanceFreight().compareTo(BigDecimal.ZERO) == 0)
                    && ((Objects.isNull(orderItemDO.getChannelManualPricing()) ||
                    !orderItemDO.getChannelManualPricing())
                    && (Objects.isNull(orderItemDO.getSpecialPriceType()) ||
                    !orderItemDO.getSpecialPriceType())
                    && (Objects.isNull(orderItemDO.getSplitCustomPriceType()) ||
                    !orderItemDO.getSplitCustomPriceType()))) {

                if (CollectionUtil.isEmpty(orderClearanceFeeNoQuoteExceptionDOList)) {
                    // 1-未设置商品清关费, 2-区间未匹配上
                    int productPriceEmptyType = orderItemDO.getProductPriceEmptyType();
                    // 1-未设置渠道清关费, 2-区间未匹配上, 3-包装类型未设置
                    int channelPriceEmptyType = orderItemDO.getChannelPriceEmptyType();
                    // 是否超出空运重量上限
                    boolean isAirWeightLimit = orderItemDO.getIsAirWeightLimit();
                    String descZh = "订单中商品%s的清关费未设置或已过期6";
                    String descEn = "The customs clearance fee for item %s in the order has not been set or has expired";
                    if (productPriceEmptyType == 2) {
                        descZh = "订单中商品%s的清关费区间未匹配上";
                        descEn = "The customs clearance fee range for product %s in the order does not match";
                    }
                    descZh = String.format(descZh, orderItemDO.getProdTitleZh());
                    descEn = String.format(descEn, orderItemDO.getProdTitleEn());
                    //当前空运或海空联运订单下单时，没又渠道id，则生成渠道异常
                    OrderExceptionCreateReqVO orderExceptionCreateReqVO =
                            this.genOrderException(orderDO.getOrderId(),
                                    orderDO,
                                    orderItemDO, null,
                                    OrderExceptionEnum.CUSTOMS_FEE_NOT_QUOTE_EXCEPTION,
                                    descZh, descEn);

                    orderExceptionService.createOrderException(orderExceptionCreateReqVO);
                }
                noQuoteOrAutomaticNoQuote = 1;
            } else {
                if (CollectionUtil.isNotEmpty(orderClearanceFeeNoQuoteExceptionDOList)) {
                    // 当其他业务补充了品名空运清关费价格后，如果还有待处理的清关费未报价异常，需要同步处理掉
                    orderExceptionService.autoProcessException(orderDO.getOrderId(), orderItemDO.getOrderItemId(), OrderExceptionEnum.CUSTOMS_FEE_NOT_QUOTE_EXCEPTION, "设置价格自动处理", OrderExceptionResult.CUSTOMS_FEE_NOT_QUOTE_EXCEPTION_RESULT.PROCESSED);
                    noQuoteOrAutomaticNoQuote = 2;
                }
            }
        }
        return noQuoteOrAutomaticNoQuote;
    }

    private void createFeeChangeException(OrderDO orderDO, Integer type, BigDecimal oldFreightAndClearanceFee, BigDecimal newFreightAndClearanceFee) {
        if (type == 10 && oldFreightAndClearanceFee.compareTo(newFreightAndClearanceFee) != 0) {
            // 订单修改业务需要判断收费异常
            // 当订单的运费收费总金额变动时，需要产生异常
            // 当订单修改审批通过后，订单的收费总金额有变动，且当前订单没有多箱异常/少箱异常/重货异常未处理且订单无收费异常，需产生异常
            // 当订单修改审批通过后，订单的收费总金额有变动，且当前订单没有多箱异常/少箱异常/重货异常未处理且订单有收费异常，需更新异常，更新运费金额
            // 处理结果：待处理/已跟客户确认可出/客户不同意发出,只需更新异常处理结果，无需进一步处理
            List<OrderExceptionDO> exceptionDOList = orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKeys(orderDO.getOrderId(), null,
                    Arrays.asList(OrderExceptionEnum.ORDER_SUPERFLUOUS_BOX_EXCEPTION.getKey(), OrderExceptionEnum.ORDER_LACK_BOX_EXCEPTION.getKey(), OrderExceptionEnum.ORDER_HEAVY_CARGO_EXCEPTION.getKey(), OrderExceptionEnum.ORDER_BULKY_CARGO_EXCEPTION.getKey()));
            if (CollectionUtil.isEmpty(exceptionDOList)) {
                BigDecimal changeAmount = oldFreightAndClearanceFee.subtract(newFreightAndClearanceFee);
                String descZh = String.format("订单修改审批通过后运费与清关费的总额变%s", (changeAmount.compareTo(BigDecimal.ZERO) > 0 ? "少了" : "多了"));
                String descEn = changeAmount.compareTo(BigDecimal.ZERO) > 0 ? "After the approval of order modification, the total amount of shipping and customs clearance fees has decreased" :
                        "After the order modification approval, the total amount of shipping and customs clearance fees has increased";
                List<OrderExceptionDO> feeExceptionDOList = orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderDO.getOrderId(), null, OrderExceptionEnum.FEE_EXCEPTION.getKey());
//                if (CollectionUtil.isEmpty(feeExceptionDOList) && Objects.equals(TransportTypeShortEnum.AIR_FREIGHT_LINE.getValue(), orderDO.getTransportId())) {
                if (CollectionUtil.isEmpty(feeExceptionDOList)) {
                    OrderExceptionCreateReqVO orderExceptionCreateReqVO = this.genOrderException(orderDO.getOrderId(), orderDO, null, null, OrderExceptionEnum.FEE_EXCEPTION, descZh, descEn);
                    orderExceptionService.createOrderException(orderExceptionCreateReqVO);
                }
//                else if (!Objects.equals(TransportTypeShortEnum.AIR_FREIGHT_LINE.getValue(), orderDO.getTransportId())) {
//                    if (CollectionUtil.isNotEmpty(feeExceptionDOList)) {
//                        // 当订单变为非空运订单时，如果异常未处理，则自动删除异常
//                        for (OrderExceptionDO orderExceptionDO : feeExceptionDOList) {
//                            orderExceptionService.handlerRemoveFeeExceptionById(orderExceptionDO.getId());
//                        }
//                    }
//                }
                else {
                    if (Objects.equals(orderDO.getStatus(), OrderStatusEnum.ORDER_PLACED.getValue()) || Objects.equals(orderDO.getStatus(), OrderStatusEnum.WAREHOUSING.getValue())) {
                        // 当订单再次修改审批通过运费清关费变动时，如果异常未处理，则更新异常
                        for (OrderExceptionDO orderExceptionDO : feeExceptionDOList) {
                            OrderExceptionDescVO orderExceptionDescVO = new OrderExceptionDescVO();
                            orderExceptionDescVO.setDescZh(descZh);
                            orderExceptionDescVO.setDescEn(descEn);
                            // 如果不为空，则更新此异常的文案说明
                            orderExceptionService.update(new LambdaUpdateWrapper<OrderExceptionDO>().set(OrderExceptionDO::getOrderExceptionDetails, JSONObject.toJSONString(orderExceptionDescVO)).eq(OrderExceptionDO::getId, orderExceptionDO.getId()));
                        }
                    }
                }
            }

        }
    }

    /**
     * 1、 海运重货订单-商品收费立方计算公式调整
     * 重货订单商品的收费体积=（订单总收费体积-商品总入仓体积）*(商品入仓重量/订单中商品为重货的总重量)+商品入仓体积
     * 下面用例子示例：
     * 订单S001是重货，入仓体积10m³，收费体积25m³，总重量16000，重货标准750
     * 商品1---手机壳入仓体积1m³，重量100KG------非重货
     * 商品2---锁链，入仓体积4m³，重量5000KG----重货
     * 商品3---秤砣，入仓体积6m³，重量10900----重货
     * 手机壳非重货，收费方数1m³
     * 锁链-重货，收费立方={（25-1-4-6）*5000/（5000+10900）}+4=8.40m³
     * 秤砣-重货，收费立方={（25-1-4-6）*10900/(5000+10900)}+6=15.6m³
     * 总收费重量1+8.4+15.6=25。。。。。。
     * <p>
     * <p>
     * 2、空运泡货订单-商品收费重量计算公式调整
     * 泡货订单商品的收费重量=（订单总收费重量-商品总入仓重量）*(商品入仓体积/订单中商品为泡货的总体积)+商品入仓重量
     * 下面用例子示例：
     * 订单A001是泡货，入仓总体积是0.5m³，入仓总重量31KG，收费重量83.5KG,泡货标准167
     * 商品1---衣服，入仓体积0.1立方，重量20KG----非泡货
     * 商品2---洞洞鞋，入仓体积0.3立方，重量10KG---泡货
     * 商品3---气球，入仓体积0.1KG，重量1KG---泡货
     * 衣服-非泡货，收费重量20KG
     * 洞洞鞋-泡货，收费重量={（83.5-20-10-1）*0.3/(0.1+0.3)}+10=49.38KG
     * 气球-泡货，收费重量={（83.5-20-10-1）*0.1/（0.1+0.3）}+1=14.12KG
     * 总收费重量20+49.38+14.12=83.5
     *
     * @param orderDO                  订单信息
     * @param orderItemDOList          订单项信息
     * @param zhongPaoBestVO           重泡货配置
     * @param channelBubbleWeightRatio 渠道泡重比例配置
     */
    private void calculationOrderItem(OrderDO orderDO,
                                      List<OrderItemDO> orderItemDOList,
                                      ZhongPaoBestVO zhongPaoBestVO,
                                      BigDecimal channelBubbleWeightRatio) {
        // 重货总重量
        BigDecimal heavyCargoTotalWeight = BigDecimal.ZERO;
        BigDecimal totalWeight = BigDecimal.ZERO;
        // 泡货总体积
        BigDecimal pickledGoodsTotalVolume = BigDecimal.ZERO;
        BigDecimal totalVolume = BigDecimal.ZERO;
        BigDecimal totalChargeQuantity = BigDecimal.ZERO;
        if (Objects.isNull(orderDO.getOrderType())) {
            orderDO.setOrderType(1);
        }
        for (OrderItemDO orderItemDO : orderItemDOList) {
            WarehouseInInfoVO warehouseInInfoVO = orderItemDO.getWarehouseInInfoVO();
            if (Objects.nonNull(warehouseInInfoVO)) {
                orderItemDO.setVWeight(Objects.isNull(warehouseInInfoVO.getWeight()) ?
                        BigDecimal.ZERO : warehouseInInfoVO.getVolume().multiply(zhongPaoBestVO.getPaoEdge()));
                orderItemDO.setWVolume(Objects.isNull(warehouseInInfoVO.getWeight()) || warehouseInInfoVO.getWeight().compareTo(BigDecimal.ZERO) <= 0 ?
                        BigDecimal.ZERO : warehouseInInfoVO.getWeight().divide(zhongPaoBestVO.getZhongEdge(), 2, RoundingMode.HALF_UP));
                // 封装订单项属性(1 普货 2 重货 3 泡货)
                this.setItemType(orderDO, orderItemDO, warehouseInInfoVO.getVolume(), warehouseInInfoVO.getWeight(), warehouseInInfoVO.getQuantityAll());
                if (orderItemDO.getItemType() == 2) {
                    heavyCargoTotalWeight = heavyCargoTotalWeight.add(warehouseInInfoVO.getWeight());
                }
                if (orderItemDO.getItemType() == 3) {
                    pickledGoodsTotalVolume = pickledGoodsTotalVolume.add(warehouseInInfoVO.getVolume());
                }
                totalWeight = totalWeight.add(warehouseInInfoVO.getWeight());
                totalVolume = totalVolume.add(warehouseInInfoVO.getVolume());
                totalChargeQuantity = totalChargeQuantity.add(Objects.nonNull(warehouseInInfoVO.getQuantityAll()) ? new BigDecimal(warehouseInInfoVO.getQuantityAll()) : BigDecimal.ZERO);
            }
        }

        BigDecimal orgTotalVWeight = Objects.isNull(orderDO.getVWeight()) ? BigDecimal.ZERO : orderDO.getVWeight();
        BigDecimal vWeight = totalVolume.multiply(zhongPaoBestVO.getPaoEdge()).setScale(2, RoundingMode.HALF_UP);
        orderDO.setWVolume(totalWeight.divide(zhongPaoBestVO.getZhongEdge(), 2, RoundingMode.HALF_UP));
        // 泡货收费值 -》渠道泡重比例<泡货异常半抛处理<订单泡重优惠申请，互相不叠加。对比三个泡货计费值，取最小的
        // 非泡重优惠值特价才重新计算订单泡重值
        orderDO.setVWeight(vWeight);
        List<ApplyInfoVO> infoVOList = new ArrayList<>();
        if (Objects.nonNull(orderDO.getSpecialVWeight()) && orderDO.getSpecialVWeight().compareTo(BigDecimal.ZERO) > 0) {
            // 泡重优惠值特价,重新判断收费泡重数据
            orderDO.setVWeight(orderDO.getVWeight().compareTo(orderDO.getSpecialVWeight()) < 0 ? orderDO.getVWeight() : orderDO.getSpecialVWeight());
            ApplyInfoVO infoVO = new ApplyInfoVO();
            infoVO.setName("特价泡重优惠值");
            infoVO.setNewValue(orderDO.getSpecialVWeight().setScale(2, RoundingMode.HALF_UP).toString());
            infoVOList.add(infoVO);
        }
        if (orderDO.getOrderType() == 3 && Objects.nonNull(orderDO.getPickleType()) && orderDO.getPickleType() == 2) {
            // 半泡收费公式=((泡重-实重) * 0.5)+实重，如订单实重10kg，泡重30kg，半泡=((30-10) * 0.5) + 10=20kg
            BigDecimal halfBubbleWeight = ((vWeight.subtract(totalWeight)).multiply(new BigDecimal("0.5"))).add(totalWeight).setScale(2, RoundingMode.HALF_UP);
            orderDO.setVWeight(orderDO.getVWeight().compareTo(halfBubbleWeight) < 0 ? orderDO.getVWeight() : halfBubbleWeight);
            ApplyInfoVO infoVO = new ApplyInfoVO();
            infoVO.setName("半泡收费值");
            infoVO.setNewValue(String.format("((泡重%s-实重%s) * 半泡比例0.5)+实重%s = 半泡收费值%s", vWeight, totalWeight, totalWeight, halfBubbleWeight));
            infoVO.setNewValue(halfBubbleWeight.toString());
            infoVOList.add(infoVO);
        }
        // 渠道泡货比例计算
        if (orderDO.getOrderType() == 3 && Objects.nonNull(channelBubbleWeightRatio)) {
            // 渠道泡重收费公式=((泡重-实重) * 渠道泡重比例)+实重，如订单实重10kg，泡重30kg， 渠道泡重比例40%，半泡=((30-10) * 0.4) + 10 = 18kg
            orderDO.setBubbleWeightRatio(channelBubbleWeightRatio);
            BigDecimal channelBubbleWeight = ((vWeight.subtract(totalWeight)).multiply(channelBubbleWeightRatio)).add(totalWeight).setScale(2, RoundingMode.HALF_UP);
            orderDO.setVWeight(orderDO.getVWeight().compareTo(channelBubbleWeight) < 0 ? orderDO.getVWeight() : channelBubbleWeight);
            ApplyInfoVO infoVO = new ApplyInfoVO();
            infoVO.setName("渠道泡重比例收费值");
            infoVO.setNewValue(String.format("((泡重%s-实重%s) * 渠道泡重比%s)+实重%s = 渠道泡重比例收费值%s", vWeight, totalWeight, channelBubbleWeightRatio, totalWeight, channelBubbleWeight));
            infoVOList.add(infoVO);
        }
        if (CollectionUtil.isNotEmpty(infoVOList) && infoVOList.size() > 0
                && orgTotalVWeight.compareTo(orderDO.getVWeight()) != 0) {
            // 泡货收费值计算日志, 当计算数据变动时，再添加日志
            this.addOrderOperateLog(orderDO.getOrderId(),
                    null, "泡货收费值取最低值变动", infoVOList);
        }
        orderDO.setOrgWVolume(totalWeight.divide(orderDO.getOrgWeightUnit(), 2, RoundingMode.HALF_UP));
        BigDecimal orgVWeight = totalVolume.multiply(orderDO.getOrgVolumeUnit()).setScale(2, RoundingMode.HALF_UP);

        orderDO.setOrgVWeight(orgVWeight);
        for (OrderItemDO it : orderItemDOList) {
            WarehouseInInfoVO warehouseInInfoVO = it.getWarehouseInInfoVO();
            if (Objects.nonNull(warehouseInInfoVO)) {
                // 已入仓的订单做处理
                BigDecimal weight = warehouseInInfoVO.getWeight();
                BigDecimal orgWeight = warehouseInInfoVO.getWeight();
                BigDecimal volume = warehouseInInfoVO.getVolume();
                BigDecimal orgVolume = warehouseInInfoVO.getVolume();
                Integer quantity = warehouseInInfoVO.getQuantityAll();
                Integer num = warehouseInInfoVO.getCartonsNum();
                if (orderDO.getOrderType() == 2 && it.getItemType() == 2) {
                    // 重货订单商品的收费体积=(订单总收费体积-商品总入仓体积)*(商品入仓重量/订单中商品为重货的总重量)+商品入仓体积
                    if (Objects.nonNull(weight) && weight.compareTo(BigDecimal.ZERO) > 0 && heavyCargoTotalWeight.compareTo(BigDecimal.ZERO) > 0) {
                        it.setWeightRatio(weight.divide(heavyCargoTotalWeight, 5, RoundingMode.HALF_UP));
                    }
                    volume = Objects.nonNull(it.getWeightRatio()) && it.getWeightRatio().compareTo(BigDecimal.ZERO) > 0 && totalVolume.compareTo(BigDecimal.ZERO) > 0 ?
                            (it.getWeightRatio().multiply(orderDO.getWVolume().subtract(totalVolume)).setScale(2, RoundingMode.HALF_UP)).add(volume) : volume;
                    // TODO 待确认重货标准是否也区分原应收来计算订单是否为重货
                    orgVolume = Objects.nonNull(it.getWeightRatio()) && it.getWeightRatio().compareTo(BigDecimal.ZERO) > 0 && totalVolume.compareTo(BigDecimal.ZERO) > 0 ?
                            (it.getWeightRatio().multiply(orderDO.getOrgWVolume().subtract(totalVolume)).setScale(2, RoundingMode.HALF_UP)).add(orgVolume) : orgVolume;
                }
                if (orderDO.getOrderType() == 3 && it.getItemType() == 3) {
                    // 泡货订单商品的收费重量=(订单总收费重量-商品总入仓重量)*(商品入仓体积/订单中商品为泡货的总体积)+商品入仓重量
                    if (Objects.nonNull(volume) && volume.compareTo(BigDecimal.ZERO) > 0 && pickledGoodsTotalVolume.compareTo(BigDecimal.ZERO) > 0) {
                        it.setVolumeRatio(volume.divide(pickledGoodsTotalVolume, 5, RoundingMode.HALF_UP));
                    }
                    weight = Objects.nonNull(it.getVolumeRatio()) && it.getVolumeRatio().compareTo(BigDecimal.ZERO) > 0 && totalWeight.compareTo(BigDecimal.ZERO) > 0 ?
                            (it.getVolumeRatio().multiply(orderDO.getVWeight().subtract(totalWeight)).setScale(2, RoundingMode.HALF_UP)).add(weight) : weight;
                    // TODO 待确认泡货标准是否也区分原应收来计算订单是否为泡货
                    orgWeight = Objects.nonNull(it.getVolumeRatio()) && it.getVolumeRatio().compareTo(BigDecimal.ZERO) > 0 && totalWeight.compareTo(BigDecimal.ZERO) > 0 ?
                            (it.getVolumeRatio().multiply(orderDO.getOrgVWeight().subtract(totalWeight)).setScale(2, RoundingMode.HALF_UP)).add(orgWeight) : orgWeight;
                }
                it.setChargeWeight(weight);
                it.setChargeVolume(volume);
                it.setChargeQuantity(Objects.isNull(quantity) ? BigDecimal.ZERO : new BigDecimal(quantity));

                it.setOrgChargeWeight(orgWeight);
                it.setOrgChargeVolume(orgVolume);
                it.setOrgChargeQuantity(Objects.isNull(quantity) ? BigDecimal.ZERO : new BigDecimal(quantity));
                it.setOrgChargeNum(num);
            } else {
                it.setChargeWeight(BigDecimal.ZERO);
                it.setChargeVolume(BigDecimal.ZERO);
                it.setChargeQuantity(BigDecimal.ZERO);
            }
        }
    }

    /**
     * 计算单种运输方式的商品费用，并批量插入
     *
     * @param userId                      操作用户
     * @param orderItemDOList             商品列表
     * @param consignorCustomerId         发货客户ID
     * @param consigneeCustomerId         收货客户ID
     * @param consignorCustomerContactsId 发货客户联系人ID
     * @param consigneeCustomerContactsId 收货客户联系人ID
     * @param type                        类型 ： 1 新增 2 修改 3 实测入仓信息 4 合单
     *                                    5 拆单 6 处理未报价异常 7 特价申请 8 订单货值修改
     *                                    9 处理重泡货异常 10 已入仓订单修改重订价 11
     *                                    处理渠道异常 12 处理单询异常 13 处理超重异常
     *                                    14 批量加价 15 完成入仓
     *                                    16 分拣完成锁定价格 17 分拣反审解除锁定价格
     *                                    20 强制重订价格  30 空运订单每日定时更新价格
     *                                    40 订单异常处理完成更新计价
     *                                    50 更新订单优惠信息
     * @return 该运输方式下的报价商品列表信息
     */
    private CalculationItemFeeDto insertOrderItemDOList(String userId,
                                                        List<OrderItemDO> orderItemDOList,
                                                        OrderDO orderDO,
                                                        Long consignorCustomerId,
                                                        Long consigneeCustomerId,
                                                        Long consignorCustomerContactsId,
                                                        Long consigneeCustomerContactsId,
                                                        Integer type) {
        List<ProdConditionParam> prodConditionParamList =
                new ArrayList<>();
        for (OrderItemDO orderItemDO : orderItemDOList) {
            ProductDO productDO =
                    productService.info(orderItemDO.getProdId());
            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 && type != 8 && type != 20) {
                    //订单【#订单编号#】包含不接受货物【#商品名称#】，请检查
                    throw exception(ORDER_NO_CONTAIN_NOT_ACCEPTED_PROD,
                            orderDO.getOrderNo(),
                            I18nMessage.getLang() == 0 ? productDO.getTitleZh() : productDO.getTitleEn());
                }
            }
            if (null == orderItemDO.getNum()) {
                throw exception(PROD_NUM_NOT_NULL,
                        I18nMessage.getLang() == 0 ? productDO.getTitleZh() : productDO.getTitleEn());
            }
            if (null == orderItemDO.getQuantity()) {
                throw exception(PROD_QUANTITY_NOT_NULL,
                        I18nMessage.getLang() == 0 ? productDO.getTitleZh() : productDO.getTitleEn());
            }
            if (null == orderItemDO.getVolume()) {
                throw exception(PROD_VOLUME_NOT_NULL,
                        I18nMessage.getLang() == 0 ? productDO.getTitleZh() : productDO.getTitleEn());
            }
            if (null == orderItemDO.getWeight()) {
                throw exception(PROD_WEIGHT_NOT_NULL,
                        I18nMessage.getLang() == 0 ? productDO.getTitleZh() : productDO.getTitleEn());
            }
            orderItemDO.setTransportId(orderDO.getTransportId());
            orderItemDO.setLineId(orderDO.getLineId());
            orderItemDO.setChannelId(orderDO.getChannelId());
            orderItemDO.setOrderId(orderDO.getOrderId());
            orderItemDO.setOrderNo(orderDO.getOrderNo());

            orderItemDO.setUpdater(userId);
            orderItemDO.setUpdateTime(new Date());


            if (Objects.isNull(orderItemDO.getOrderItemId())) {
                // 如果订单项id不存在，则先保存获得订单项id
                orderItemMapper.insert(orderItemDO);
            }

            //入仓信息，新建订单时入仓信息为空
            WarehouseInInfoVO warehouseInInfoVO =
                    orderItemDO.getWarehouseInInfoVO();
//            if (type == 30 || type == 10) {
//                // 空运自动刷新价格和订单修改价格变动，需要将之前的特价、
//                渠道/单询/超限自定义价格、拆单自定义价格等全部重置
//                orderItemDO.setSpecialPriceType(false);
//                orderItemDO.setSplitCustomPriceType(false);
//                orderItemDO.setChannelManualPricing(false);
//            }
            orderItemDO.setProdTitleZh(productDO.getTitleZh());
            orderItemDO.setProdTitleEn(productDO.getTitleEn());
            orderItemDO.setProdType(
                    Integer.valueOf(String.valueOf(productDO.getTypeId())));
            orderItemDO.setMaterial(productDO.getMaterialType());
            // 给出商品是否为待确认商品的判断，方便后面判断是否生成未报价异常，
            //如果是待确认商品是不用去生成未报价异常的，确认后再计价判断是否生成未报价异常
            orderItemDO.setIsProd(productDO.getStatus() == 1);
            //计价参数
            ProdConditionParam param = new ProdConditionParam();
            param.setItemId(orderItemDO.getOrderItemId());

            param.setItemType(orderItemDO.getItemType());
            param.setNeedOrderInquiry(orderItemDO.getNeedOrderInquiry());

            //计较重量
            param.setChargeWeight(
                    Objects.nonNull(orderItemDO.getWarehouseInInfoVO()) ? orderItemDO.getChargeWeight() :
                            (Objects.equals(orderDO.getStatus(), OrderStatusEnum.DRAFT.getValue()) ||
                                    Objects.equals(orderDO.getStatus(), OrderStatusEnum.ORDER_PLACED.getValue()) ?
                                    orderItemDO.getWeight() : null)
            );
            //计价体积
            param.setChargeVolume(
                    Objects.nonNull(orderItemDO.getWarehouseInInfoVO()) ?
                            orderItemDO.getChargeVolume() :
                            (Objects.equals(orderDO.getStatus(), OrderStatusEnum.DRAFT.getValue()) ||
                                    Objects.equals(orderDO.getStatus(), OrderStatusEnum.ORDER_PLACED.getValue()) ? orderItemDO.getVolume() : null)
            );

            param.setChargeQuantity(Objects.nonNull(orderItemDO.getWarehouseInInfoVO()) ?
                    orderItemDO.getChargeQuantity() : (Objects.equals(orderDO.getStatus(), OrderStatusEnum.DRAFT.getValue()) || Objects.equals(orderDO.getStatus(), OrderStatusEnum.ORDER_PLACED.getValue()) ? new BigDecimal(orderItemDO.getQuantity()) : null));

            param.setOrgChargeNum(Objects.nonNull(orderItemDO.getWarehouseInInfoVO()) ? orderItemDO.getOrgChargeNum() : 0);
            param.setOrgChargeQuantity(Objects.nonNull(orderItemDO.getWarehouseInInfoVO()) ? orderItemDO.getOrgChargeQuantity() : BigDecimal.ZERO);
            param.setOrgChargeVolume(Objects.nonNull(orderItemDO.getWarehouseInInfoVO()) ? orderItemDO.getOrgChargeVolume() : BigDecimal.ZERO);
            param.setOrgChargeWeight(Objects.nonNull(orderItemDO.getWarehouseInInfoVO()) ? orderItemDO.getOrgChargeWeight() : BigDecimal.ZERO);

            param.setTotalChargeQuantity(orderItemDO.getTotalChargeQuantity());
            param.setHeavyCargoTotalChargeVolume(orderItemDO.getHeavyCargoTotalChargeVolume());
            param.setCommonGoodsTotalChargeVolume(orderItemDO.getCommonGoodsTotalChargeVolume());
            param.setPickledGoodsTotalChargeWeight(orderItemDO.getPickledGoodsTotalChargeWeight());
            param.setCommonGoodsTotalChargeWeight(
                    orderItemDO.getCommonGoodsTotalChargeWeight());

            param.setSpecialPriceType(
                    Objects.nonNull(orderItemDO.getSpecialPriceType()) && orderItemDO.getSpecialPriceType());
            param.setSplitCustomPriceType(
                    Objects.nonNull(orderItemDO.getSplitCustomPriceType()) && orderItemDO.getSplitCustomPriceType());
            param.setChannelManualPricing(
                    Objects.nonNull(orderItemDO.getChannelManualPricing()) && orderItemDO.getChannelManualPricing());
            // 空运订单自动刷新价格时，需要忽略这里，一律重新定价,
            // 当type等于30时是空运每日定时刷新价格，只针对待入仓、入仓中、已入仓-待出空运订单
            if ((Objects.nonNull(orderItemDO.getSpecialPriceType()) &&
                    orderItemDO.getSpecialPriceType() && !orderItemDO.getIsPriced())
                    || (Objects.nonNull(orderItemDO.getSplitCustomPriceType()) && orderItemDO.getSplitCustomPriceType())
                    || (Objects.nonNull(orderItemDO.getChannelManualPricing()) && orderItemDO.getChannelManualPricing())) {
                orderItemDO.setIsPriced(Boolean.TRUE);
            } else {
                orderItemDO.setIsPriced(Objects.nonNull(orderItemDO.getIsPriced()) && Objects.nonNull(orderItemDO.getItemStatus()) && orderItemDO.getItemStatus() != -1 ?
                        orderItemDO.getIsPriced() : Boolean.FALSE);
            }
            //类型 ：1 新增 2 修改 3 实测入仓信息 4 合单 5 拆单 6 处理未报价异常
            // 7 特价申请 8 订单货值修改
            //9 处理重泡货异常 10 已入仓订单修改重订价 11 处理渠道异常 12 处理单询异常
            // 13 处理超重异常 14 批量加价 15 完成入仓
            //20 强制重订价格  30 空运订单每日定时更新价格 40 订单异常处理完成更新计价
            // 50 更新订单优惠信息
            if (type == 2 || (type == 4 && orderDO.getTransportId() == 3) ||
                    type == 6 || type == 10 || type == 20 || type == 30
                    || (type == 15 && (Objects.isNull(orderDO.getParentOrderId())
                    || orderDO.getParentOrderId() == 0L ||
                    orderDO.getSplitSeparateOrder()))) {
                // 拆单后的子订单入仓不需要重新定价，
                // 但涉及了空运拆单的会标记为独立订单，走一样的逻辑
                // 第一次入仓或后面的重新入仓都需要更新基础单价,
                // 特价需要在计价时单独判断，不去更新成交单价
                // 未报价异常处理需要重新定价
                // 处理重泡货异常也需要重新定价
                // 编辑修改订单重新定价
                // 手动强制重订价
                // 空运订单分拣反审解除价格锁定
                orderItemDO.setIsPriced(Boolean.FALSE);
            }
            // 处理重泡货异常时，标记计价类型，如果是阶梯价格，则需要重新计价，
            // 如果是非阶梯价格,则不用重新计价
            if (type == 9) {
                param.setIsChangeFeeValue(true);
            }
            param.setSpecialCommission(Objects.nonNull(
                    orderItemDO.getSpecialCommission()) &&
                    orderItemDO.getSpecialCommission());
            param.setCommissionType(orderItemDO.getCommissionType());
            param.setHiddenCommission(orderItemDO.getHiddenCommission());
            param.setPlainCommission(orderItemDO.getPlainCommission());

            param.setMinMeteringQuantity(orderItemDO.getMinMeteringQuantity());
            param.setMinMeteringVolume(orderItemDO.getMinMeteringVolume());
            param.setMinMeteringWeight(orderItemDO.getMinMeteringWeight());

            param.setLiquidFreightPrice(orderItemDO.getLiquidFreightPrice());
            param.setLiquidClearanceFeePrice(orderItemDO.getLiquidClearanceFeePrice());
            param.setElectrifiedFreightPrice(orderItemDO.getElectrifiedFreightPrice());
            param.setElectrifiedClearanceFeePrice(orderItemDO.getElectrifiedClearanceFeePrice());
            param.setBrandFreightPrice(orderItemDO.getBrandFreightPrice());
            param.setBrandClearanceFeePrice(orderItemDO.getBrandClearanceFeePrice());
            param.setPackagingFreightPrice(orderItemDO.getPackagingFreightPrice());
            param.setPackagingClearanceFeePrice(orderItemDO.getPackagingClearanceFeePrice());
            param.setDiscountFreightPrice(orderItemDO.getDiscountFreightPrice());
            param.setDiscountFreightTotalPrice(orderItemDO.getDiscountFreightTotalPrice());
            param.setDiscountClearanceFeePrice(orderItemDO.getDiscountClearanceFeePrice());
            param.setDiscountClearanceFeeTotalPrice(orderItemDO.getDiscountClearanceFeeTotalPrice());
            param.setIsPriced(orderItemDO.getIsPriced());
            param.setOrderType(orderDO.getOrderType());
            param.setProdId(orderItemDO.getProdId());
            param.setProdTitleEn(productDO.getTitleEn());
            param.setProdTitleZh(productDO.getTitleZh());
            param.setProductType(Integer.valueOf(String.valueOf(productDO.getTypeId())));
            // 入仓业务增加了单独的存储特性，所以这里需要区分入仓前后的品名特性字段值
            if (Objects.isNull(warehouseInInfoVO) ||
                    warehouseInInfoVO.getCartonsNum() == 0) {
                // 填单特性以前端传值为准, 需要排除前端传值数据正确性，对以删除的数据进行筛选
                if (Objects.isNull(orderItemDO.getProdAttrIds())) {
                    // 为保证更新品名的特性值，如果特性为null，则需要默认给值空字符串，以保证更新成功
                    orderItemDO.setProdAttrIds("");
                }
                if (StringUtils.isNotBlank(orderItemDO.getProdAttrIds())) {
                    orderItemDO.setProdAttrIds(
                            this.filterProdAttrIds(orderItemDO.getProdAttrIds()));
                }
                orderItemDO.setFillProdAttrIds(orderItemDO.getProdAttrIds());
                //将前端传值的填单特性转存入填单商品特性字段
                param.setProdAttrIds(orderItemDO.getProdAttrIds());
                //未入仓取填单包装单位
                param.setPackages(Collections.singletonList(orderItemDO.getUnit()));
            } else {
                // 入仓特性以前端传值为
                if (Objects.isNull(orderItemDO.getWarehouseInProdAttrIds())) {
                    // 为保证更新品名的特性值，如果特性为null，则需要默认给值空字符串，以保证更新成功
                    orderItemDO.setWarehouseInProdAttrIds("");
                }
                param.setProdAttrIds(orderItemDO.getWarehouseInProdAttrIds());
                if (StringUtils.isNotBlank(orderItemDO.getWarehouseInProdAttrIds())) {
                    // 实时更新使用中的商品特性，有入仓值则取入仓值
                    orderItemDO.setProdAttrIds(this.filterProdAttrIds(orderItemDO.getWarehouseInProdAttrIds()));
                }
                // 入仓后的包装单位优先取全部入仓记录的包装单位, 兼容老入仓数据，当全部包装单位记录不存在时，取默认值
                if (StringUtils.isNotBlank(warehouseInInfoVO.getUnits())) {
                    // 逗号分割后去重转集合参数
                    param.setPackages(Arrays.stream(warehouseInInfoVO.getUnits().split(StrUtil.COMMA)).distinct().collect(Collectors.toList()));
                } else {
                    // 已入仓取入仓包装单位
                    param.setPackages(Collections.singletonList(warehouseInInfoVO.getUnit()));
                }
            }
            if (Objects.equals(orderDO.getStatus(), OrderStatusEnum.ORDER_PLACED.getValue()) || Objects.equals(orderDO.getStatus(), OrderStatusEnum.DRAFT.getValue())) {
                BigDecimal alreadyExistsTotalVolume = orderMapper.getOrderTotalVolumeByDeliveryDate(orderDO.getDeliveryDate(), orderItemDO.getProdId(), orderItemDO.getOrderItemId());
                param.setAlreadyExistsTotalVolume(Objects.isNull(alreadyExistsTotalVolume) ? BigDecimal.ZERO : alreadyExistsTotalVolume);
            }

            if (null != orderItemDO.getOneSeaFreight() &&
                    orderItemDO.getOneSeaFreight().compareTo(BigDecimal.ZERO) > 0) {
                //商品运费单价(成交)
                param.setOneFreight(orderItemDO.getOneSeaFreight());
            }
            if (null != orderItemDO.getOneClearanceFreight() &&
                    orderItemDO.getOneClearanceFreight().compareTo(BigDecimal.ZERO) > 0) {
                //商品清关费单价(成交)
                param.setOneClearanceFee(orderItemDO.getOneClearanceFreight());
            }
            if (Objects.nonNull(warehouseInInfoVO)) {
                param.setNum(warehouseInInfoVO.getCartonsNum());
                param.setQuantity(warehouseInInfoVO.getQuantityAll());
                param.setVolume(warehouseInInfoVO.getVolume());
                param.setWeight(warehouseInInfoVO.getWeight());
                if (null == orderItemDO.getWorth()) {
                    orderItemDO.setWorth(BigDecimal.ZERO);
                }
            } else {
                if (null == orderItemDO.getWorth()) {
                    throw exception(PROD_WORTH_NOT_NULL, I18nMessage.getLang() == 0 ? productDO.getTitleZh() : productDO.getTitleEn());
                }
                param.setNum(type == 1 || type == 2 ? orderItemDO.getNum() : 0);
                param.setQuantity(type == 1 || type == 2 ? orderItemDO.getQuantity() : 0);
                param.setVolume(type == 1 || type == 2 ? orderItemDO.getVolume() : BigDecimal.ZERO);
                param.setWeight(type == 1 || type == 2 ? orderItemDO.getWeight() : BigDecimal.ZERO);
            }
            param.setWVolume(Objects.isNull(orderItemDO.getWVolume()) ? BigDecimal.ZERO : orderItemDO.getWVolume());
            param.setVWeight(Objects.isNull(orderItemDO.getVWeight()) ? BigDecimal.ZERO : orderItemDO.getVWeight());
            param.setCharging(orderItemDO.getCharging());
            param.setIsPayAdvance(orderItemDO.getIsPayAdvance());
            param.setWorth(orderItemDO.getWorth());
            param.setWorthCurrency(orderItemDO.getWorthCurrency());
            param.setBoxGauge(orderItemDO.getBoxGauge());
            if (Objects.isNull(warehouseInInfoVO)) {
                // 未入仓则以填单值为准
                param.setBrandType(orderItemDO.getBrandType());
            } else {
                param.setBrandType(orderItemDO.getFeeType());
            }
            //价格修改只限定在报价单中，不修改原价
            //商品运费单价(成交)
            param.setOneFreight(orderItemDO.getOneSeaFreight());
            //商品运费单价(原始单价)
            param.setOrgFreightPrice(orderItemDO.getOriginalSeaFreight());

            param.setFreightCurrency(Objects.isNull(orderItemDO.getSeaFreightCurrency()) ? null : Integer.valueOf(String.valueOf(orderItemDO.getSeaFreightCurrency())));
            param.setFreightVolume(orderItemDO.getSeaFreightVolume());
            //商品清关费单价(成交)
            param.setOneClearanceFee(orderItemDO.getOneClearanceFreight());
            param.setOrgClearanceFeePrice(orderItemDO.getOriginalClearanceFreight());
            param.setClearanceFeeCurrency(Objects.isNull(orderItemDO.getClearanceFreightCurrency()) ? null : Integer.valueOf(String.valueOf(orderItemDO.getClearanceFreightCurrency())));
            param.setClearanceFeeVolume(orderItemDO.getClearanceFreightVolume());
            if (type == 50) {
                param.setCalculationType(6);
            } else if (type == 14) {
                // 批量加价
                param.setMarkupSeaFreight(orderItemDO.getMarkupSeaFreight());
                param.setMarkupClearanceFreight(orderItemDO.getMarkupClearanceFreight());
                param.setCalculationType(5);
            } else {
                param.setCalculationType(1);
            }
            prodConditionParamList.add(param);
        }

        boolean isWarehouseIn = false;
        if (!Objects.equals(orderDO.getStatus(),
                OrderStatusEnum.ORDER_PLACED.getValue()) &&
                !Objects.equals(orderDO.getStatus(), OrderStatusEnum.DRAFT.getValue())) {
            isWarehouseIn = true;
        }
        // 定单价费用
        List<ProdConditionParam> prodConditionParams =
                prodCostCalculation.obtainProdLineOnePrice(
                        prodConditionParamList,
                        orderDO.getOrderNo(),
                        orderDO.getCustomsType(),
                        orderDO.getCustomerId(),
                        orderDO.getTransportId(),
                        orderDO.getLineId(),
                        orderDO.getChannelId(), isWarehouseIn);
        //  对订单品名的收费数据进行误差补全，单价最低的品名加上误差值
        if (type != 1 && type != 2 && !Objects.equals(orderDO.getStatus(),
                OrderStatusEnum.ORDER_PLACED.getValue()) && !Objects.equals(orderDO.getStatus(), OrderStatusEnum.DRAFT.getValue())) {
            // 只要不是草稿和待入仓订单，都会对此进行计算, 对误差值进行调整
            errorValueAdjustment(orderItemDOList,
                    orderDO,
                    prodConditionParams);
        }
        // 计算小计费用
        CalculationCostResultDto resultDto =
                prodCostCalculation.calculationProdCost(prodConditionParams,
                        orderDO.getOrderNo(),
                        orderDO.getOrderType(),
                        orderDO.getCustomsType(),
                        orderDO.getIsCargoControl() ? 1 : 0, orderDO.getUserId(),
                        orderDO.getCustomerId(),
                        consignorCustomerId,
                        consigneeCustomerId,
                        consignorCustomerContactsId,
                        consigneeCustomerContactsId,
                        orderDO.getTransportId(),
                        orderDO.getLineId(),
                        orderDO.getChannelId());

        for (OrderItemDO orderItemDO : orderItemDOList) {
            for (ProdCostDto prodCostDto : resultDto.getProdCostDtoList()) {
                if (Objects.equals(prodCostDto.getItemId(), orderItemDO.getOrderItemId())) {

                    orderItemDO.setOriginalSeaFreight(prodCostDto.getOrgFreightPrice());
                    orderItemDO.setOneSeaFreight(prodCostDto.getOneFreight());
                    orderItemDO.setDiscountFreightPrice(prodCostDto.getDiscountFreightPrice());
                    orderItemDO.setDiscountFreightTotalPrice(prodCostDto.getDiscountFreightTotalPrice());
                    orderItemDO.setSeaFreight(prodCostDto.getFreight());
                    orderItemDO.setReceivableSeaFreight(prodCostDto.getReceivableSeaFreight());
                    orderItemDO.setSeaFreightVolume(prodCostDto.getFreightVolume());
                    orderItemDO.setSeaFreightCurrency(prodCostDto.getFreightCurrency());

                    orderItemDO.setNeedOrderInquiry(prodCostDto.getNeedOrderInquiry());
                    orderItemDO.setLiquidFreightPrice(prodCostDto.getLiquidFreightPrice());
                    orderItemDO.setLiquidClearanceFeePrice(prodCostDto.getLiquidClearanceFeePrice());
                    orderItemDO.setElectrifiedFreightPrice(prodCostDto.getElectrifiedFreightPrice());
                    orderItemDO.setElectrifiedClearanceFeePrice(prodCostDto.getElectrifiedClearanceFeePrice());
                    orderItemDO.setBrandFreightPrice(prodCostDto.getBrandFreightPrice());
                    orderItemDO.setBrandClearanceFeePrice(prodCostDto.getBrandClearanceFeePrice());
                    orderItemDO.setPackagingFreightPrice(prodCostDto.getPackagingFreightPrice());
                    orderItemDO.setPackagingClearanceFeePrice(prodCostDto.getPackagingClearanceFeePrice());

                    orderItemDO.setProductPriceEmptyType(prodCostDto.getProductPriceEmptyType());
                    orderItemDO.setChannelPriceEmptyType(prodCostDto.getChannelPriceEmptyType());
                    orderItemDO.setIsAirWeightLimit(prodCostDto.getIsAirWeightLimit());

                    // 这里的未报价状态只看订单运费，清关费有单独的处理方式(海运相关没有清关费就是全包价的业务，空运有单独的清关费未报价异常)
                    // 当未报价品名通过处理其他异常自定义价格后，产生了成交单价，不再是未设置价格
                    if ((Objects.isNull(orderItemDO.getSpecialPriceType()) || !orderItemDO.getSpecialPriceType())
                            && (Objects.isNull(orderItemDO.getSplitCustomPriceType()) || !orderItemDO.getSplitCustomPriceType())
                            && (Objects.isNull(orderItemDO.getChannelManualPricing()) || !orderItemDO.getChannelManualPricing())
                            && orderItemDO.getOriginalSeaFreight().compareTo(BigDecimal.ZERO) == 0) {
                        orderItemDO.setItemStatus(-1);// 未设置价格
                    } else {
                        orderItemDO.setItemStatus(0); // 订单有设置价格则改默认值为0
                    }

                    if (Objects.isNull(orderItemDO.getSpecialCommission()) || !orderItemDO.getSpecialCommission()) {
                        orderItemDO.setCommissionType(prodCostDto.getCommissionType());
                        orderItemDO.setPlainCommission(prodCostDto.getPlainCommission());
                        orderItemDO.setHiddenCommission(prodCostDto.getHiddenCommission());
                    }
                    if (Objects.isNull(orderItemDO.getWorthCurrency())) {
                        orderItemDO.setWorthCurrency(prodCostDto.getWorthCurrency());
                    }
                    orderItemDO.setMinMeteringQuantity(prodCostDto.getMinMeteringQuantity());
                    orderItemDO.setMinMeteringVolume(prodCostDto.getMinMeteringVolume());
                    orderItemDO.setMinMeteringWeight(prodCostDto.getMinMeteringWeight());

                    orderItemDO.setOriginalClearanceFreight(prodCostDto.getOrgClearanceFeePrice());
                    orderItemDO.setOneClearanceFreight(prodCostDto.getOneClearanceFee());
                    orderItemDO.setDiscountClearanceFeePrice(prodCostDto.getDiscountClearanceFeePrice());
                    orderItemDO.setDiscountClearanceFeeTotalPrice(prodCostDto.getDiscountClearanceFeeTotalPrice());
                    orderItemDO.setClearanceFreight(prodCostDto.getClearanceFee());
                    orderItemDO.setReceivableClearanceFreight(prodCostDto.getReceivableClearanceFreight());
                    orderItemDO.setClearanceFreightVolume(prodCostDto.getClearanceFeeVolume());
                    orderItemDO.setClearanceFreightCurrency(prodCostDto.getClearanceFeeCurrency());
                    if (Objects.equals(TransportTypeShortEnum.AIR_FREIGHT_LINE.getValue(), orderDO.getTransportId())
                            || Objects.equals(TransportTypeShortEnum.AIR_SEA_COMBINED_TRANSPORT.getValue(), orderDO.getTransportId())) {
                        orderItemDO.setAirClearanceSource(prodCostDto.getAirClearanceSource());
                        orderItemDO.setAirClearanceInfo(prodCostDto.getAirClearanceInfo());
                    }
                    if (Objects.nonNull(prodCostDto.getCouponInfoVOList())) {
                        orderItemDO.setCouponInfo(JSONObject.toJSONString(prodCostDto.getCouponInfoVOList()));
                    }

                    if (Objects.equals(TransportTypeShortEnum.AIR_FREIGHT_LINE.getValue(), orderDO.getTransportId())
                            || Objects.equals(TransportTypeShortEnum.AIR_SEA_COMBINED_TRANSPORT.getValue(), orderDO.getTransportId())) {
                        // 空运
                        if (type == 16 && StringUtils.isNotBlank(orderItemDO.getWarehouseInInfo()) && orderItemDO.getOneSeaFreight().compareTo(BigDecimal.ZERO) > 0 && !orderItemDO.getIsPriced()) {
                            //已入仓的商品项，如果未定价，且价格不为0，则标记为已定价
                            orderItemDO.setIsPriced(Boolean.TRUE);
                        } else {
                            orderItemDO.setIsPriced(Objects.nonNull(orderItemDO.getIsPriced()) ? orderItemDO.getIsPriced() : Boolean.FALSE);
                        }
                    } else {
                        // 海运
                        if (StringUtils.isNotBlank(orderItemDO.getWarehouseInInfo()) && orderItemDO.getOneSeaFreight().compareTo(BigDecimal.ZERO) > 0 && !orderItemDO.getIsPriced()) {
                            //已入仓的商品项，如果未定价，且价格不为0，则标记为已定价
                            orderItemDO.setIsPriced(Boolean.TRUE);
                        } else {
                            orderItemDO.setIsPriced(Objects.nonNull(orderItemDO.getIsPriced()) ? orderItemDO.getIsPriced() : Boolean.FALSE);
                        }
                    }
                    orderItemDO.setCharging(prodCostDto.getCharging());
                    orderItemDO.setIsPayAdvance(prodCostDto.getIsPayAdvance());
                }
            }
            if (Objects.isNull(orderItemDO.getItemStatus()) ||
                    orderItemDO.getItemStatus() != -1) {
                updateItem(orderItemDO);
            } else {
                orderItemMapper.updateById(orderItemDO);
            }
        }

        CalculationItemFeeDto dto = new CalculationItemFeeDto();
        CostVO costVO = new CostVO();
        BeanUtils.copyProperties(resultDto.getCostDto(), costVO);
        dto.setCostVO(costVO);
        dto.setOrderItemDOList(orderItemDOList);
        return dto;
    }

    private void errorValueAdjustment(List<OrderItemDO> orderItemDOList, OrderDO orderDO, List<ProdConditionParam> prodConditionParams) {
        // 计算总单价
        this.calculateTotalOnePrice(orderItemDOList, orderDO, prodConditionParams);
        // 只获取非普货最低价格的品名
        OrderItemDO it = orderItemDOList.stream()
                .filter(orderItemDO -> Objects.nonNull(orderItemDO.getWarehouseInInfoVO()) && orderItemDO.getWarehouseInInfoVO().getCartonsNum() > 0 && orderItemDO.getItemType() != 1)
                .min(Comparator.comparing(OrderItemDO::getTotalOnePrice)).orElse(null);
        // 修正重泡货平均值误差
        if (Objects.nonNull(it)) {
            correctionError(orderItemDOList, orderDO, it);
            for (ProdConditionParam param : prodConditionParams) {
                if (Objects.equals(it.getOrderItemId(), param.getItemId())) {
                    // 调整误差值后的数据补充到计价参数中
                    param.setChargeWeight(it.getChargeWeight());
                    param.setMinMeteringWeight(it.getMinMeteringWeight());
                    param.setChargeVolume(it.getChargeVolume());
                    param.setMinMeteringVolume(it.getMinMeteringVolume());
                }
            }
            for (OrderItemDO orderItemDO : orderItemDOList) {
                if (Objects.equals(it.getOrderItemId(), orderItemDO.getOrderItemId())) {
                    // 调整误差值后的数据补充到计价参数中
                    orderItemDO.setChargeWeight(it.getChargeWeight());
                    orderItemDO.setMinMeteringVolume(it.getMinMeteringVolume());
                    orderItemDO.setChargeVolume(it.getChargeVolume());
                    orderItemDO.setMinMeteringWeight(it.getMinMeteringWeight());
                }
            }
        }
        OrderItemDO airItem = orderItemDOList.stream()
                .filter(orderItemDO -> Objects.nonNull(orderItemDO.getWarehouseInInfoVO()) && orderItemDO.getWarehouseInInfoVO().getCartonsNum() > 0)
                .min(Comparator.comparing(OrderItemDO::getTotalOnePrice)).orElse(null);
        // 修正空运补偿重量误差
        if (Objects.nonNull(airItem) && orderDO.getTransportId() == 3) {
            this.correctionAirError(orderItemDOList, orderDO, airItem);
            for (ProdConditionParam param : prodConditionParams) {
                if (Objects.equals(airItem.getOrderItemId(), param.getItemId())) {
                    // 调整误差值后的数据补充到计价参数中
                    param.setChargeWeight(airItem.getChargeWeight());
                    param.setMinMeteringWeight(airItem.getMinMeteringWeight());
                }
            }
            for (OrderItemDO orderItemDO : orderItemDOList) {
                if (Objects.equals(airItem.getOrderItemId(), orderItemDO.getOrderItemId())) {
                    // 调整误差值后的数据补充到计价参数中
                    orderItemDO.setChargeWeight(airItem.getChargeWeight());
                    orderItemDO.setMinMeteringWeight(airItem.getMinMeteringWeight());
                }
            }
        }
    }


    private void correctionAirError(List<OrderItemDO> orderItemDOList, OrderDO orderDO, OrderItemDO it) {
        if (orderDO.getOrderType() == 1) {
            // 判断入仓品名的收费重量是否与订单的泡货重量一致
            BigDecimal sumChargeWeight = orderItemDOList.stream().filter(t -> Objects.nonNull(t.getWarehouseInInfoVO()) && t.getWarehouseInInfoVO().getCartonsNum() > 0)
                    .map(item -> item.getChargeWeight().compareTo(item.getMinMeteringWeight()) >= 0 ? item.getChargeWeight() : item.getMinMeteringWeight())
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal sumWeight = sumChargeWeight;
            // 空运收费重量，总重量小于1kg,按1kg算，大于1kg的小数点后值，不足0.5按0.5加，大于0.5不足1按1.0加，如收费重量3.1=实际收费重量3.5，收费重量4.51=实际收费重量5.0
            if (sumChargeWeight.compareTo(BigDecimal.ONE) < 0) {
                sumChargeWeight = BigDecimal.ONE;
            } else {
                sumChargeWeight = BigDecimalUtils.convertWv(sumChargeWeight);
            }
            if (sumWeight.compareTo(sumChargeWeight) != 0) {
                // 误差值
                BigDecimal errorValue = sumWeight.subtract(sumChargeWeight);
                // 普货差值为负数，需要转正
                if (errorValue.compareTo(BigDecimal.ZERO) < 0) {
                    errorValue = errorValue.negate();
                }
                // 该品名收费重量大于最小计量，以收费重量做偏移量修正，否则以最小计量做偏移量修正
                if (it.getChargeWeight().compareTo(it.getMinMeteringWeight()) >= 0) {
                    it.setChargeWeight(it.getChargeWeight().add(errorValue));
                } else {
                    it.setMinMeteringWeight(it.getMinMeteringWeight().add(errorValue));
                }
            }
        }
        if (orderDO.getOrderType() == 3) {
            // 判断入仓品名的收费重量是否与订单的泡货重量一致
            BigDecimal sumChargeWeight = orderItemDOList.stream().filter(t -> Objects.nonNull(t.getWarehouseInInfoVO()) && t.getWarehouseInInfoVO().getCartonsNum() > 0)
                    .map(item -> item.getChargeWeight().compareTo(item.getMinMeteringWeight()) >= 0 ? item.getChargeWeight() : item.getMinMeteringWeight())
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            // 空运收费重量，总重量小于1kg,按1kg算，大于1kg的小数点后值，不足0.5按0.5加，大于0.5不足1按1.0加，如收费重量3.1=实际收费重量3.5，收费重量4.51=实际收费重量5.0
            if (sumChargeWeight.compareTo(BigDecimal.ONE) < 0) {
                sumChargeWeight = BigDecimal.ONE;
            } else {
                sumChargeWeight = BigDecimalUtils.convertWv(sumChargeWeight);
            }
            BigDecimal errorValue = BigDecimal.ZERO;
            if (orderDO.getVWeight().compareTo(sumChargeWeight) != 0) {
                // 误差值
                errorValue = orderDO.getVWeight().subtract(sumChargeWeight);
                if (errorValue.compareTo(BigDecimal.ZERO) < 0) {
                    errorValue = errorValue.negate();
                }
            }
            if (errorValue.compareTo(BigDecimal.ZERO) > 0) {
                // 该品名收费重量大于最小计量，以收费重量做偏移量修正，否则以最小计量做偏移量修正 ,这里的偏移量有两种，一种是计算泡重平均值时的偏移量，另一种即是
                if (it.getChargeWeight().compareTo(it.getMinMeteringWeight()) >= 0) {
                    it.setChargeWeight(it.getChargeWeight().add(errorValue));
                } else {
                    it.setMinMeteringWeight(it.getMinMeteringWeight().add(errorValue));
                }
            }
        }
    }

    private static void correctionError(List<OrderItemDO> orderItemDOList, OrderDO orderDO, OrderItemDO it) {
        if (orderDO.getOrderType() == 2) {
            // 判断入仓品名的收费体积是否与订单的重货体积一致
            BigDecimal sumChargeVolume = orderItemDOList.stream().filter(t -> Objects.nonNull(t.getWarehouseInInfoVO()) && t.getWarehouseInInfoVO().getCartonsNum() > 0)
                    .map(item -> item.getChargeVolume().compareTo(item.getMinMeteringVolume()) >= 0 ? item.getChargeVolume() : item.getMinMeteringVolume())
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            if (orderDO.getWVolume().compareTo(sumChargeVolume) != 0) {
                // 误差值
                BigDecimal errorValue = orderDO.getWVolume().subtract(sumChargeVolume);
                it.setChargeVolume(it.getChargeVolume().add(errorValue));
                // 该品名收费体积大于最小计量，以收费体积做偏移量修正，否则以最小计量做偏移量修正
                if (it.getChargeVolume().compareTo(it.getMinMeteringVolume()) >= 0) {
                    it.setChargeVolume(it.getChargeVolume().add(errorValue));
                } else {
                    it.setMinMeteringVolume(it.getMinMeteringVolume().add(errorValue));
                }
            }
            if (Objects.nonNull(orderDO.getOrgWVolume())) {
                BigDecimal sumOrgChargeVolume = orderItemDOList.stream().map(OrderItemDO::getOrgChargeVolume).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
                if (orderDO.getOrgWVolume().compareTo(sumOrgChargeVolume) != 0) {
                    // 误差值
                    BigDecimal errorValue = orderDO.getOrgWVolume().subtract(sumOrgChargeVolume);
                    it.setOrgChargeVolume(it.getOrgChargeVolume().add(errorValue));
                }
            }
        }
        if (orderDO.getOrderType() == 3) {
            // 判断入仓品名的收费重量是否与订单的泡货重量一致
            BigDecimal sumChargeWeight = orderItemDOList.stream().filter(t -> Objects.nonNull(t.getWarehouseInInfoVO()) && t.getWarehouseInInfoVO().getCartonsNum() > 0)
                    .map(item -> item.getChargeWeight().compareTo(item.getMinMeteringWeight()) >= 0 ? item.getChargeWeight() : item.getMinMeteringWeight())
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            // 泡货订单，需要先计算泡重与收费数据的偏移量
            if (orderDO.getVWeight().compareTo(sumChargeWeight) != 0) {
                BigDecimal errorValue = orderDO.getVWeight().subtract(sumChargeWeight);
                // 该品名收费重量大于最小计量，以收费重量做偏移量修正，否则以最小计量做偏移量修正 ,这里的偏移量有两种，一种是计算泡重平均值时的偏移量，另一种即是
                if (it.getChargeWeight().compareTo(it.getMinMeteringWeight()) >= 0) {
                    it.setChargeWeight(it.getChargeWeight().add(errorValue));
                } else {
                    it.setMinMeteringWeight(it.getMinMeteringWeight().add(errorValue));
                }
            }
            if (Objects.nonNull(orderDO.getOrgVWeight())) {
                BigDecimal sumOrgChargeWeight = orderItemDOList.stream().map(OrderItemDO::getOrgChargeWeight).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
                if (orderDO.getOrgVWeight().compareTo(sumOrgChargeWeight) != 0) {
                    // 误差值
                    BigDecimal errorValue = orderDO.getOrgVWeight().subtract(sumOrgChargeWeight);
                    // 对最后的值进行误差修正,倒序拦截，获取最后一个入仓订单项的泡货品名收费重量进行误差修正
                    it.setOrgChargeWeight(it.getOrgChargeWeight().add(errorValue));
                }
            }
        }
    }

    /**
     * @param orderDO     订单信息
     * @param orderItemDO 订单项信息
     * @param volume      体积
     * @param weight      重量
     * @param quantity    数量
     */
    private void setItemType(OrderDO orderDO, OrderItemDO orderItemDO, BigDecimal volume, BigDecimal
            weight, Integer quantity) {
        switch (orderDO.getOrderType()) {
            case 2:
                orderItemDO.setItemType(orderItemDO.getWVolume().compareTo(volume) > 0 ? 2 : 1);
                break;
            case 3:
                orderItemDO.setItemType(orderItemDO.getVWeight().compareTo(weight) > 0 ? 3 : 1);
                break;
            default:
                // 普货
                orderItemDO.setItemType(1);
                break;
        }
        // 普货直接取入仓数据集(未入仓直接取填单值)
        if (orderItemDO.getItemType() == 1) {
            orderItemDO.setChargeWeight(weight);
            orderItemDO.setChargeVolume(volume);
            orderItemDO.setChargeQuantity(Objects.isNull(quantity) ? BigDecimal.ZERO : new BigDecimal(quantity));
        }
    }


    private String filterProdAttrIds(String prodAttrIds) {
        List<Long> attrIdList = Arrays.stream(prodAttrIds.split(StrUtil.COMMA)).map(Long::parseLong).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(attrIdList)) {
            // 获取全部的商品特性id
            List<Long> allAttrIdList = productAttrService.getAllAttrId();
            String attrIds = "";
            if (CollectionUtil.isNotEmpty(allAttrIdList)) {
                attrIds = attrIdList.stream().filter(allAttrIdList::contains).map(String::valueOf).collect(Collectors.joining(StrUtil.COMMA));
            }
            return attrIds;
        }
        return "";
    }


    private void calculateTotalOnePrice(List<OrderItemDO> orderItemDOList, OrderDO orderDO, List<ProdConditionParam> prodConditionParams) {
        Long targetId = 1L;// 目标币种，默认美元
        OrderObjectiveDO objectiveDO = orderObjectiveService.getByOrderId(orderDO.getOrderId());
        if (Objects.nonNull(objectiveDO)) {
            RegionDO regionDO = JSONObject.parseObject(objectiveDO.getObjective(), RegionDO.class);
            if (Objects.nonNull(regionDO)) {
                // 进口国运费币种
                String importCurrency1 = regionDO.getImportCurrency1();
                if (StringUtils.isNotBlank(importCurrency1)) {
                    targetId = Long.parseLong(importCurrency1);
                }
            }
        }
        for (OrderItemDO orderItemDO : orderItemDOList) {
            for (ProdConditionParam param : prodConditionParams) {
                if (Objects.equals(param.getItemId(), orderItemDO.getOrderItemId())) {
                    if (Objects.nonNull(orderItemDO.getWarehouseInInfoVO()) && orderItemDO.getWarehouseInInfoVO().getCartonsNum() > 0) {
                        BigDecimal totalOnePrice = BigDecimal.ZERO;
                        if (Objects.nonNull(param.getOneFreight()) && param.getOneFreight().compareTo(BigDecimal.ZERO) > 0) {
                            ExchangeRateRespDTO freightExchangeRate = currencyApi.getCurrencyRate(Long.valueOf(param.getFreightCurrency().toString()), targetId);
                            totalOnePrice = totalOnePrice.add(param.getOneFreight().multiply(freightExchangeRate.getCurrencyRate()).setScale(2, RoundingMode.HALF_UP));
                        }
                        if (param.getCharging() == 0) {
                            if (Objects.nonNull(param.getOneClearanceFee()) && param.getOneClearanceFee().compareTo(BigDecimal.ZERO) > 0) {
                                ExchangeRateRespDTO clearanceExchangeRate = currencyApi.getCurrencyRate(Long.valueOf(param.getClearanceFeeCurrency().toString()), targetId);
                                totalOnePrice = totalOnePrice.add(param.getOneClearanceFee().multiply(clearanceExchangeRate.getCurrencyRate()).setScale(2, RoundingMode.HALF_UP));
                            }
                        }
                        orderItemDO.setTotalOnePrice(totalOnePrice);
                    }
                }
            }
        }
    }


    public void updateItem(OrderItemDO orderItemDO) {
        // 设置订单项的状态类型
        List<OrderExceptionDO> orderExceptionDOList = orderExceptionService.getOrderExceptionByOrderItemId(orderItemDO.getOrderItemId());
        WarehouseInInfoVO warehouseInInfoVO = orderItemDO.getWarehouseInInfoVO();
        if (Objects.isNull(orderExceptionDOList) || CollectionUtil.isEmpty(orderExceptionDOList)) {
            // 没有异常， 判断是否入仓，入仓则是准备到齐(4),否则待入仓(0)
            orderItemDO.setItemStatus(Objects.isNull(warehouseInInfoVO) || warehouseInInfoVO.getCartonsNum() == 0 ? 0 : 4);
        } else {
            // 有异常,判断异常类型
            OrderAbnormalStateEnum abnormalState = OrderAbnormalStateEnum.keyOf(orderExceptionDOList.stream().findFirst().get().getOrderExceptionType());
            switch (abnormalState) {
//                case ORDER_NO_QUOTE_EXCEPTION:
//                    orderItemDO.setItemStatus(-1);
//                    break;
                case ORDER_SUPERFLUOUS_BOX_EXCEPTION:
                    orderItemDO.setItemStatus(2);
                    break;
                case ORDER_LACK_BOX_EXCEPTION:
                    orderItemDO.setItemStatus(3);
                    break;
                default:
                    orderItemDO.setItemStatus(1);
            }
        }
        // TODO 待处理订单项特价审批状态

        orderItemMapper.updateById(orderItemDO);
    }
}
