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

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.MessageFormat;
import java.util.*;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.spring.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO;
import cn.iocoder.yudao.framework.i18n.core.I18nMessage;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.bpm.api.BpmCreateServiceFactory;
import cn.iocoder.yudao.module.bpm.enums.WorkFlowEmus;
import cn.iocoder.yudao.module.bpm.resp.TaskResp;
import cn.iocoder.yudao.module.ecw.api.internalMessage.ClientInternalMessageApi;
import cn.iocoder.yudao.module.ecw.api.internalMessage.dto.InternalMessageCreateDto;
import cn.iocoder.yudao.module.ecw.api.paramValid.ParamValidatorApi;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO;
import cn.iocoder.yudao.module.order.convert.approval.OrderApprovalConvert;
import cn.iocoder.yudao.module.order.dal.dataobject.approval.OrderApprovalDO;
import cn.iocoder.yudao.module.order.dal.dataobject.order.OrderDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderCargoControl.OrderCargoControlDO;
import cn.iocoder.yudao.module.order.dal.mysql.approval.OrderApprovalMapper;
import cn.iocoder.yudao.module.order.dal.mysql.orderCargoControl.OrderCargoControlMapper;
import cn.iocoder.yudao.module.order.dal.mysql.orderPickup.OrderPickupMapper;
import cn.iocoder.yudao.module.order.dto.OrderCargoControlReleaseInfoDto;
import cn.iocoder.yudao.module.order.param.OrderControlLogParam;
import cn.iocoder.yudao.module.order.service.order.OrderBusinessService;
import cn.iocoder.yudao.module.order.service.order.OrderQueryService;
import cn.iocoder.yudao.module.order.service.order.OrderService;
import cn.iocoder.yudao.module.order.service.orderCargoControl.OrderCargoControlService;
import cn.iocoder.yudao.module.order.vo.order.OrderBackPageVO;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
import cn.iocoder.yudao.module.system.api.sms.SmsSendApi;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import cn.iocoder.yudao.framework.mybatis.core.vo.PageVO;
import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService;
import cn.iocoder.yudao.module.order.vo.orderCargoControlPick.*;
import cn.iocoder.yudao.module.order.dal.dataobject.orderCargoControlPick.OrderCargoControlPickDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.order.convert.orderCargoControlPick.OrderCargoControlPickConvert;
import cn.iocoder.yudao.module.order.dal.mysql.orderCargoControlPick.OrderCargoControlPickMapper;

import javax.annotation.Resource;

import static cn.iocoder.yudao.framework.apollo.core.constants.Constants.CUSTOMER_USER_APPROVAL_ID;
import static cn.iocoder.yudao.framework.apollo.core.constants.Constants.CUSTOMER_USER_TO_ADMIN;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.USER_PASSWORD_FAILED;
import static cn.iocoder.yudao.module.order.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum.NOTIFICATION_SUCCESS_DELIVERY;

/**
 * 订单控货人放货记录 Service 实现类
 *
 * @author 郑屹
 */
@Service
@Validated
@Slf4j
public class OrderCargoControlPickServiceImpl extends AbstractService<OrderCargoControlPickMapper, OrderCargoControlPickDO> implements OrderCargoControlPickService {

    @Resource
    private OrderCargoControlPickMapper orderCargoControlPickMapper;
    @Resource
    private OrderCargoControlMapper orderCargoControlMapper;
    @Resource
    private OrderService orderService;
    @Resource
    private OrderBusinessService orderBusinessService;
    @Resource
    private OrderQueryService orderQueryService;

    @Resource
    private OrderPickupMapper orderPickupMapper;
    @Resource
    private OrderCargoControlService orderCargoControlService;
    @Resource
    private SmsCodeApi smsCodeApi;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private ClientInternalMessageApi clientInternalMessageApi;
    @Resource
    private MemberUserApi memberUserApi;
    @Resource
    private SmsSendApi smsSendApi;
    @Resource
    private OrderApprovalMapper orderApprovalMapper;
    @Resource
    private BpmCreateServiceFactory bpmCreateServiceFactory;
    @Resource
    private DictDataApi dictDataApi;
    @Resource
    private ParamValidatorApi paramValidatorApi;

    @Override
    public Long createOrderCargoControlPick(
            OrderCargoControlPickCreateReqVO createReqVO) {
        if (Objects.isNull(createReqVO.getPickNum()) || createReqVO.getPickNum() <= 0) {
            throw exception(ORDER_CARGO_CONTROL_PICK_NUM_NOT_EQ_ZERO);
        }
        if (StringUtils.isBlank(createReqVO.getConsigneeCountryCode())) {
            throw exception(CONSIGNEE_PHONE_CODE_NOT_NULL);
        }
        if (StringUtils.isBlank(createReqVO.getConsigneePhone())) {
            throw exception(CONSIGNEE_PHONE_NOT_NULL);
        }
        // 控货订单放货收货人电话号码不允许填写国内号码
        if (StringUtils.equals(createReqVO.getConsigneeCountryCode(), "86")) {
            throw exception(CONSIGNEE_PHONE_IS_NOT_CHINA);
        }
        String mobileCode = createReqVO.getConsigneeCountryCode() +
                StrUtil.COLON + createReqVO.getConsigneePhone();
        paramValidatorApi.validatorMobile(mobileCode);

        OrderDO orderDO = orderService.getById(createReqVO.getOrderId());
        if (Objects.isNull(orderDO)) {
            throw exception(ORDER_NOT_EXISTS);
        }
        if (orderDO.getCargoControlStatus() == 1) {
            throw exception(ORDER_CARGO_CONTROL_PICK_FINISH);
        }
        // 检查订单是否在收货人限制修改申请中
        long limitUpdateCount = orderApprovalMapper.selectCount(new LambdaQueryWrapper<OrderApprovalDO>()
                .eq(OrderApprovalDO::getOrderId, orderDO.getOrderId())
                .eq(OrderApprovalDO::getType, 61)
                .eq(OrderApprovalDO::getStatus, 1)
        );
        if (limitUpdateCount > 0) {
            throw exception(ORDER_CARGO_CONTROL_CONSIGNEE_LIMIT_UPDATE_APPLYING);
        }
        long overseasWarehouseUpdateCount = orderApprovalMapper.selectCount(new LambdaQueryWrapper<OrderApprovalDO>()
                .eq(OrderApprovalDO::getOrderId, orderDO.getOrderId())
                .eq(OrderApprovalDO::getType, 62)
                .eq(OrderApprovalDO::getStatus, 1)
        );
        if (overseasWarehouseUpdateCount > 0) {
            throw exception(ORDER_CARGO_CONTROL_OVERSEAS_WAREHOUSE_UPDATE_APPLYING);
        }
        //不能大于总箱数
        if (createReqVO.getPickNum() > orderDO.getSumNum()) {
            throw exception(ORDER_CARGO_CONTROL_NUM_GO_BEYOND);
        }
        // 如果控货订单限制修改收货人，则需要判断控货收货人限制修改时间是否到期，且当前放货操作的收货人电话是否有变动
//        if (orderDO.getIsLimitUpdateConsignee() && Objects.isNull(orderDO.getLockConsigneeTime())) {
//            // 当前控货订单限制修改收货人，但是未到仓/卸柜，未查询到限制时间
//            throw exception(ORDER_CARGO_CONTROL_LIMIT_UPDATE_CONSIGNEE_ERROR);
//        }
        // 当前控货订单限制修改收货人，但是未到仓/卸柜(没有限制时间)，或者限制时间未到期
        if (orderDO.getIsLimitUpdateConsignee() && (Objects.isNull(orderDO.getLockConsigneeTime()) || (Objects.nonNull(orderDO.getLockConsigneeTime()) && orderDO.getLockConsigneeTime().compareTo(new Date()) >= 0))) {
            // 控货收货人限制修改时间未到期，需要判断当前放货操作的收货人电话是否有变动
            OrderCargoControlReleaseInfoDto releaseInfoDto = orderCargoControlMapper.getOrderCargoControlReleaseInfo(orderDO.getOrderId());
            if (StringUtils.isBlank(releaseInfoDto.getConsigneeCountryCode()) || StringUtils.isBlank(releaseInfoDto.getConsigneePhone())) {
                throw exception(ORDER_CONSIGNEE_PHONE_INFO_NOT_COMPLETE);
            }
            if (!StringUtils.equals(releaseInfoDto.getConsigneeCountryCode() + releaseInfoDto.getConsigneePhone(), createReqVO.getConsigneeCountryCode() + createReqVO.getConsigneePhone())) {
                throw exception(ORDER_CARGO_CONTROL_LIMIT_UPDATE_CONSIGNEE_INFO);
            }
        }
        int pickNum = 0;
        int pickQuantity = 0;
        BigDecimal pickVolume = BigDecimal.ZERO;
        BigDecimal pickWeight = BigDecimal.ZERO;
        List<OrderCargoControlPickDO> pickDOList =
                orderCargoControlPickMapper.selectList(new LambdaQueryWrapper<OrderCargoControlPickDO>()
                        .eq(OrderCargoControlPickDO::getOrderId, createReqVO.getOrderId())
                        .in(OrderCargoControlPickDO::getStatus, Arrays.asList(1, 2, 3, 4, 5, 6))
                        .eq(OrderCargoControlPickDO::getDeleted, Boolean.FALSE));
        if (CollectionUtil.isNotEmpty(pickDOList)) {
            pickNum = pickDOList.stream().mapToInt(OrderCargoControlPickDO::getPickNum).sum();
            pickQuantity = pickDOList.stream().mapToInt(OrderCargoControlPickDO::getPickQuantity).sum();
            pickVolume = pickDOList.stream().map(OrderCargoControlPickDO::getPickVolume).reduce(BigDecimal.ZERO, BigDecimal::add);
            pickWeight = pickDOList.stream().map(OrderCargoControlPickDO::getPickWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
        }
        if (orderDO.getSumNum() == 0) {
            throw exception(ORDER_CARGO_CONTROL_NOT_NUM);
        }
        if (pickNum >= orderDO.getSumNum()) {
            throw exception(ORDER_CARGO_CONTROL_PICK_FINISH);
        }
        //不能大于可放箱数（总箱数-已放箱数）
        if (createReqVO.getPickNum() > (orderDO.getSumNum() - pickNum)) {
            throw exception(ORDER_CARGO_CONTROL_NUM_OVER);
        }


        OrderCargoControlDO orderCargoControlDO =
                orderCargoControlService.getOne(new LambdaQueryWrapper<OrderCargoControlDO>()
                        .eq(OrderCargoControlDO::getOrderId, createReqVO.getOrderId())
                        .eq(OrderCargoControlDO::getIsActual, Boolean.TRUE)
                        .orderByDesc(OrderCargoControlDO::getId)
                        .last("limit 1"));
        if (Objects.isNull(orderCargoControlDO)) {
            throw exception(ORDER_CARGO_CONTROL_NOT_EXISTS);
        }
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        Long userId = loginUser != null ? loginUser.getId() : null;
        String operator = loginUser != null ? loginUser.getNickname() : "";
        Integer userType = loginUser != null ? loginUser.getUserType() : null;
        String creator = String.valueOf(userId);
        Date now = new Date();
        if (StringUtils.isBlank(createReqVO.getCode()) &&
                StringUtils.isBlank(createReqVO.getControlPassword())) {
            throw exception(ORDER_CARGO_CONTROL_PICK_MUST_CODE_OR_PASSWORD);
        }
        boolean isPasswordError = false; // 是否密码错误
        boolean isPasswordNull = false; // 是否未设置密码
        boolean isPasswordPick = true; // 是否密码放货(默认是)
        if (StringUtils.isNotBlank(createReqVO.getControlPassword())) {
            // 没有短信验证码时就验证控货密码
            UserRespDTO user = memberUserApi.getUserByMobile(orderCargoControlDO.getPhone());
            // 当控货人手机号没有注册web用户，或者用户没有设置控货密码时不能进行控货密码放货
            if ((user == null || StringUtils.isBlank(user.getControlPassword()))) {
                isPasswordNull = true;
//                throw exception(CONTROLLER_USER_NOT_SET_CONTROL_PASSWORD);
            }
            // 参数：未加密密码，编码后的密码
            if (Objects.nonNull(user) && StringUtils.isNotBlank(user.getControlPassword()) && (!passwordEncoder.matches(createReqVO.getControlPassword(), user.getControlPassword()))) {
                isPasswordError = true;
//                throw exception(USER_PASSWORD_FAILED);
            }
        }

        if (StringUtils.isNotBlank(createReqVO.getCode()) &&
                (StringUtils.isBlank(createReqVO.getControlPassword()) ||
                        isPasswordError || isPasswordNull)) {
            //验证放货短信验证码
            SmsCodeUseReqDTO smsCodeSendReqDTO = new SmsCodeUseReqDTO();
            smsCodeSendReqDTO.setCode(createReqVO.getCode());
            smsCodeSendReqDTO.setMobile(orderCargoControlDO.getPhone());
            smsCodeSendReqDTO.setUsedIp(getClientIP());
            smsCodeSendReqDTO.setScene(SmsSceneEnum.DELIVERY_VERIFICATION_SMS.getScene());
            smsCodeApi.useSmsCode(smsCodeSendReqDTO);
            isPasswordPick = false;
        }

        if (StringUtils.isBlank(createReqVO.getCode()) && (isPasswordError ||
                isPasswordNull)) {
            // 当控货人手机号没有注册web用户，或者用户没有设置控货密码时不能进行控货密码放货
            if (isPasswordNull) {
                throw exception(CONTROLLER_USER_NOT_SET_CONTROL_PASSWORD);
            } else {
                // 参数：未加密密码，编码后的密码
                throw exception(USER_PASSWORD_FAILED);
            }
        }

        // 发送放货站内信
        this.smsInternal(orderDO, createReqVO, orderCargoControlDO, now);

        // 插入
        OrderCargoControlPickDO orderCargoControlPick =
                OrderCargoControlPickConvert.INSTANCE.convert(createReqVO);


        orderCargoControlPick.setControlNum(orderDO.getSumNum() - pickNum);
        orderCargoControlPick.setPickVolume(addPickVolume(orderCargoControlPick.getPickNum(), orderCargoControlPick.getControlNum(), orderDO.getSumNum(), orderDO.getSumVolume(), (orderDO.getSumVolume().subtract(pickVolume))));
        orderCargoControlPick.setPickWeight(addPickWeight(orderCargoControlPick.getPickNum(), orderCargoControlPick.getControlNum(), orderDO.getSumNum(), orderDO.getSumWeight(), (orderDO.getSumWeight().subtract(pickWeight))));
        orderCargoControlPick.setPickQuantity(addPickQuantity(orderCargoControlPick.getPickNum(), orderCargoControlPick.getControlNum(), orderDO.getSumNum(), orderDO.getSumQuantity(), (orderDO.getSumQuantity() - pickQuantity)));
        if (orderCargoControlPick.getPickQuantity() > (orderDO.getSumQuantity() - pickQuantity)) {
            orderCargoControlPick.setPickQuantity(orderDO.getSumQuantity() - pickQuantity);
        }
        if (orderCargoControlPick.getPickVolume().compareTo(orderDO.getSumVolume().subtract(pickVolume)) > 0) {
            orderCargoControlPick.setPickVolume(orderDO.getSumVolume().subtract(pickVolume));
        }
        if (orderCargoControlPick.getPickWeight().compareTo(orderDO.getSumWeight().subtract(pickWeight)) > 0) {
            orderCargoControlPick.setPickWeight(orderDO.getSumWeight().subtract(pickWeight));
        }
        orderCargoControlPick.setName(orderCargoControlDO.getName());
        orderCargoControlPick.setNameEn(orderCargoControlDO.getNameEn());
        orderCargoControlPick.setCompany(orderCargoControlDO.getCompany());
        orderCargoControlPick.setCompanyEn(orderCargoControlDO.getCompanyEn());
        orderCargoControlPick.setPhone(orderCargoControlDO.getPhone());
        orderCargoControlPick.setCountryCode(String.valueOf(orderCargoControlDO.getDialCode()));
        orderCargoControlPick.setEmail(orderCargoControlDO.getEmail());
        orderCargoControlPick.setOrderNo(orderCargoControlDO.getOrderNo());
        orderCargoControlPick.setTidanNo(orderDO.getTidanNo());
        orderCargoControlPick.setPickId(null); // TODO 提货信息id  是否同步插入提货信息
        orderCargoControlPick.setCreator(creator);
        orderCargoControlPick.setCreateTime(now);
        orderCargoControlPick.setOperator(operator);
        orderCargoControlPick.setUserType(userType);
        orderCargoControlPick.setStatus(1);
        orderCargoControlPickMapper.insert(orderCargoControlPick);

        // 修改订单控货状态
        String msg = "";
        if (Objects.equals(orderCargoControlPick.getControlNum(),
                orderCargoControlPick.getPickNum())) {
            // 已放完货
            orderDO.setCargoControlStatus(1);
            msg = String.format("订单放货%s箱, 放货方式：%s, 已放完货, 收货人姓名%s,电话+%s", orderCargoControlPick.getPickNum(), isPasswordPick ? "密码放货" : "验证码放货",
                    orderCargoControlPick.getConsigneeName() + "/" + (StringUtils.isNotBlank(orderCargoControlPick.getConsigneeNameEn()) ? orderCargoControlPick.getConsigneeNameEn() : "空"),
                    orderCargoControlPick.getConsigneeCountryCode() + orderCargoControlPick.getConsigneePhone());
        } else {
            // 部分控货中
            orderDO.setCargoControlStatus(2);
            msg = String.format("订单放货%s箱, 放货方式：%s, 部分控货中, 收货人姓名%s,电话+%s", orderCargoControlPick.getPickNum(), isPasswordPick ? "密码放货" : "验证码放货",
                    orderCargoControlPick.getConsigneeName() + "/" + (StringUtils.isNotBlank(orderCargoControlPick.getConsigneeNameEn()) ? orderCargoControlPick.getConsigneeNameEn() : "空"),
                    orderCargoControlPick.getConsigneeCountryCode() + orderCargoControlPick.getConsigneePhone());
        }
        if (Objects.isNull(orderDO.getReleaseNum())) orderDO.setReleaseNum(0);
        orderDO.setReleaseNum(orderDO.getReleaseNum() + orderCargoControlPick.getPickNum());
        if (Objects.nonNull(orderDO.getSumNum()) && orderDO.getSumNum() > 0) {
            orderDO.setReleaseRatio(new BigDecimal(orderDO.getReleaseNum()).divide(new BigDecimal(orderDO.getSumNum()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
        }
        orderService.updateById(orderDO);
        // 订单控货信息日志补充
        orderBusinessService.createOrderControlLog(orderCargoControlPick.getOrderId(), 4, "订单放货", msg, 0L);
        // 返回
        return orderCargoControlPick.getId();
    }

    private void smsInternal(OrderDO orderDO, OrderCargoControlPickCreateReqVO createReqVO, OrderCargoControlDO orderCargoControlDO, Date now) {
        Set<Long> userIds = new HashSet<>();
        // 获取控货人会员信息
        UserRespDTO userRespDTO = memberUserApi.getUserByMobile(orderCargoControlDO.getPhone());
        if (Objects.isNull(userRespDTO)) {
            log.info("放货站内信查询控货用户不是注册会员,无法发送站内信提醒！");
        } else {
            userIds.add(userRespDTO.getId());
        }
        // 获取收货人会员信息
        Long consigneeUserId = orderQueryService.getOrderConsigneeMemberInfo(orderDO.getOrderId());
        if (Objects.isNull(consigneeUserId)) {
            log.info("放货站内信查询收货用户不是注册会员,无法发送站内信提醒！");
        } else {
            userIds.add(consigneeUserId);
        }

        if (CollectionUtil.isNotEmpty(userIds)) {
            //发送站内信
            InternalMessageCreateDto dto = InternalMessageCreateDto.builder().toIdList(new ArrayList<>(userIds))
                    .fromId("")
                    .sendTime(new Date())
                    .title(I18nMessage.getMessage("app.message.pick.title"))
                    .content(MessageFormat.format(I18nMessage.getMessage("app.message.pick.content"),
                            orderDO.getOrderNo(), orderDO.getMarks(), DateUtil.format(now, "yyyy年MM月dd日"), createReqVO.getPickNum()))
                    .type(1).build();
            clientInternalMessageApi.createInternalMessage(dto);
        }
    }


    /**
     * @param orderCargoControlPick    调货参数
     * @param orgOrderCargoControlPick 被调货记录
     */
    private void seasoningCondimentsOrderCargoControlPick(OrderCargoControlPickDO orderCargoControlPick, OrderCargoControlPickDO orgOrderCargoControlPick, Long approvalId) {
        if (Objects.isNull(orderCargoControlPick)) {
            throw exception(ORDER_CARGO_CONTROL_PICK_NOT_EXISTS);
        }
        OrderDO orderDO = orderService.getById(orderCargoControlPick.getOrderId());
        if (Objects.isNull(orderDO)) {
            throw exception(ORDER_NOT_EXISTS);
        }
        if (orderDO.getCargoControlStatus() == 1) {
            throw exception(ORDER_CARGO_CONTROL_PICK_FINISH);
        }
        int pickNum = 0;
        List<OrderCargoControlPickDO> pickDOList = orderCargoControlPickMapper.selectList(new LambdaQueryWrapper<OrderCargoControlPickDO>()
                .eq(OrderCargoControlPickDO::getOrderId, orderCargoControlPick.getOrderId())
                .in(OrderCargoControlPickDO::getStatus, Arrays.asList(1, 2, 3, 4, 5, 6))
                .eq(OrderCargoControlPickDO::getDeleted, Boolean.FALSE));
        if (CollectionUtil.isNotEmpty(pickDOList)) {
            pickNum = pickDOList.stream().mapToInt(OrderCargoControlPickDO::getPickNum).sum();
        }
        if (orderDO.getSumNum() == 0) {
            throw exception(ORDER_CARGO_CONTROL_NOT_NUM);
        }
        if (pickNum >= orderDO.getSumNum()) {
            throw exception(ORDER_CARGO_CONTROL_PICK_FINISH);
        }
        OrderCargoControlDO orderCargoControlDO = orderCargoControlService.getOne(new LambdaQueryWrapper<OrderCargoControlDO>()
                .eq(OrderCargoControlDO::getOrderId, orderCargoControlPick.getOrderId())
                .eq(OrderCargoControlDO::getIsActual, Boolean.TRUE)
                .orderByDesc(OrderCargoControlDO::getId)
                .last("limit 1"));
        if (Objects.isNull(orderCargoControlDO)) {
            throw exception(ORDER_CARGO_CONTROL_NOT_EXISTS);
        }
        String creator = String.valueOf(SecurityFrameworkUtils.getLoginUserId());
        Date now = new Date();

        // 插入
        orderCargoControlPick.setControlNum(orderDO.getSumNum() - pickNum);
        orderCargoControlPick.setName(orderCargoControlDO.getName());
        orderCargoControlPick.setNameEn(orderCargoControlDO.getNameEn());
        orderCargoControlPick.setCompany(orderCargoControlDO.getCompany());
        orderCargoControlPick.setCompanyEn(orderCargoControlDO.getCompanyEn());
        orderCargoControlPick.setPhone(orderCargoControlDO.getPhone());
        orderCargoControlPick.setCountryCode(String.valueOf(orderCargoControlDO.getDialCode()));
        orderCargoControlPick.setEmail(orderCargoControlDO.getEmail());
        orderCargoControlPick.setOrderNo(orderCargoControlDO.getOrderNo());
        orderCargoControlPick.setTidanNo(orderDO.getTidanNo());
        orderCargoControlPick.setPickId(null); // TODO 提货信息id  是否同步插入提货信息
        orderCargoControlPick.setCreator(creator);
        orderCargoControlPick.setCreateTime(now);
        orderCargoControlPick.setStatus(1);
        orderCargoControlPick.setOperator(orgOrderCargoControlPick.getOperator());
        orderCargoControlPick.setUserType(orgOrderCargoControlPick.getUserType());
        orderCargoControlPickMapper.insert(orderCargoControlPick);

        // TODO 修改订单控货状态
        String msg = "";
        Integer releaseNum = orderDO.getReleaseNum() + orderCargoControlPick.getPickNum();
        if (Objects.equals(orderCargoControlPick.getControlNum(), orderCargoControlPick.getPickNum())) {
            // 已放完货
            orderService.update(new LambdaUpdateWrapper<OrderDO>()
                    .set(OrderDO::getCargoControlStatus, 1)
                    .set(OrderDO::getReleaseNum, releaseNum)
                    .set(OrderDO::getReleaseRatio, new BigDecimal(releaseNum).divide(new BigDecimal(orderDO.getSumNum()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")))
                    .eq(OrderDO::getOrderId, orderDO.getOrderId()));
            msg = String.format("订单放货%s箱, 已放完货, 收货人姓名%s,电话+%s", orderCargoControlPick.getPickNum(),
                    orderCargoControlPick.getConsigneeName() + "/" + (StringUtils.isNotBlank(orderCargoControlPick.getConsigneeNameEn()) ? orderCargoControlPick.getConsigneeNameEn() : "空"),
                    orderCargoControlPick.getConsigneeCountryCode() + orderCargoControlPick.getConsigneePhone());
        } else {
            // 部分控货中
            orderService.update(new LambdaUpdateWrapper<OrderDO>()
                    .set(OrderDO::getCargoControlStatus, 2)
                    .set(OrderDO::getReleaseNum, releaseNum)
                    .set(OrderDO::getReleaseRatio, new BigDecimal(releaseNum).divide(new BigDecimal(orderDO.getSumNum()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")))
                    .eq(OrderDO::getOrderId, orderDO.getOrderId()));
            msg = String.format("订单放货%s箱, 部分控货中, 收货人姓名%s,电话+%s", orderCargoControlPick.getPickNum(),
                    orderCargoControlPick.getConsigneeName() + "/" + (StringUtils.isNotBlank(orderCargoControlPick.getConsigneeNameEn()) ? orderCargoControlPick.getConsigneeNameEn() : "空"),
                    orderCargoControlPick.getConsigneeCountryCode() + orderCargoControlPick.getConsigneePhone());
        }
        // 订单控货信息日志补充
        orderBusinessService.createOrderControlLog(orderCargoControlPick.getOrderId(), 20, "订单被调货审批通过", msg, approvalId);
    }

    @Override
    public void updateOrderCargoControlPick(OrderCargoControlPickUpdateReqVO updateReqVO) {
        // 更新
        OrderCargoControlPickDO updateObj = OrderCargoControlPickConvert.INSTANCE.convert(updateReqVO);
        orderCargoControlPickMapper.updateById(updateObj);
    }

    @Override
    public void deleteOrderCargoControlPick(Long id) {
        // 删除
        orderCargoControlPickMapper.deleteById(id);
    }


    @Override
    public OrderCargoControlPickDO getOrderCargoControlPick(Long id) {
        return orderCargoControlPickMapper.selectById(id);
    }

    @Override
    public List<OrderCargoControlPickDO> getOrderCargoControlPickList(Collection<Long> ids) {
        return orderCargoControlPickMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<OrderCargoControlPickDO> getOrderCargoControlPickPage(OrderCargoControlPickQueryVO query, PageVO page) {
        return orderCargoControlPickMapper.selectPage(page, query);
    }

    @Override
    public List<OrderCargoControlPickDO> getOrderCargoControlPickList(OrderCargoControlPickQueryVO query) {
        return orderCargoControlPickMapper.selectList(query);
    }

    @Override
    public OrderCargoControlReleaseInfoDto getOrderCargoControlReleaseInfo(Long orderId) {
        OrderCargoControlReleaseInfoDto releaseInfoDto = orderCargoControlPickMapper.getOrderCargoControlReleaseInfo(orderId);
        if (Objects.nonNull(releaseInfoDto) && CollectionUtil.isNotEmpty(releaseInfoDto.getCargoControlPickBackVOList())) {
            // 因为放货记录创建时可能没有提单编号，所以在这里进行数据填充
            releaseInfoDto.setCargoControlPickBackVOList(releaseInfoDto.getCargoControlPickBackVOList().stream().peek(vo -> vo.setTidanNo(releaseInfoDto.getTidanNo())).collect(Collectors.toList()));
        }
        List<OrderApprovalDO> orderApprovalDOList = orderApprovalMapper.selectList(new LambdaQueryWrapper<OrderApprovalDO>()
                .eq(OrderApprovalDO::getOrderId, orderId)
                .in(OrderApprovalDO::getType, 7, 8, 9, 10)
                .orderByDesc(OrderApprovalDO::getOrderApprovalId));
        if (CollectionUtil.isNotEmpty(orderApprovalDOList)) {
            releaseInfoDto.setOrderApprovalBackVOList(OrderApprovalConvert.INSTANCE.convertList(orderApprovalDOList));
        } else {
            releaseInfoDto.setOrderApprovalBackVOList(Collections.emptyList());
        }
        return releaseInfoDto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void orderCargoControlPickApply(OrderCargoControlPickApplyVO orderCargoControlPickApplyVO) {

        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        Integer userType = loginUser != null ? loginUser.getUserType() : null;
        Long userId = loginUser != null ? loginUser.getId() : null;
        String creator = String.valueOf(userId);
        if (Objects.equals(userType, UserTypeEnum.MEMBER.getValue())) {
            DictDataRespDTO dto = dictDataApi.parseDictDataFromCache(CUSTOMER_USER_TO_ADMIN, CUSTOMER_USER_APPROVAL_ID);
            userId = Long.valueOf(dto.getValue());
        }
        OrderCargoControlDO orderCargoControlDO = orderCargoControlService.getOne(new LambdaQueryWrapper<OrderCargoControlDO>()
                .eq(OrderCargoControlDO::getOrderId, orderCargoControlPickApplyVO.getOrderId())
                .eq(OrderCargoControlDO::getIsActual, Boolean.TRUE)
                .orderByDesc(OrderCargoControlDO::getId)
                .last("limit 1"));
        if (Objects.isNull(orderCargoControlDO)) {
            throw exception(ORDER_CARGO_CONTROL_NOT_EXISTS);
        }
        Date now = new Date();
        SmsCodeUseReqDTO smsCodeSendReqDTO = new SmsCodeUseReqDTO();
        smsCodeSendReqDTO.setCode(orderCargoControlPickApplyVO.getCode());
        smsCodeSendReqDTO.setMobile(orderCargoControlDO.getPhone());
        smsCodeSendReqDTO.setUsedIp(getClientIP());
        smsCodeSendReqDTO.setScene(SmsSceneEnum.DELIVERY_VERIFICATION_SMS.getScene());
        smsCodeApi.useSmsCode(smsCodeSendReqDTO);

        OrderDO orderDO = orderService.getById(orderCargoControlPickApplyVO.getOrderId());
        orderCargoControlPickApplyVO.setOrderNo(orderDO.getOrderNo());
        OrderApprovalDO orderApprovalDO = new OrderApprovalDO();
        orderApprovalDO.setFollowUpSalesmanId(String.valueOf(orderDO.getSalesmanId()));//跟进业务员为订单的跟进业务员
        orderApprovalDO.setDetails(JSONObject.toJSONString(orderCargoControlPickApplyVO));
        orderApprovalDO.setCreator(creator);
        orderApprovalDO.setUpdater(creator);
        orderApprovalDO.setCreateTime(now);
        orderApprovalDO.setUpdateTime(now);
        OrderCargoControlPickDO orderCargoControlPickDO = null;
        if (Objects.nonNull(orderCargoControlPickApplyVO.getCargoControlPickId())) {
            orderCargoControlPickDO = orderCargoControlPickMapper.selectById(orderCargoControlPickApplyVO.getCargoControlPickId());
        }
        List<OrderControlLogParam> controlLogParams = new ArrayList<>();
        if (orderCargoControlPickApplyVO.getApplyType() == 7) {
            if (Objects.isNull(orderCargoControlPickDO)) {
                throw exception(ORDER_CARGO_CONTROL_PICK_NOT_EXISTS);
            }
            if (orderCargoControlPickDO.getStatus() != 1) {
                throw exception(ORDER_CARGO_CONTROL_PICK_STATUS_ERROR);
            }
            if (orderCargoControlPickApplyVO.getCurrentPickNum() > orderCargoControlPickDO.getControlNum()) {
                throw exception(ORDER_CARGO_CONTROL_NUM_GO_BEYOND);
            }
            //不能大于总箱数
            if (orderCargoControlPickApplyVO.getCurrentPickNum() > orderDO.getSumNum()) {
                throw exception(ORDER_CARGO_CONTROL_NUM_GO_BEYOND);
            }
            orderCargoControlPickApplyVO.setPickNum(orderCargoControlPickDO.getPickNum());
            orderApprovalDO.setOrderId(orderCargoControlPickApplyVO.getOrderId());
            orderApprovalDO.setType(7);
            orderApprovalDO.setDetails(JSONObject.toJSONString(orderCargoControlPickApplyVO));
            orderApprovalMapper.insert(orderApprovalDO);
            String formId = bpmCreateServiceFactory.createBmp(userId, orderApprovalDO.getOrderApprovalId(), WorkFlowEmus.ORDER_RELEASE_GOODS.getKey(), orderDO.getOrderNo(),
                    StringUtils.isNotBlank(orderCargoControlPickApplyVO.getCcIds()) ? orderCargoControlPickApplyVO.getCcIds().split(StrUtil.COMMA) : null);
            orderApprovalDO.setFormId(formId);

            orderCargoControlPickDO.setStatus(2);
            orderCargoControlPickMapper.updateById(orderCargoControlPickDO);
            String msg = String.format("订单原放货%s箱, 订单当前放货%s箱", orderCargoControlPickDO.getPickNum(),
                    orderCargoControlPickApplyVO.getCurrentPickNum());
            OrderControlLogParam param = new OrderControlLogParam();
            param.setTypeKey(7);
            param.setType("放货修改申请");
            param.setMsg(msg);
            param.setOrderId(orderCargoControlPickApplyVO.getOrderId());
            param.setApprovalId(orderApprovalDO.getOrderApprovalId());
            controlLogParams.add(param);
        } else if (orderCargoControlPickApplyVO.getApplyType() == 8) {
            if (Objects.isNull(orderCargoControlPickApplyVO.getRecurrentNuclearType())) {
                throw exception(RECURRENT_NUCLEAR_TYPE_NOT_EXISTS);
            }
            List<OrderCargoControlPickDO> orderCargoControlPickDOList = this.list(new LambdaQueryWrapper<OrderCargoControlPickDO>()
                    .eq(OrderCargoControlPickDO::getOrderId, orderCargoControlPickApplyVO.getOrderId())
                    .eq(Objects.nonNull(orderCargoControlPickApplyVO.getCargoControlPickId()), OrderCargoControlPickDO::getId, orderCargoControlPickApplyVO.getCargoControlPickId())
                    .eq(OrderCargoControlPickDO::getStatus, 3)
                    .eq(OrderCargoControlPickDO::getDeleted, Boolean.FALSE)
            );
            if (CollectionUtil.isEmpty(orderCargoControlPickDOList)) {
                throw exception(ORDER_CARGO_CONTROL_PICK_NOT_EXISTS);
            }

            // 反复核提交箱数
            int antiCheckingPickNum = orderCargoControlPickDOList.stream().filter(pick -> pick.getStatus() == 3 || pick.getStatus() == 4).mapToInt(OrderCargoControlPickDO::getPickNum).sum();
            // 校验放货数量与提货数量
            checkAntiCheckingOrderPickNum(antiCheckingPickNum, orderDO.getOrderId(), orderDO.getOrderNo());
            orderApprovalDO.setOrderId(orderCargoControlPickApplyVO.getOrderId());
            orderApprovalDO.setType(8);
            orderApprovalDO.setFollowUpSalesmanId(String.valueOf(orderDO.getSalesmanId()));//跟进业务员为订单的跟进业务员
            orderApprovalDO.setDetails(JSONObject.toJSONString(orderCargoControlPickApplyVO));
            orderApprovalMapper.insert(orderApprovalDO);
            String formId = bpmCreateServiceFactory.createBmp(userId, orderApprovalDO.getOrderApprovalId(), WorkFlowEmus.ORDER_RELEASE_GOODS_RECURRENT_NUCLEUS.getKey(), orderDO.getOrderNo(),
                    StringUtils.isNotBlank(orderCargoControlPickApplyVO.getCcIds()) ? orderCargoControlPickApplyVO.getCcIds().split(StrUtil.COMMA) : null);
            orderApprovalDO.setFormId(formId);
            String msg = "放货反复核申请，对放货:%s,进行反复核";
            OrderControlLogParam param = new OrderControlLogParam();
            param.setTypeKey(8);
            param.setType("放货反复核申请");
            StringBuilder sb = new StringBuilder();
            for (OrderCargoControlPickDO cargoControlPickDO : orderCargoControlPickDOList) {
                String content = "收发货人%s放货%s箱";
                content = String.format(content, cargoControlPickDO.getConsigneeName() + "/" + (StringUtils.isNotBlank(cargoControlPickDO.getConsigneeNameEn()) ? cargoControlPickDO.getConsigneeNameEn() : "空"),
                        cargoControlPickDO.getPickNum());
                if (StringUtils.isNotBlank(sb)) {
                    sb.append("和").append(content);
                } else {
                    sb.append(content);
                }
                cargoControlPickDO.setStatus(4);
            }
            param.setMsg(String.format(msg, sb));
            param.setOrderId(orderDO.getOrderId());
            param.setApprovalId(orderApprovalDO.getOrderApprovalId());
            controlLogParams.add(param);
            this.updateBatchById(orderCargoControlPickDOList);
        } else if (orderCargoControlPickApplyVO.getApplyType() == 9) {
            if (Objects.isNull(orderCargoControlPickDO)) {
                throw exception(ORDER_CARGO_CONTROL_PICK_NOT_EXISTS);
            }
            if (orderCargoControlPickDO.getStatus() != 3) {
                throw exception(ORDER_CARGO_CONTROL_PICK_STATUS_ERROR);
            }
            if (CollectionUtil.isEmpty(orderCargoControlPickApplyVO.getOrderBackPageVOList())) {
                throw exception(TRANSFER_GOODS_ORDER_NOT_NULL);
            }
            int seasoningCondimentsCount = orderCargoControlPickApplyVO.getOrderBackPageVOList().stream().mapToInt(OrderBackPageVO::getReleaseNum).sum();
            int orgPickNum = orderCargoControlPickDO.getPickNum();
            int pickNum = orgPickNum - seasoningCondimentsCount;
            // 反复核提交箱数
            int antiCheckingPickNum = pickNum <= 0 ? orgPickNum : seasoningCondimentsCount;
            // 校验放货数量与提货数量
            checkAntiCheckingOrderPickNum(antiCheckingPickNum, orderDO.getOrderId(), orderDO.getOrderNo());
            String reasonZh = "%s调为%s备注%s";
            String reasonEn = "%s TO %s remarks %s";
            StringBuilder sbZh = new StringBuilder();
            StringBuilder sbEn = new StringBuilder();

            for (OrderBackPageVO orderBackPageVO : orderCargoControlPickApplyVO.getOrderBackPageVOList()) {
                if (orderBackPageVO.getReleaseNum() > orderBackPageVO.getControlNum()) {
                    throw exception(ORDER_CONTROL_NUM_LT_RELEASE_NUM, orderBackPageVO.getOrderNo());
                }
                OrderControlLogParam controlLogParam = new OrderControlLogParam();
                controlLogParam.setTypeKey(9);
                controlLogParam.setType("订单被调货申请");
                controlLogParam.setMsg(String.format("订单放货%s箱", orderBackPageVO.getReleaseNum()));
                controlLogParam.setOrderId(orderBackPageVO.getOrderId());
                controlLogParams.add(controlLogParam);
                sbZh.append(orderBackPageVO.getOrderNo()).append("进行放货，放货箱数为：").append(orderBackPageVO.getReleaseNum()).append(", ");
                sbEn.append(orderBackPageVO.getOrderNo()).append(" Release , Number of containers:").append(orderBackPageVO.getReleaseNum()).append(", ");
            }
            reasonZh = String.format(reasonZh, orderDO.getOrderNo(), sbZh, Objects.isNull(orderCargoControlPickApplyVO.getRemarks()) ? "" : orderCargoControlPickApplyVO.getRemarks());
            reasonEn = String.format(reasonEn, orderDO.getOrderNo(), sbEn, Objects.isNull(orderCargoControlPickApplyVO.getRemarks()) ? "" : orderCargoControlPickApplyVO.getRemarks());
            OrderControlLogParam controlLogParam = new OrderControlLogParam();
            controlLogParam.setTypeKey(10);
            controlLogParam.setType("订单调货申请");
            controlLogParam.setMsg(reasonZh);
            controlLogParam.setOrderId(orderCargoControlPickApplyVO.getOrderId());
            controlLogParams.add(controlLogParam);
            orderCargoControlPickApplyVO.setReasonZh(reasonZh);
            orderCargoControlPickApplyVO.setReasonEn(reasonEn);
            orderCargoControlPickApplyVO.setPickNum(orderCargoControlPickDO.getPickNum());
            orderCargoControlPickApplyVO.setPickVolume(orderCargoControlPickDO.getPickVolume());
            orderCargoControlPickApplyVO.setPickWeight(orderCargoControlPickDO.getPickWeight());
            orderCargoControlPickApplyVO.setPickQuantity(orderCargoControlPickDO.getPickQuantity());
            orderApprovalDO.setOrderId(orderCargoControlPickApplyVO.getOrderId());
            orderApprovalDO.setType(9);
            orderApprovalDO.setDetails(JSONObject.toJSONString(orderCargoControlPickApplyVO));
            orderApprovalMapper.insert(orderApprovalDO);
            String formId = bpmCreateServiceFactory.createBmp(userId, orderApprovalDO.getOrderApprovalId(), WorkFlowEmus.ORDER_TRANSFER_GOODS.getKey(), orderDO.getOrderNo(),
                    StringUtils.isNotBlank(orderCargoControlPickApplyVO.getCcIds()) ? orderCargoControlPickApplyVO.getCcIds().split(StrUtil.COMMA) : null);
            orderApprovalDO.setFormId(formId);
            controlLogParams.forEach(param -> param.setApprovalId(orderApprovalDO.getOrderApprovalId()));
            orderCargoControlPickDO.setStatus(5);
            orderCargoControlPickDO.setRemarks("调货");
            orderCargoControlPickMapper.updateById(orderCargoControlPickDO);
        } else if (orderCargoControlPickApplyVO.getApplyType() == 10) {
            if (Objects.isNull(orderCargoControlPickDO)) {
                throw exception(ORDER_CARGO_CONTROL_PICK_NOT_EXISTS);
            }
            if (orderCargoControlPickDO.getStatus() != 1) {
                throw exception(ORDER_CARGO_CONTROL_PICK_STATUS_ERROR);
            }
            if (Objects.isNull(orderCargoControlPickApplyVO.getCancelPickType())) {
                throw exception(CANCEL_PICK_TYPE_NOT_EXISTS);
            }
            orderApprovalDO.setOrderId(orderCargoControlPickApplyVO.getOrderId());
            orderApprovalDO.setType(10);
            orderApprovalDO.setDetails(JSONObject.toJSONString(orderCargoControlPickApplyVO));
            orderApprovalMapper.insert(orderApprovalDO);
            String formId = bpmCreateServiceFactory.createBmp(userId, orderApprovalDO.getOrderApprovalId(), WorkFlowEmus.ORDER_CANCEL_GOODS.getKey(), orderDO.getOrderNo(),
                    StringUtils.isNotBlank(orderCargoControlPickApplyVO.getCcIds()) ? orderCargoControlPickApplyVO.getCcIds().split(StrUtil.COMMA) : null);
            orderApprovalDO.setFormId(formId);

            orderCargoControlPickDO.setStatus(6);
            orderCargoControlPickMapper.updateById(orderCargoControlPickDO);
            OrderControlLogParam controlLogParam = new OrderControlLogParam();
            controlLogParam.setTypeKey(11);
            controlLogParam.setType("订单取消放货申请");
            String msg = String.format("订单放货%s箱, 取消放货申请", orderCargoControlPickDO.getPickNum());
            controlLogParam.setMsg(msg);
            controlLogParam.setOrderId(orderCargoControlPickApplyVO.getOrderId());
            controlLogParam.setApprovalId(orderApprovalDO.getOrderApprovalId());
            controlLogParams.add(controlLogParam);
        }
        orderApprovalMapper.updateById(orderApprovalDO);

        // TODO 订单控货信息日志补充
        if (CollectionUtil.isNotEmpty(controlLogParams)) {
            orderBusinessService.createOrderControlLogs(controlLogParams);
        }
    }

    @Override
    public OrderCargoControlPickApplyVO approvalOrderCargoControlPick(Long approveId) {
        OrderApprovalDO orderApprovalDO = orderApprovalMapper.selectById(approveId);
        if (Objects.isNull(orderApprovalDO) || (orderApprovalDO.getType() != 7 && orderApprovalDO.getType() != 8 && orderApprovalDO.getType() != 9 && orderApprovalDO.getType() != 10)) {
            throw exception(ORDER_APPROVAL_INFO_NOT_FIND);
        }
        return JSONObject.parseObject(orderApprovalDO.getDetails(), OrderCargoControlPickApplyVO.class);
    }

    @Override
    public OrderCargoControlPickApplyVO approvalUpdateCargoControlPickByCargoControlPickId(Long cargoControlPickId) {
        OrderCargoControlPickDO orderCargoControlPickDO = orderCargoControlPickMapper.selectById(cargoControlPickId);
        if (Objects.isNull(orderCargoControlPickDO)) {
            throw exception(ORDER_CARGO_CONTROL_PICK_NOT_EXISTS);
        }
        OrderApprovalDO orderApprovalDO = orderApprovalMapper.newOrderCargoControlPickInfo(orderCargoControlPickDO.getOrderId(), orderCargoControlPickDO.getId(), 7);
        if (Objects.isNull(orderApprovalDO)) {
            OrderCargoControlReleaseInfoDto releaseInfoDto = orderCargoControlService.getOrderCargoControlReleaseInfo(orderCargoControlPickDO.getOrderId());
            OrderCargoControlPickApplyVO orderCargoControlPickApplyVO = new OrderCargoControlPickApplyVO();
            BeanUtils.copyProperties(releaseInfoDto, orderCargoControlPickApplyVO);
            orderCargoControlPickApplyVO.setApplyStatus(1);
            orderCargoControlPickApplyVO.setCargoControlPickId(orderCargoControlPickDO.getId());
            orderCargoControlPickApplyVO.setPickNum(orderCargoControlPickDO.getPickNum());
            return orderCargoControlPickApplyVO;
        } else {
            return JSONObject.parseObject(orderApprovalDO.getDetails(), OrderCargoControlPickApplyVO.class);
        }
    }

    @Override
    public OrderCargoControlPickApplyVO approvalCancelCargoControlPickByCargoControlPickId(Long cargoControlPickId) {
        OrderCargoControlPickDO orderCargoControlPickDO = orderCargoControlPickMapper.selectById(cargoControlPickId);
        if (Objects.isNull(orderCargoControlPickDO)) {
            throw exception(ORDER_CARGO_CONTROL_PICK_NOT_EXISTS);
        }
        OrderApprovalDO orderApprovalDO = orderApprovalMapper.newOrderCargoControlPickInfo(orderCargoControlPickDO.getOrderId(), orderCargoControlPickDO.getId(), 10);
        if (Objects.isNull(orderApprovalDO)) {
            OrderCargoControlReleaseInfoDto releaseInfoDto = orderCargoControlService.getOrderCargoControlReleaseInfo(orderCargoControlPickDO.getOrderId());
            OrderCargoControlPickApplyVO orderCargoControlPickApplyVO = new OrderCargoControlPickApplyVO();
            BeanUtils.copyProperties(releaseInfoDto, orderCargoControlPickApplyVO);
            orderCargoControlPickApplyVO.setApplyStatus(1);
            orderCargoControlPickApplyVO.setCargoControlPickId(orderCargoControlPickDO.getId());
            orderCargoControlPickApplyVO.setPickNum(orderCargoControlPickDO.getPickNum());
            return orderCargoControlPickApplyVO;
        } else {
            return JSONObject.parseObject(orderApprovalDO.getDetails(), OrderCargoControlPickApplyVO.class);
        }
    }

    @Override
    public OrderCargoControlPickApplyVO approvalAntiCheckingOrderCargoControlPickByOrderId(Long orderId) {
        OrderApprovalDO orderApprovalDO = orderApprovalMapper.newOrderCargoControlPickInfo(orderId, null, 8);
        if (Objects.isNull(orderApprovalDO)) {
            OrderCargoControlReleaseInfoDto releaseInfoDto = orderCargoControlService.getOrderCargoControlReleaseInfo(orderId);
            OrderCargoControlPickApplyVO orderCargoControlPickApplyVO = new OrderCargoControlPickApplyVO();
            BeanUtils.copyProperties(releaseInfoDto, orderCargoControlPickApplyVO);
            orderCargoControlPickApplyVO.setApplyStatus(1);
            return orderCargoControlPickApplyVO;
        } else {
            return JSONObject.parseObject(orderApprovalDO.getDetails(), OrderCargoControlPickApplyVO.class);
        }
    }

    @Override
    public OrderCargoControlPickApplyVO seasoningCondimentsOrderCargoControlPickByOrderId(Long cargoControlPickId) {
        OrderCargoControlPickDO orderCargoControlPickDO = orderCargoControlPickMapper.selectById(cargoControlPickId);
        if (Objects.isNull(orderCargoControlPickDO)) {
            throw exception(ORDER_CARGO_CONTROL_PICK_NOT_EXISTS);
        }
        OrderApprovalDO orderApprovalDO = orderApprovalMapper.newOrderCargoControlPickInfo(orderCargoControlPickDO.getOrderId(), orderCargoControlPickDO.getId(), 9);
        if (Objects.isNull(orderApprovalDO)) {
//            if (orderCargoControlPickDO.getStatus() != 3) {
//                throw exception(ORDER_CARGO_CONTROL_PICK_STATUS_ERROR);
//            }
            OrderCargoControlReleaseInfoDto releaseInfoDto = orderCargoControlService.getOrderCargoControlReleaseInfo(orderCargoControlPickDO.getOrderId());
            OrderCargoControlPickApplyVO orderCargoControlPickApplyVO = new OrderCargoControlPickApplyVO();
            BeanUtils.copyProperties(releaseInfoDto, orderCargoControlPickApplyVO);
            orderCargoControlPickApplyVO.setApplyStatus(1);
            orderCargoControlPickApplyVO.setCargoControlPickId(orderCargoControlPickDO.getId());
            orderCargoControlPickApplyVO.setPickNum(orderCargoControlPickDO.getPickNum());
            return orderCargoControlPickApplyVO;
        } else {
            return JSONObject.parseObject(orderApprovalDO.getDetails(), OrderCargoControlPickApplyVO.class);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void approvalOrderCargoControlPick(String approveId, Integer result) {
        OrderApprovalDO orderApprovalDO = orderApprovalMapper.selectById(approveId);
        if (Objects.isNull(orderApprovalDO)) {
            throw exception(ORDER_APPROVAL_INFO_NOT_FIND);
        }
        orderApprovalDO.setStatus(result);
        if (result == 1) {
            // 进行中的审批直接返回
            return;
        }
        OrderCargoControlPickApplyVO orderCargoControlPickApplyVO = JSONObject.parseObject(orderApprovalDO.getDetails(), OrderCargoControlPickApplyVO.class);
        orderCargoControlPickApplyVO.setApplyStatus(result);
        // 查询最后审核的详细信息
        TaskResp taskResp = bpmCreateServiceFactory.getLastTaskByProcessInstanceId(orderApprovalDO.getFormId());
        orderApprovalDO.setFinishBy(String.valueOf(taskResp.getAssigneeUser().getId()));
        orderApprovalDO.setFinishTime(new Date());
        orderApprovalDO.setProcessingResults(taskResp.getComment());
        orderApprovalDO.setDetails(JSONObject.toJSONString(orderCargoControlPickApplyVO));
        OrderCargoControlPickDO orderCargoControlPickDO = new OrderCargoControlPickDO();
        List<OrderCargoControlPickDO> orderCargoControlPickDOList = new ArrayList<>();
        List<OrderControlLogParam> controlLogParams = new ArrayList<>();
        if (orderApprovalDO.getType() == 7) {
            orderCargoControlPickDO = orderCargoControlPickMapper.selectById(orderCargoControlPickApplyVO.getCargoControlPickId());
            if (Objects.isNull(orderCargoControlPickDO)) {
                return;
            }
        } else if (orderApprovalDO.getType() == 8) {
            orderCargoControlPickDOList = this.list(new LambdaQueryWrapper<OrderCargoControlPickDO>()
                    .eq(OrderCargoControlPickDO::getOrderId, orderApprovalDO.getOrderId())
                    .eq(Objects.nonNull(orderCargoControlPickApplyVO.getCargoControlPickId()), OrderCargoControlPickDO::getId, orderCargoControlPickApplyVO.getCargoControlPickId())
                    .eq(OrderCargoControlPickDO::getStatus, 4)
                    .eq(OrderCargoControlPickDO::getDeleted, Boolean.FALSE)
            );
            if (CollectionUtil.isEmpty(orderCargoControlPickDOList)) {
                return;
            }
        } else if (orderApprovalDO.getType() == 9) {
            orderCargoControlPickDO = orderCargoControlPickMapper.selectById(orderCargoControlPickApplyVO.getCargoControlPickId());
            if (Objects.isNull(orderCargoControlPickDO)) {
                return;
            }
        } else if (orderApprovalDO.getType() == 10) {
            orderCargoControlPickDO = orderCargoControlPickMapper.selectById(orderCargoControlPickApplyVO.getCargoControlPickId());
            if (Objects.isNull(orderCargoControlPickDO)) {
                return;
            }
        }
        orderCargoControlPickDO.setUpdateTime(new Date());
        if (result == 3 || result == 4) {
            // 未通过的审批到此结束，不再去处理订单价格
            // 审批通过
            if (orderApprovalDO.getType() == 7) {
                orderCargoControlPickDO.setStatus(1);
                orderCargoControlPickMapper.updateById(orderCargoControlPickDO);
                String msg = String.format("订单原放货%s箱, 订单当前放货%s箱", orderCargoControlPickApplyVO.getPickNum(),
                        orderCargoControlPickApplyVO.getCurrentPickNum());
                OrderControlLogParam param = new OrderControlLogParam();
                param.setTypeKey(12);
                param.setType(result == 3 ? "放货修改审批拒绝" : "放货修改审批取消");
                param.setMsg(msg);
                param.setOrderId(orderCargoControlPickApplyVO.getOrderId());
                param.setApprovalId(orderApprovalDO.getOrderApprovalId());
                controlLogParams.add(param);
            } else if (orderApprovalDO.getType() == 8) {
                this.batchAntiCheckingOrderCargoControlPick(orderCargoControlPickDOList, orderApprovalDO.getOrderId(), 2);
                String msg = "放货反复核申请，对放货:%s,进行反复核";
                OrderControlLogParam param = new OrderControlLogParam();
                param.setTypeKey(13);
                param.setType(result == 3 ? "放货反复核拒绝" : "放货反复核取消");
                StringBuilder sb = new StringBuilder();
                for (OrderCargoControlPickDO cargoControlPickDO : orderCargoControlPickDOList) {
                    String content = "收发货人%s放货%s箱";
                    content = String.format(content, cargoControlPickDO.getConsigneeName() + "/" + (StringUtils.isNotBlank(cargoControlPickDO.getConsigneeNameEn()) ? cargoControlPickDO.getConsigneeNameEn() : "空"),
                            cargoControlPickDO.getPickNum());
                    if (StringUtils.isNotBlank(sb)) {
                        sb.append("和").append(content);
                    } else {
                        sb.append(content);
                    }
                }
                param.setMsg(String.format(msg, sb));
                param.setOrderId(orderCargoControlPickApplyVO.getOrderId());
                param.setApprovalId(orderApprovalDO.getOrderApprovalId());
                controlLogParams.add(param);
            } else if (orderApprovalDO.getType() == 9) {
                orderCargoControlPickDO.setStatus(3);
                orderCargoControlPickMapper.updateById(orderCargoControlPickDO);
                for (OrderBackPageVO orderBackPageVO : orderCargoControlPickApplyVO.getOrderBackPageVOList()) {
                    OrderControlLogParam controlLogParam = new OrderControlLogParam();
                    controlLogParam.setTypeKey(14);
                    controlLogParam.setType(result == 3 ? "订单被调货审批拒绝" : "订单被调货审批取消");
                    controlLogParam.setMsg(String.format("订单放货%s箱", orderBackPageVO.getReleaseNum()));
                    controlLogParam.setOrderId(orderBackPageVO.getOrderId());
                    controlLogParam.setApprovalId(orderApprovalDO.getOrderApprovalId());
                    controlLogParams.add(controlLogParam);
                }
                OrderControlLogParam controlLogParam = new OrderControlLogParam();
                controlLogParam.setTypeKey(15);
                controlLogParam.setType(result == 3 ? "订单调货审批拒绝" : "订单调货审批取消");
                controlLogParam.setMsg(orderCargoControlPickApplyVO.getReasonZh());
                controlLogParam.setOrderId(orderCargoControlPickApplyVO.getOrderId());
                controlLogParam.setApprovalId(orderApprovalDO.getOrderApprovalId());
                controlLogParams.add(controlLogParam);
            } else if (orderApprovalDO.getType() == 10) {
                orderCargoControlPickDO.setStatus(1);
                orderCargoControlPickMapper.updateById(orderCargoControlPickDO);
                OrderControlLogParam controlLogParam = new OrderControlLogParam();
                controlLogParam.setTypeKey(16);
                controlLogParam.setType(result == 3 ? "订单取消放货审批拒绝" : "订单取消放货审批取消");
                controlLogParam.setMsg(String.format("订单放货%s箱, %s", orderCargoControlPickDO.getPickNum(), controlLogParam.getType()));
                controlLogParam.setOrderId(orderCargoControlPickApplyVO.getOrderId());
                controlLogParam.setApprovalId(orderApprovalDO.getOrderApprovalId());
                controlLogParams.add(controlLogParam);
            }
        }
        OrderDO orderDO = orderService.getById(orderApprovalDO.getOrderId());
        if (result == 2) {
            // 审批通过
            if (orderApprovalDO.getType() == 7) {
                orderCargoControlPickDO.setStatus(1);
                int pickNum = 0;
                int pickQuantity = 0;
                BigDecimal pickVolume = BigDecimal.ZERO;
                BigDecimal pickWeight = BigDecimal.ZERO;
                // 获取当前订单放货记录除外的其他放货记录
                List<OrderCargoControlPickDO> pickDOList = orderCargoControlPickMapper.selectList(new LambdaQueryWrapper<OrderCargoControlPickDO>()
                        .eq(OrderCargoControlPickDO::getOrderId, orderCargoControlPickApplyVO.getOrderId())
                        .notIn(OrderCargoControlPickDO::getId, orderCargoControlPickDO.getId())
                        .in(OrderCargoControlPickDO::getStatus, Arrays.asList(1, 2, 3, 4, 5, 6))
                        .eq(OrderCargoControlPickDO::getDeleted, Boolean.FALSE));
                if (CollectionUtil.isNotEmpty(pickDOList)) {
                    pickNum = pickDOList.stream().mapToInt(OrderCargoControlPickDO::getPickNum).sum();
                    pickQuantity = pickDOList.stream().mapToInt(OrderCargoControlPickDO::getPickQuantity).sum();
                    pickVolume = pickDOList.stream().map(OrderCargoControlPickDO::getPickVolume).reduce(BigDecimal.ZERO, BigDecimal::add);
                    pickWeight = pickDOList.stream().map(OrderCargoControlPickDO::getPickWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
                }
                if (orderDO.getSumNum() == 0) {
                    throw exception(ORDER_CARGO_CONTROL_NOT_NUM);
                }
                if (pickNum >= orderDO.getSumNum()) {
                    throw exception(ORDER_CARGO_CONTROL_PICK_FINISH);
                }
                //不能大于可放箱数（总箱数-已放箱数）
                if (orderCargoControlPickApplyVO.getCurrentPickNum() > (orderDO.getSumNum() - pickNum)) {
                    throw exception(ORDER_CARGO_CONTROL_NUM_OVER);
                }
                orderCargoControlPickDO.setPickNum(orderCargoControlPickApplyVO.getCurrentPickNum());
                orderCargoControlPickDO.setControlNum(orderDO.getSumNum() - pickNum);
                orderCargoControlPickDO.setPickVolume(addPickVolume(orderCargoControlPickDO.getPickNum(), orderCargoControlPickDO.getControlNum(), orderDO.getSumNum(), orderDO.getSumVolume(), (orderDO.getSumVolume().subtract(pickVolume))));
                orderCargoControlPickDO.setPickWeight(addPickWeight(orderCargoControlPickDO.getPickNum(), orderCargoControlPickDO.getControlNum(), orderDO.getSumNum(), orderDO.getSumWeight(), (orderDO.getSumWeight().subtract(pickWeight))));
                orderCargoControlPickDO.setPickQuantity(addPickQuantity(orderCargoControlPickDO.getPickNum(), orderCargoControlPickDO.getControlNum(), orderDO.getSumNum(), orderDO.getSumQuantity(), (orderDO.getSumQuantity() - pickQuantity)));
                if (orderCargoControlPickDO.getPickQuantity() > (orderDO.getSumQuantity() - pickQuantity)) {
                    orderCargoControlPickDO.setPickQuantity(orderDO.getSumQuantity() - pickQuantity);
                }
                if (orderCargoControlPickDO.getPickVolume().compareTo(orderDO.getSumVolume().subtract(pickVolume)) > 0) {
                    orderCargoControlPickDO.setPickVolume(orderDO.getSumVolume().subtract(pickVolume));
                }
                if (orderCargoControlPickDO.getPickWeight().compareTo(orderDO.getSumWeight().subtract(pickWeight)) > 0) {
                    orderCargoControlPickDO.setPickWeight(orderDO.getSumWeight().subtract(pickWeight));
                }
                orderCargoControlPickMapper.updateById(orderCargoControlPickDO);
                String msg = String.format("订单原放货%s箱, 订单当前放货%s箱", orderCargoControlPickApplyVO.getPickNum(),
                        orderCargoControlPickApplyVO.getCurrentPickNum());
                // 当前已放货箱数
                Integer releasePickNum = orderCargoControlPickApplyVO.getCurrentPickNum() + pickNum;
                if (releasePickNum == 0) {
                    // 放货箱数0
                    orderService.update(new LambdaUpdateWrapper<OrderDO>()
                            .set(OrderDO::getCargoControlStatus, 0)
                            .set(OrderDO::getReleaseNum, 0)
                            .set(OrderDO::getReleaseRatio, BigDecimal.ZERO)
                            .eq(OrderDO::getOrderId, orderCargoControlPickDO.getOrderId()));
                    msg = msg.concat(", 订单控货中");
                }
                if (releasePickNum > 0 && releasePickNum < orderDO.getSumNum()) {
                    // 放货完部分箱数
                    orderService.update(new LambdaUpdateWrapper<OrderDO>()
                            .set(OrderDO::getCargoControlStatus, 2)
                            .set(OrderDO::getReleaseNum, releasePickNum)
                            .set(OrderDO::getReleaseRatio, new BigDecimal(releasePickNum).divide(new BigDecimal(orderDO.getSumNum()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")))
                            .eq(OrderDO::getOrderId, orderCargoControlPickDO.getOrderId()));
                    msg = msg.concat(", 订单部分控货中");
                }
                if (releasePickNum > 0 && Objects.equals(releasePickNum, orderDO.getSumNum())) {
                    // 放货完所有箱数
                    orderService.update(new LambdaUpdateWrapper<OrderDO>()
                            .set(OrderDO::getCargoControlStatus, 1)
                            .set(OrderDO::getReleaseNum, releasePickNum)
                            .set(OrderDO::getReleaseRatio, new BigDecimal(releasePickNum).divide(new BigDecimal(orderDO.getSumNum()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")))
                            .eq(OrderDO::getOrderId, orderCargoControlPickDO.getOrderId()));
                    msg = msg.concat(", 订单已放完货");
                }
                OrderControlLogParam param = new OrderControlLogParam();
                param.setTypeKey(17);
                param.setType("放货修改审批通过");
                param.setMsg(msg);
                param.setOrderId(orderCargoControlPickApplyVO.getOrderId());
                param.setApprovalId(orderApprovalDO.getOrderApprovalId());
                controlLogParams.add(param);
            } else if (orderApprovalDO.getType() == 8) {
                this.batchAntiCheckingOrderCargoControlPick(orderCargoControlPickDOList, orderApprovalDO.getOrderId(), 3);
                String msg = "放货反复核申请，对放货:%s,进行反复核";
                OrderControlLogParam param = new OrderControlLogParam();
                param.setTypeKey(18);
                param.setType("放货反复核通过");
                StringBuilder sb = new StringBuilder();
                for (OrderCargoControlPickDO cargoControlPickDO : orderCargoControlPickDOList) {
                    String content = "收发货人%s放货%s箱";
                    content = String.format(content, cargoControlPickDO.getConsigneeName() + "/" + (StringUtils.isNotBlank(cargoControlPickDO.getConsigneeNameEn()) ? cargoControlPickDO.getConsigneeNameEn() : "空"),
                            cargoControlPickDO.getPickNum());
                    if (StringUtils.isNotBlank(sb)) {
                        sb.append("和").append(content);
                    } else {
                        sb.append(content);
                    }
                }
                param.setMsg(String.format(msg, sb));
                param.setOrderId(orderDO.getOrderId());
                param.setApprovalId(orderApprovalDO.getOrderApprovalId());
                controlLogParams.add(param);
            } else if (orderApprovalDO.getType() == 9) {
                // 处理调货订单业务的货物放货数量增减
                orderCargoControlPickDO.setStatus(3);
                int seasoningCondimentsCount = 0;
                String seasoningCondimentsOrderNumbers = "";
                if (CollectionUtil.isNotEmpty(orderCargoControlPickApplyVO.getOrderBackPageVOList())) {
                    for (OrderBackPageVO orderBackPageVO : orderCargoControlPickApplyVO.getOrderBackPageVOList()) {
                        if (orderBackPageVO.getReleaseNum() > 0) {
                            OrderCargoControlPickDO orderCargoControlPick = new OrderCargoControlPickDO();
                            orderCargoControlPick.setOrderId(orderBackPageVO.getOrderId());
                            orderCargoControlPick.setOrderNo(orderBackPageVO.getOrderNo());
                            orderCargoControlPick.setTidanNo(orderBackPageVO.getTidanNo());
                            orderCargoControlPick.setRemarks("调货");
                            orderCargoControlPick.setStatus(1);
                            orderCargoControlPick.setConsigneeName(orderBackPageVO.getConsigneeName());
                            orderCargoControlPick.setConsigneeNameEn(orderBackPageVO.getConsigneeNameEn());
                            orderCargoControlPick.setConsigneePhone(orderBackPageVO.getConsigneePhone());
                            orderCargoControlPick.setConsigneeCountryCode(orderBackPageVO.getConsigneeCountryCode());
                            orderCargoControlPick.setPickNum(orderBackPageVO.getReleaseNum());
                            // 计算放货体积、重量、数量平均值
                            orderCargoControlPick.setPickVolume(addPickVolume(orderBackPageVO.getReleaseNum(), orderBackPageVO.getControlNum(), orderBackPageVO.getSumNum(), orderBackPageVO.getSumVolume(), orderBackPageVO.getControlVolume()));
                            orderCargoControlPick.setPickWeight(addPickWeight(orderBackPageVO.getReleaseNum(), orderBackPageVO.getControlNum(), orderBackPageVO.getSumNum(), orderBackPageVO.getSumWeight(), orderBackPageVO.getControlWeight()));
                            orderCargoControlPick.setPickQuantity(addPickQuantity(orderBackPageVO.getReleaseNum(), orderBackPageVO.getControlNum(), orderBackPageVO.getSumNum(), orderBackPageVO.getSumQuantity(), orderBackPageVO.getControlQuantity()));
                            this.seasoningCondimentsOrderCargoControlPick(orderCargoControlPick, orderCargoControlPickDO, orderApprovalDO.getOrderApprovalId());
                            seasoningCondimentsCount = seasoningCondimentsCount + orderBackPageVO.getReleaseNum();
                            seasoningCondimentsOrderNumbers = StringUtils.isNotBlank(seasoningCondimentsOrderNumbers) ?
                                    (StrUtil.COMMA + orderBackPageVO.getOrderNo()) : orderBackPageVO.getOrderNo();
                        }
                    }

                }
                int orgPickNum = orderCargoControlPickApplyVO.getPickNum();
                int pickNum = orgPickNum - seasoningCondimentsCount;
                orderCargoControlPickDO.setPickNum(Math.max(pickNum, 0));
                // 反复核提交箱数
                int antiCheckingPickNum = orderCargoControlPickDO.getPickNum() == 0 ? orgPickNum : seasoningCondimentsCount;
                // 校验放货数量与提货数量
                checkAntiCheckingOrderPickNum(antiCheckingPickNum, orderDO.getOrderId(), orderDO.getOrderNo());
                if (orderCargoControlPickDO.getPickNum() == 0) {
                    // TODO 是否需要修改放货数量等于0的放货记录状态
                    // 放货归0需要
                    orderCargoControlPickDO.setPickQuantity(0);
                    orderCargoControlPickDO.setPickWeight(BigDecimal.ZERO);
                    orderCargoControlPickDO.setPickVolume(BigDecimal.ZERO);
                } else {
                    BigDecimal ratio = new BigDecimal(pickNum).divide(new BigDecimal(orgPickNum), 5, RoundingMode.HALF_UP);
                    orderCargoControlPickDO.setPickQuantity(new BigDecimal(orderCargoControlPickDO.getPickQuantity()).multiply(ratio).setScale(0, RoundingMode.UP).intValue());
                    orderCargoControlPickDO.setPickWeight(orderCargoControlPickDO.getPickWeight().multiply(ratio).setScale(2, RoundingMode.UP));
                    orderCargoControlPickDO.setPickVolume(orderCargoControlPickDO.getPickVolume().multiply(ratio).setScale(2, RoundingMode.UP));
                }
                orderCargoControlPickMapper.updateById(orderCargoControlPickDO);
                Long count = orderCargoControlPickMapper.selectCount(new LambdaQueryWrapper<OrderCargoControlPickDO>()
                        .eq(OrderCargoControlPickDO::getOrderId, orderCargoControlPickDO.getOrderId())
                        .in(OrderCargoControlPickDO::getStatus, 1, 2, 3, 4, 5, 6)
                        .gt(OrderCargoControlPickDO::getPickNum, 0)
                        .eq(OrderCargoControlPickDO::getDeleted, false));
                // 避免并发修改，这里只对订单的控货状态进行修改
                if (count == 0) {
                    orderService.update(new LambdaUpdateWrapper<OrderDO>()
                            .set(OrderDO::getCargoControlStatus, 0)
                            .set(OrderDO::getReleaseNum, 0)
                            .set(OrderDO::getReleaseRatio, BigDecimal.ZERO)
                            .eq(OrderDO::getOrderId, orderCargoControlPickDO.getOrderId()));
                }
                if (count > 0) {
                    if (orderDO.getCargoControlStatus() == 1) {
                        // 放完货的改为放货中
                        orderService.update(new LambdaUpdateWrapper<OrderDO>()
                                .set(OrderDO::getCargoControlStatus, 2)
                                .set(OrderDO::getReleaseNum, count)
                                .set(OrderDO::getReleaseRatio, new BigDecimal(count).divide(new BigDecimal(orderDO.getSumNum()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")))
                                .eq(OrderDO::getOrderId, orderCargoControlPickDO.getOrderId()));
                    }else {
                        // 放完货的改为放货中
                        orderService.update(new LambdaUpdateWrapper<OrderDO>()
                                .set(OrderDO::getReleaseNum, count)
                                .set(OrderDO::getReleaseRatio, new BigDecimal(count).divide(new BigDecimal(orderDO.getSumNum()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")))
                                .eq(OrderDO::getOrderId, orderCargoControlPickDO.getOrderId()));
                    }
                }
                OrderControlLogParam controlLogParam = new OrderControlLogParam();
                controlLogParam.setTypeKey(19);
                controlLogParam.setType("订单调货审批通过");
                controlLogParam.setMsg(orderCargoControlPickApplyVO.getReasonZh());
                controlLogParam.setOrderId(orderCargoControlPickApplyVO.getOrderId());
                controlLogParam.setApprovalId(orderApprovalDO.getOrderApprovalId());
                controlLogParams.add(controlLogParam);
                // 发送调货短信通知
//                this.smsSendSendSingle(orderDO, SmsSceneEnum.NOTIFICATION_SUCCESS_SEASONING_CONDIMENTS, seasoningCondimentsOrderNumbers);
            } else if (orderApprovalDO.getType() == 10) {
                orderCargoControlPickDO.setStatus(0);
                orderCargoControlPickMapper.updateById(orderCargoControlPickDO);
                // TODO 需要处理取消后，订单没有放货记录，订单中控货状态是否改变
                Long count = orderCargoControlPickMapper.selectCount(new LambdaQueryWrapper<OrderCargoControlPickDO>()
                        .eq(OrderCargoControlPickDO::getOrderId, orderCargoControlPickDO.getOrderId())
                        .in(OrderCargoControlPickDO::getStatus, 1, 2, 3, 4, 5, 6)
                        .gt(OrderCargoControlPickDO::getPickNum, 0)
                        .eq(OrderCargoControlPickDO::getDeleted, false));
                String msg = "";
                // 避免并发修改，这里只对订单的控货状态进行修改
                if (count == 0) {
                    orderService.update(new LambdaUpdateWrapper<OrderDO>()
                            .set(OrderDO::getCargoControlStatus, 0)
                            .set(OrderDO::getReleaseNum, 0)
                            .set(OrderDO::getReleaseRatio, BigDecimal.ZERO)
                            .eq(OrderDO::getOrderId, orderCargoControlPickDO.getOrderId()));
                    msg = String.format("订单放货%s箱, 取消放货审批通过, 控货状态改为控货中", orderCargoControlPickDO.getPickNum());
                }
                if (count > 0) {
                    if (orderDO.getCargoControlStatus() == 1) {
                        // 放完货的改为放货中
                        orderService.update(new LambdaUpdateWrapper<OrderDO>()
                                .set(OrderDO::getCargoControlStatus, 2)
                                .set(OrderDO::getReleaseNum, count)
                                .set(OrderDO::getReleaseRatio, new BigDecimal(count).divide(new BigDecimal(orderDO.getSumNum()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")))
                                .eq(OrderDO::getOrderId, orderCargoControlPickDO.getOrderId()));
                        msg = String.format("订单放货%s箱, 取消放货审批通过, 放完货的改为放货中", orderCargoControlPickDO.getPickNum());
                    } else {
                        orderService.update(new LambdaUpdateWrapper<OrderDO>()
                                .set(OrderDO::getReleaseNum, count)
                                .set(OrderDO::getReleaseRatio, new BigDecimal(count).divide(new BigDecimal(orderDO.getSumNum()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")))
                                .eq(OrderDO::getOrderId, orderCargoControlPickDO.getOrderId()));
                        msg = String.format("订单放货%s箱, 取消放货审批通过", orderCargoControlPickDO.getPickNum());
                    }

                }
                OrderControlLogParam controlLogParam = new OrderControlLogParam();
                controlLogParam.setTypeKey(21);
                controlLogParam.setType("订单取消放货审批通过");
                controlLogParam.setMsg(msg);
                controlLogParam.setOrderId(orderCargoControlPickApplyVO.getOrderId());
                controlLogParam.setApprovalId(orderApprovalDO.getOrderApprovalId());
                controlLogParams.add(controlLogParam);
                // 发送取消放货短信通知
                this.smsSendSendSingle(orderDO, SmsSceneEnum.NOTIFICATION_SUCCESS_CANCEL_DELIVERY, 0, null, orderCargoControlPickDO);
            }
        }
        orderApprovalMapper.updateById(orderApprovalDO);
        orderBusinessService.createOrderControlLogs(controlLogParams);
    }

    private Integer addPickQuantity(Integer releaseNum, Integer controlNum, Integer sumNum, Integer sumQuantity, Integer controlQuantity) {
        int releaseQuantity = 0;
        if (Objects.equals(releaseNum, controlNum)) {
            return controlQuantity;
        }
        if (sumQuantity == 0) {
            return releaseQuantity;
        }
        releaseQuantity = new BigDecimal(sumQuantity).multiply(new BigDecimal(releaseNum.toString()).divide(new BigDecimal(sumNum.toString()), 5, RoundingMode.HALF_UP)).setScale(0, RoundingMode.UP).intValue();
        return releaseQuantity;
    }

    private BigDecimal addPickVolume(Integer releaseNum, Integer controlNum, Integer sumNum, BigDecimal sumVolume, BigDecimal controlVolume) {
        BigDecimal releaseVolume = BigDecimal.ZERO;
        if (Objects.equals(releaseNum, controlNum)) {
            return controlVolume;
        }
        if (sumVolume.compareTo(BigDecimal.ZERO) == 0) {
            return releaseVolume;
        }
        releaseVolume = sumVolume.multiply(new BigDecimal(releaseNum.toString()).divide(new BigDecimal(sumNum.toString()), 5, RoundingMode.HALF_UP)).setScale(2, RoundingMode.UP);
        return releaseVolume;
    }

    private BigDecimal addPickWeight(Integer releaseNum, Integer controlNum, Integer sumNum, BigDecimal sumWeight, BigDecimal controlWeight) {
        BigDecimal releaseWeight = BigDecimal.ZERO;
        if (Objects.equals(releaseNum, controlNum)) {
            return controlWeight;
        }
        if (sumWeight.compareTo(BigDecimal.ZERO) == 0) {
            return releaseWeight;
        }
        releaseWeight = sumWeight.multiply(new BigDecimal(releaseNum.toString()).divide(new BigDecimal(sumNum.toString()), 5, RoundingMode.HALF_UP)).setScale(2, RoundingMode.UP);
        return releaseWeight;
    }

    private void smsSendSendSingle(OrderDO orderDO, SmsSceneEnum smsSceneEnum, Integer num, String seasoningCondimentsOrderNumbers, OrderCargoControlPickDO orderCargoControlPickDO) {
        Map<String, Object> templateParams = new HashMap<>(10);
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH) + 1;
        int day = calendar.get(Calendar.DATE);
        templateParams.put("date", DateUtils.formatDateTime(calendar.getTime()));
        templateParams.put("year", year);
        templateParams.put("month", month);
        templateParams.put("day", day);
        templateParams.put("order", orderDO.getOrderNo());
        templateParams.put("number", Objects.nonNull(orderDO.getContainerNumber()) ? orderDO.getContainerNumber() : " ");
        // 控制单个marks长度 超出12个字符，截取后面的字符串替换为...
        String marks = orderDO.getMarks();
        if (StringUtils.isNotBlank(marks) && marks.length() > 15) marks = marks.replaceAll(marks.substring(12), "...");
        templateParams.put("marks", marks);
        templateParams.put("num", num);
        if (StringUtils.isNotBlank(seasoningCondimentsOrderNumbers)) {
            templateParams.put("order2", seasoningCondimentsOrderNumbers);
        }
        // 定义发送短信的对象map，避免收发货人相同的重复发送
        Map<String, SmsSendSingleToUserReqDTO> smsMap = new HashMap<>(2);
//        OrderConsignorDO orderConsignorDO = orderConsignorService.getOne(new LambdaQueryWrapper<OrderConsignorDO>().eq(OrderConsignorDO::getOrderId, orderDO.getOrderId())
//                .orderByDesc(OrderConsignorDO::getId)
//                .last("limit 1"));
        //发货人 短信发送信息(当前控货人)
        String consignorCountryCode = orderCargoControlPickDO.getCountryCode();
        String consignorPhone = orderCargoControlPickDO.getPhone();
        Long consignorCustomerId = 0L; // 当前控货人不一定绑定了客户信息，默认给0
        SmsSendSingleToUserReqDTO reqDTO = new SmsSendSingleToUserReqDTO();
        reqDTO.setAreaCode(consignorCountryCode);
        reqDTO.setMobile(consignorPhone);
        reqDTO.setUserId(consignorCustomerId);
        reqDTO.setTemplateCode(smsSceneEnum.getTemplateCode());
        reqDTO.setTemplateParams(templateParams);

        smsMap.put(consignorCountryCode + consignorPhone, reqDTO);

//        OrderConsigneeDO orderConsigneeDO = orderConsigneeService.getOne(new LambdaQueryWrapper<OrderConsigneeDO>().eq(OrderConsigneeDO::getOrderId, orderDO.getOrderId())
//                .orderByDesc(OrderConsigneeDO::getId)
//                .last("limit 1"));
        //收货人 短信发送信息
        String consigneeCountryCode = orderCargoControlPickDO.getConsigneeCountryCode();
        String consigneePhone = orderCargoControlPickDO.getConsigneePhone();
        Long consigneeCustomerId = 0L; // 放货记录中的收货人信息未关联客户信息，默认给0
        reqDTO = new SmsSendSingleToUserReqDTO();
        reqDTO.setAreaCode(consigneeCountryCode);
        reqDTO.setMobile(consigneePhone);
        reqDTO.setUserId(consigneeCustomerId);
        reqDTO.setTemplateCode(smsSceneEnum.getTemplateCode());
        reqDTO.setTemplateParams(templateParams);
        smsMap.put(consigneeCountryCode + consigneePhone, reqDTO);
        for (Map.Entry<String, SmsSendSingleToUserReqDTO> entry : smsMap.entrySet()) {
            smsSendApi.sendSingleSmsToAdmin(entry.getValue());
        }
    }


    @Override
    public void reviewOrderCargoControlPick(OrderCargoControlPickDO orderCargoControlPickDO) {
        if (orderCargoControlPickDO.getStatus() == 1 && !orderCargoControlPickDO.getDeleted()) {
            orderCargoControlPickDO.setStatus(3);
            orderCargoControlPickDO.setCheckTime(new Date()); // 补充复核时间
            orderCargoControlPickMapper.updateById(orderCargoControlPickDO);
        } else {
            throw exception(ORDER_CARGO_CONTROL_PICK_STATUS_ERROR);
        }
        OrderDO orderDO = orderService.getById(orderCargoControlPickDO.getOrderId());
        // 发送放货短信通知
        this.smsSendSendSingle(orderDO, NOTIFICATION_SUCCESS_DELIVERY, orderCargoControlPickDO.getPickNum(), null, orderCargoControlPickDO);
        // 需要处理订单状态
        OrderCargoControlReleaseInfoDto releaseInfoDto = orderCargoControlMapper.getOrderCargoControlReleaseInfo(orderCargoControlPickDO.getOrderId());
        if (Objects.nonNull(releaseInfoDto)) {
            orderService.update(new LambdaUpdateWrapper<OrderDO>()
                    .set(OrderDO::getCargoControlStatus, releaseInfoDto.getReleaseNum() == 0 ? 0 : (releaseInfoDto.getReleaseNum() >= releaseInfoDto.getSumNum()) ? 1 : 2)
                    .eq(OrderDO::getOrderId, orderCargoControlPickDO.getOrderId()));

        }
        // TODO 订单控货信息日志补充
        String msg = String.format("订单放货%s箱复核成功, 收货人姓名%s,电话+%s", orderCargoControlPickDO.getPickNum(),
                orderCargoControlPickDO.getConsigneeName() + "/" + (StringUtils.isNotBlank(orderCargoControlPickDO.getConsigneeNameEn()) ? orderCargoControlPickDO.getConsigneeNameEn() : "空"),
                orderCargoControlPickDO.getConsigneeCountryCode() + orderCargoControlPickDO.getConsigneePhone());
        orderBusinessService.createOrderControlLog(orderCargoControlPickDO.getOrderId(), 5, "订单放货复核", msg, 0L);
    }

    @Override
    public void reviewOrderCargoControlPick(List<OrderCargoControlPickDO> orderCargoControlPickDOList) {
        for (OrderCargoControlPickDO orderCargoControlPickDO : orderCargoControlPickDOList) {
            this.reviewOrderCargoControlPick(orderCargoControlPickDO);
        }
    }

    @Override
    public void cancelOrderCargoControlPick(OrderCargoControlPickDO orderCargoControlPickDO) {
        if (orderCargoControlPickDO.getStatus() == 1 && !orderCargoControlPickDO.getDeleted()) {
            orderCargoControlPickDO.setStatus(0);
            orderCargoControlPickMapper.updateById(orderCargoControlPickDO);
        } else {
            throw exception(ORDER_CARGO_CONTROL_PICK_STATUS_ERROR);
        }
        // TODO 需要处理订单状态
        OrderCargoControlReleaseInfoDto releaseInfoDto = orderCargoControlMapper.getOrderCargoControlReleaseInfo(orderCargoControlPickDO.getOrderId());
        if (Objects.nonNull(releaseInfoDto)) {
            orderService.update(new LambdaUpdateWrapper<OrderDO>()
                    .set(OrderDO::getCargoControlStatus, releaseInfoDto.getReleaseNum() == 0 ? 0 : (releaseInfoDto.getReleaseNum() >= releaseInfoDto.getSumNum()) ? 1 : 2)
                    .eq(OrderDO::getOrderId, orderCargoControlPickDO.getOrderId()));
        }
        // TODO 订单控货信息日志补充
        String msg = String.format("订单放货%s箱取消成功", orderCargoControlPickDO.getPickNum());
        orderBusinessService.createOrderControlLog(orderCargoControlPickDO.getOrderId(), 6, "订单放货取消", msg, 0L);
    }

    @Override
    public void batchAntiCheckingOrderCargoControlPick(List<OrderCargoControlPickDO> allOrderCargoControlPickDOList, Long orderId, Integer type) {
        if (type == 1 || type == 3) {
            OrderDO orderDO = orderQueryService.getOrderById(orderId);
            // 反复核提交箱数
            int antiCheckingPickNum = allOrderCargoControlPickDOList.stream().filter(pick -> pick.getStatus() == 3 || pick.getStatus() == 4).mapToInt(OrderCargoControlPickDO::getPickNum).sum();
            // 校验放货数量与提货数量
            checkAntiCheckingOrderPickNum(antiCheckingPickNum, orderId, orderDO.getOrderNo());
        }
        for (OrderCargoControlPickDO orderCargoControlPickDO : allOrderCargoControlPickDOList) {
            orderCargoControlPickDO.setUpdateTime(new Date());
            switch (type) {
                case 1:
                    if (orderCargoControlPickDO.getStatus() == 3 && !orderCargoControlPickDO.getDeleted()) {
                        orderCargoControlPickDO.setStatus(1);
                    } else {
                        throw exception(ORDER_CARGO_CONTROL_PICK_STATUS_ERROR);
                    }
                    break;
                case 2:
                    if (orderCargoControlPickDO.getStatus() == 4 && !orderCargoControlPickDO.getDeleted()) {
                        orderCargoControlPickDO.setStatus(3);
                    } else {
                        throw exception(ORDER_CARGO_CONTROL_PICK_STATUS_ERROR);
                    }
                    break;
                case 3:
                    if (orderCargoControlPickDO.getStatus() == 4 && !orderCargoControlPickDO.getDeleted()) {
                        orderCargoControlPickDO.setStatus(1);
                    } else {
                        throw exception(ORDER_CARGO_CONTROL_PICK_STATUS_ERROR);
                    }
                    break;
                default:
                    return;
            }
            // TODO 需要处理订单状态
        }
        this.updateBatchById(allOrderCargoControlPickDOList);
        OrderCargoControlReleaseInfoDto releaseInfoDto = orderCargoControlMapper.getOrderCargoControlReleaseInfo(orderId);
        if (Objects.nonNull(releaseInfoDto)) {
            orderService.update(new LambdaUpdateWrapper<OrderDO>()
                    .set(OrderDO::getCargoControlStatus, releaseInfoDto.getReleaseNum() == 0 ? 0 : (releaseInfoDto.getReleaseNum() >= releaseInfoDto.getSumNum()) ? 1 : 2)
                    .eq(OrderDO::getOrderId, orderId));
        }
        // TODO 订单控货信息日志补充
    }

    /**
     * 校验反复核放货箱数与已提货箱数的一致性，确保未放货数量+已提货数据+已放货数量未提货数量=订单总数量。
     * 这里实际就是提货货箱数 不得大于已放货箱数(包括反复核后剩下得已放货箱数)
     *
     * @param antiCheckingPickNum 反复核提交箱数
     * @param orderId             订单ID
     * @param orderNo             订单编号
     */
    private void checkAntiCheckingOrderPickNum(int antiCheckingPickNum, Long orderId, String orderNo) {
        // 已提货的箱数
        int pickupNum = orderPickupMapper.selectPickedNum(orderNo);
        // 已复核和正在进行反复核的放货箱数
        int pickNum = orderCargoControlPickMapper.getPickNumByOrderId(orderId);
        // 反复核成功后的剩余放货箱数
        int antiCheckingAfterPickNum = pickNum - antiCheckingPickNum;
        // 反复核成功后的剩余放货箱数 < 已提货的箱数 ---> 无法放货反复核，需先撤销提货
        if (antiCheckingAfterPickNum < pickupNum) {
            throw exception(ORDER_PICK_ANTIC_CHECKING_ERROR);
        }
    }

    @Override
    public void cancelApprovalByOrderApprovalId(Long orderApprovalId, String reason) {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        Integer userType = loginUser != null ? loginUser.getUserType() : null;
        Long userId = loginUser != null ? loginUser.getId() : null;
        if (Objects.equals(userType, UserTypeEnum.MEMBER.getValue())) {
            DictDataRespDTO dto = dictDataApi.parseDictDataFromCache(CUSTOMER_USER_TO_ADMIN, CUSTOMER_USER_APPROVAL_ID);
            userId = Long.valueOf(dto.getValue());
        }
        OrderApprovalDO approvalDO = orderApprovalMapper.selectById(orderApprovalId);
        if (approvalDO.getDeleted() ||
                (approvalDO.getType() != 7
                        && approvalDO.getType() != 8
                        && approvalDO.getType() != 9
                        && approvalDO.getType() != 10
                        && approvalDO.getType() != 61
                        && approvalDO.getType() != 62
                        && approvalDO.getStatus() != 1)) {
            throw exception(ORDER_APPROVAL_STATUS_NOT_CORRECT);
        }
        if (Objects.isNull(approvalDO.getFormId())) {
            throw exception(ORDER_APPROVAL_FORM_ID_NOT_EXISTS);
        }
        bpmCreateServiceFactory.cancelBmpById(userId, approvalDO.getFormId(), reason);
    }

}
