package com.prolog.rdc.tms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.exception.ParameterException;
import com.prolog.framework.core.exception.PrologException;
import com.prolog.framework.core.pojo.Page;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Restriction;
import com.prolog.framework.core.restriction.Restrictions;
import com.prolog.framework.dao.util.PageUtils;
import com.prolog.product.core.easyexcel.util.ExcelUtils;
import com.prolog.product.core.framework.entity.UserEntity;
import com.prolog.product.core.framework.util.PlgFxUsrUtils;
import com.prolog.product.core.tools.util.ToolKits;
import com.prolog.rdc.tms.constant.BmsConstant;
import com.prolog.rdc.tms.constant.RabbitMQConstant;
import com.prolog.rdc.tms.constant.enums.LogTypeEnum;
import com.prolog.rdc.tms.dao.mapper.BmsBillIncomeFeeDetailMapper;
import com.prolog.rdc.tms.dao.mapper.BmsBillIncomeFeeHeaderMapper;
import com.prolog.rdc.tms.dao.mapper.LoadingBillHeadMapper;
import com.prolog.rdc.tms.dao.mapper.ShipBillHeadMapper;
import com.prolog.rdc.tms.model.dto.SySParameterDTO;
import com.prolog.rdc.tms.model.dto.basicConfigure.StandardTemplateDetailsListDTO;
import com.prolog.rdc.tms.model.dto.income.*;
import com.prolog.rdc.tms.model.dto.loadingbill.BmsLoadingBillDTO;
import com.prolog.rdc.tms.model.dto.shipbill.BmsLogOperationDTO;
import com.prolog.rdc.tms.model.dto.shipbill.BmsShipBillDTO;
import com.prolog.rdc.tms.model.dto.shipbill.BmsShipBillDetailDTO;
import com.prolog.rdc.tms.model.dto.shipbill.BmsShipBillPackageDTO;
import com.prolog.rdc.tms.model.entity.*;
import com.prolog.rdc.tms.model.vo.BmsFeeAdjustImportVO;
import com.prolog.rdc.tms.model.vo.basicConfigure.ImportLogAddVO;
import com.prolog.rdc.tms.model.vo.income.ArReconciliationLoadingVO;
import com.prolog.rdc.tms.model.vo.income.BmsIncomeQueryVO;
import com.prolog.rdc.tms.proxy.MainDataProxy;
import com.prolog.rdc.tms.rmi.feign.MaindataFeign;
import com.prolog.rdc.tms.service.ArReconciliationMngService;
import com.prolog.rdc.tms.service.BmsBillLogService;
import com.prolog.rdc.tms.service.BmsLoadingBillService;
import com.prolog.rdc.tms.service.BmsShipBillService;
import com.prolog.rdc.tms.util.ConvertorUtil;
import com.prolog.rdc.tms.util.FileUtils;
import com.prolog.rdc.tms.util.ImportUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.plugin.PluginException;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.TreeMap;
import java.util.stream.Collectors;

/**
 * @author lhb
 * @date 2023/4/13
 */
@Service
@Slf4j
public class ArReconciliationMngServiceServiceImpl implements ArReconciliationMngService {

    @Autowired
    private BmsShipBillService shipBillService;

    @Autowired
    private BmsLoadingBillService loadingBillService;

    @Autowired
    private BmsBillLogService logService;

    @Autowired
    private BmsBillIncomeFeeHeaderMapper incomeFeeHeaderMapper;

    @Autowired
    private LoadingBillHeadMapper loadingBillHeadMapper;

    @Autowired
    private BmsBillIncomeFeeDetailMapper incomeFeeDetailMapper;

    @Autowired
    private MainDataProxy mainDataProxy;

    @Autowired
    private ConvertorUtil convertorUtil;

    @Autowired
    private ShipBillHeadMapper shipBillHeadMapper;

    @Autowired
    private MaindataFeign maindataTmsResource;

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Autowired
    private MaindataFeign maindataFeign;

    @Override
    public Page<ArReconciliationLoadingDTO> findLoadingBillFee(ArReconciliationLoadingVO vo) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();

        vo.setEnterpriseId(user.getEnterpriseId());
        vo.setUserType(user.getUserType());
        if (user.getUserType().equals(BmsConstant.USER_TYPE_ZY)) {
            if (user.getOwnedAllDataAuthFlag().equals(BmsConstant.USER_DEPARTMENT_AUTH_Y)) {
                vo.setDepartmentIds(user.getDepts().toArray(new String[0]));
                vo.setIsDept(BmsConstant.IS_DEPT_YES);
            }
        }

        PageUtils.startPage(vo.getPageNum(), vo.getPageSize());
        List<ArReconciliationLoadingDTO> dtoList = incomeFeeHeaderMapper.findLoadingBillFeeForAr(vo);
        if (CollectionUtil.isNotEmpty(dtoList)) {
            List<SysRefdatadModel> dicData = getLoadingDic();
            dtoList.forEach(dto -> {
                dto.setStatusName(ConvertorUtil.getName(dicData, BmsConstant.LOADING_BILL_STATUS, String.valueOf(dto.getStatus())));
                dto.setSourceName(ConvertorUtil.getName(dicData, BmsConstant.SOURCE, String.valueOf(dto.getSource())));
                dto.setSynchronousStatusName(ConvertorUtil.getName(dicData, BmsConstant.SYNCHRONOUS_STATUS, String.valueOf(dto.getSynchronousStatus())));
                dto.setFeeCltTypeName(ConvertorUtil.getName(dicData, BmsConstant.FEE_CLT_TYPE, String.valueOf(dto.getFeeCltType())));
                dto.setCostStatusName(ConvertorUtil.getName(dicData, BmsConstant.COST_STATUS, String.valueOf(dto.getCostStatus())));
                dto.setSettlementStatusName(ConvertorUtil.getName(dicData, BmsConstant.SETTLEMENT_STATUS, String.valueOf(dto.getSettlementStatus())));
                dto.setCarrierTypeName(ConvertorUtil.getName(dicData, BmsConstant.LINE_CARRIER_TYPE, String.valueOf(dto.getCarrierType())));
                dto.setCheckStatusName(ConvertorUtil.getName(dicData, BmsConstant.CHECK_STATUS, String.valueOf(dto.getCheckStatus())));
            });
        }
        return PageUtils.getPage(dtoList);
    }

    @Override
    // 运单查询
    public List<BmsShipBillDTO> getShipBill(Long id) {
        BmsBillIncomeFeeHeaderModel headerModel = incomeFeeHeaderMapper.findById(id, BmsBillIncomeFeeHeaderModel.class);
        return loadingBillService.getShipBill(headerModel.getBillId());
    }

    @Override
    public Page<BmsShipBillIncomeFeeDTO> findShipBillFee(BmsIncomeQueryVO vo) {
        PageUtils.startPage(vo.getPageNum(), vo.getPageSize());
        List<BmsShipBillIncomeFeeDTO> dtoList = incomeFeeHeaderMapper.findShipBillFee(vo);
        if (CollectionUtil.isNotEmpty(dtoList)) {
            List<SysRefdatadModel> dicData = getShipBillDic();
            dtoList.forEach(dto -> {
                dto.setOrderTypeName(ConvertorUtil.getName(dicData, BmsConstant.ORDER_TYPE, String.valueOf(dto.getOrderType())));
                dto.setOrderBusinessTypeName(ConvertorUtil.getName(dicData, BmsConstant.ORDER_BUSINESS_TYPE, String.valueOf(dto.getOrderBusinessType())));
                dto.setTemperatureRequirementName(ConvertorUtil.getName(dicData, BmsConstant.TEMPERATURE_REQUIREMENT, String.valueOf(dto.getTemperatureRequirement())));
                dto.setShipperTypeName(ConvertorUtil.getName(dicData, BmsConstant.SHIPPER_TYPE, String.valueOf(dto.getShipperType())));
                dto.setConsigneeTypeName(ConvertorUtil.getName(dicData, BmsConstant.CONSIGNEE_TYPE, String.valueOf(dto.getConsigneeType())));
                dto.setStatusName(ConvertorUtil.getName(dicData, BmsConstant.SHIPBILL_STATUS, String.valueOf(dto.getStatus())));
                dto.setSourceName(ConvertorUtil.getName(dicData, BmsConstant.SOURCE, String.valueOf(dto.getSource())));
                dto.setShipBillStatusName(ConvertorUtil.getName(dicData, BmsConstant.SHIPBILL_STATUS, String.valueOf(dto.getShipBillStatus())));
                dto.setSynchronousStatusName(ConvertorUtil.getName(dicData, BmsConstant.SYNCHRONOUS_STATUS, String.valueOf(dto.getSynchronousStatus())));
                dto.setAbnormalStatusName(ConvertorUtil.getName(dicData, BmsConstant.ABNORMAL_STATUS, String.valueOf(dto.getAbnormalStatus())));
                dto.setDeliveryMethodTypeName(ConvertorUtil.getName(dicData, BmsConstant.DELIVERY_METHOD_TYPE, String.valueOf(dto.getDeliveryMethodType())));
                dto.setTransportTypeName(ConvertorUtil.getName(dicData, BmsConstant.TRANSPORT_TYPE, String.valueOf(dto.getTransportType())));
                dto.setFeeCltTypeName(ConvertorUtil.getName(dicData, BmsConstant.FEE_CLT_TYPE, String.valueOf(dto.getFeeCltType())));
                dto.setCostStatusName(ConvertorUtil.getName(dicData, BmsConstant.COST_STATUS, String.valueOf(dto.getCostStatus())));
                dto.setSettlementStatusName(ConvertorUtil.getName(dicData, BmsConstant.SETTLEMENT_STATUS, String.valueOf(dto.getSettlementStatus())));
                dto.setCheckStatusName(ConvertorUtil.getName(dicData, BmsConstant.CHECK_STATUS, String.valueOf(dto.getCheckStatus())));
            });
        }
        return PageUtils.getPage(dtoList);
    }

    @Override
    public BmsBillIncomeFeeInfoDTO detailById(Long id) {
        BmsBillIncomeFeeInfoDTO dto = new BmsBillIncomeFeeInfoDTO();
        BmsBillIncomeFeeHeaderModel headerModel = incomeFeeHeaderMapper.findById(id, BmsBillIncomeFeeHeaderModel.class);
        if (headerModel.getBillType() == 10) {
            dto.setShipBillDTO(shipBillService.detailById(headerModel.getBillId()));
        } else if (headerModel.getBillType() == 20) {
            dto.setLoadingBillDTO(loadingBillService.detailById(headerModel.getBillId()));
        }
        BmsBillIncomeFeeDTO feeDTO = BeanUtil.copyProperties(headerModel, BmsBillIncomeFeeDTO.class);
        feeDTO.setDetailDTOList(getDetail(id));
        dto.setIncomeFeeDTO(feeDTO);
        return dto;
    }

    @Override
    public BmsLoadingBillIncomeFeeInfoDTO detailLoadingBillById(Long id) {
        BmsBillIncomeFeeHeaderModel headerModel = incomeFeeHeaderMapper.findById(id, BmsBillIncomeFeeHeaderModel.class);
        BmsBillIncomeFeeDTO feeDTO = BeanUtil.copyProperties(headerModel, BmsBillIncomeFeeDTO.class);
        feeDTO.setDetailDTOList(getDetail(id));
        BmsLoadingBillDTO loadingBillDTO = loadingBillService.detailById(headerModel.getBillId());
        BmsLoadingBillIncomeFeeInfoDTO loadingBillFeeDTO = BeanUtil.copyProperties(loadingBillDTO, BmsLoadingBillIncomeFeeInfoDTO.class);
        loadingBillFeeDTO.setShipBillList(loadingBillDTO.getShipBillList());
        loadingBillFeeDTO.setIncomeFeeDTO(feeDTO);
        return loadingBillFeeDTO;
    }

    @Override
    public List<BmsBillIncomeFeeDetailDTO> getDetail(Long id) {
        BmsBillIncomeFeeHeaderModel headerModel = incomeFeeHeaderMapper.findById(id, BmsBillIncomeFeeHeaderModel.class);
        List<BmsBillIncomeFeeDetailDTO> dtoList = Lists.newArrayList();
        List<BmsBillIncomeFeeDetailModel> modelList = findDetailModel(headerModel);
        if (CollectionUtil.isNotEmpty(modelList)) {
            List<SysRefdatadModel> dicData = convertorUtil.getDictionary(new String[]{
                    BmsConstant.EXPENSE_STATUS, // 费用状态
                    BmsConstant.BILLING_STATUS // 计费状态
            });
            dtoList = modelList.stream().map(dto -> {
                BmsBillIncomeFeeDetailDTO detailDTO = BeanUtil.copyProperties(dto, BmsBillIncomeFeeDetailDTO.class);
                detailDTO.setExpenseStatusName(ConvertorUtil.getName(dicData, BmsConstant.EXPENSE_STATUS, String.valueOf(detailDTO.getExpenseStatus())));
                detailDTO.setBillingSourceName(detailDTO.getBillingSource() == 1 ? "价格表生成" : "手工录入");
                detailDTO.setBillingTypeName(detailDTO.getBillingType());
                detailDTO.setBillingStatusName(ConvertorUtil.getName(dicData, BmsConstant.BILLING_STATUS, String.valueOf(detailDTO.getBillingStatus())));
                return detailDTO;
            }).collect(Collectors.toList());
        }
        return dtoList;
    }

    @Override
    public List<BmsLogOperationDTO> getLog(Long id) {
        return logService.getLog(LogTypeEnum.FEE, id.toString());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirm(List<String> ids) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        List<BmsBillIncomeFeeHeaderModel> incomeFeeHeaderModels = incomeFeeHeaderMapper.findByIds(BmsBillIncomeFeeHeaderModel.class, ids.toArray(), null);
        if (ObjectUtil.isEmpty(incomeFeeHeaderModels)) {
            throw new PluginException("获取费用信息失败");
        }
        Date date = DateUtil.date();
        for (BmsBillIncomeFeeHeaderModel feeHeaderModel : incomeFeeHeaderModels) {
            if (Integer.valueOf(2).equals(feeHeaderModel.getCheckStatus())) {
                throw new PluginException(StrUtil.format("单据{}已对账确认！", feeHeaderModel.getBillNo()));
            }
            feeHeaderModel.setCheckStatus(2);
            feeHeaderModel.setUpdateperson(user.getNickname());
            feeHeaderModel.setUpdatetime(date);
            incomeFeeHeaderMapper.update(feeHeaderModel);
            // 日志操作
            logService.addLog(LogTypeEnum.STATEMENT, feeHeaderModel.getId().toString(), "已对账确认");
            logService.addLog(LogTypeEnum.LOADING_BILL, feeHeaderModel.getId().toString(), "已对账确认");

            // 费用明细
            Criteria criteriaFeeDetail = Criteria.forClass(BmsBillIncomeFeeDetailModel.class);
            Restriction r1 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getBillId, feeHeaderModel.getBillId());
            Restriction r2 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getBillNo, feeHeaderModel.getBillNo());
            Restriction r3 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getEnterpriseId, user.getEnterpriseId());
            criteriaFeeDetail.setRestriction(Restrictions.and(r1, r2, r3));
            List<BmsBillIncomeFeeDetailModel> feeDetailModels = incomeFeeDetailMapper.findByCriteria(criteriaFeeDetail);

            TreeMap<Long, String> origFeeHeaderIds = new TreeMap<>();
            for (BmsBillIncomeFeeDetailModel feeDetailModel : feeDetailModels) {
                feeDetailModel.setCheckStatus(2);
                feeDetailModel.setUpdateperson(user.getNickname());
                feeDetailModel.setUpdatetime(date);
                incomeFeeDetailMapper.update(feeDetailModel);

                if (ObjectUtil.isNotEmpty(feeDetailModel.getOriginalFeeDetailId())) {
                    BmsBillIncomeFeeDetailModel origFeeDetailModel = incomeFeeDetailMapper.findById(feeDetailModel.getOriginalFeeDetailId(), BmsBillIncomeFeeDetailModel.class);
                    if (ObjectUtil.isNotEmpty(origFeeDetailModel)) {
                        origFeeDetailModel.setCheckStatus(2);
                        origFeeDetailModel.setUpdateperson(user.getNickname());
                        origFeeDetailModel.setUpdatetime(date);
                        incomeFeeDetailMapper.update(origFeeDetailModel);
                        origFeeHeaderIds.put(origFeeDetailModel.getBillId(), origFeeDetailModel.getBillNo());
                    }
                }
            }

            if (ObjectUtil.isEmpty(origFeeHeaderIds)) {
                continue;
            }

            for (Long billId : origFeeHeaderIds.keySet()) {
                String billNo = origFeeHeaderIds.get(billId);

                Criteria criteriaFeeHeader = Criteria.forClass(BmsBillIncomeFeeHeaderModel.class);
                r1 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getBillId, billId);
                r2 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getBillNo, billNo);
                r3 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getEnterpriseId, user.getEnterpriseId());
                criteriaFeeHeader.setRestriction(Restrictions.and(r1, r2, r3));
                List<BmsBillIncomeFeeHeaderModel> origFeeHeaderModels = incomeFeeHeaderMapper.findByCriteria(criteriaFeeHeader);
                if (ObjectUtil.isNotEmpty(origFeeHeaderModels)) {
                    BmsBillIncomeFeeHeaderModel origFeeHeaderModel = origFeeHeaderModels.get(0);
                    origFeeHeaderModel.setCheckStatus(2);
                    origFeeHeaderModel.setUpdateperson(user.getNickname());
                    origFeeHeaderModel.setUpdatetime(date);
                    incomeFeeHeaderMapper.update(origFeeHeaderModel);

                    // 日志操作
                    logService.addLog(LogTypeEnum.STATEMENT, origFeeHeaderModel.getId().toString(), "已对账确认");
                    logService.addLog(LogTypeEnum.LOADING_BILL, origFeeHeaderModel.getId().toString(), "已对账确认");
                }
            }
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importFeeAdjustData(MultipartFile file) throws Exception {
        // 导入文件判断
        FileUtils.multipartFileJudge(file);

        // 获取导入批次号
        RestMessage<String> restMessage = maindataTmsResource.getCodeNumberByCode(BmsConstant.BMS_FEE_ADJUST_IMPORT, "L");
        if (!restMessage.isSuccess()) {
            throw new ParameterException("获取导入批次号调用失败 :" + restMessage.getMessage());
        }
        String importBatchNumber = restMessage.getData();
        if (ObjectUtil.isEmpty(importBatchNumber)) {
            throw new PrologException("导入批次号生成失败");
        }

        // 导入日志对象
        ImportLogAddVO logAddVO = new ImportLogAddVO();
        logAddVO.setImportObjNo(BmsConstant.BMS_FEE_ADJUST_IMPORT);
        logAddVO.setImportBatchNumber(importBatchNumber);

        // 导入统计
        int count = 0;
        try {
            // 导入执行
            count = this.importProcess(file);
            logAddVO.setStatus(BmsConstant.IMPORT_STATUS_YES);
            logAddVO.setSuccessNum(count);
            logAddVO.setFailNum(0);
            RestMessage<String> restMessage1 = maindataTmsResource.addImportLogExecute(logAddVO);
            if (!restMessage1.isSuccess()) {
                throw new ParameterException(restMessage1.getMessage());
            }
        } catch (Exception e) {
            Class<BmsFeeAdjustImportVO> importVOClass = BmsFeeAdjustImportVO.class;
            List<BmsFeeAdjustImportVO> importVOs = ExcelUtils.read(file, importVOClass);
            logAddVO.setStatus(BmsConstant.IMPORT_STATUS_NO);
            logAddVO.setSuccessNum(0);
            logAddVO.setFailNum(importVOs.size());
            logAddVO.setFailReason(e.getMessage());
            // 为了避免导入失败时导入日志的保存事务也被回滚,所以采用消息队列异步保存导入失败的日志
            amqpTemplate.convertAndSend(RabbitMQConstant.FEE_ADJUST_IMPORT_LOG, logAddVO);
            e.printStackTrace();
            throw new ParameterException(e.getMessage());
        }
    }

    public int importProcess(MultipartFile file) {
        // 人员权限
        UserEntity user = PlgFxUsrUtils.getUserEntity();

        SySParameterDTO parameterData = mainDataProxy.queryParameter();
        Integer costPrecision = parameterData.getCostPrecision();
        Integer costInteger = parameterData.getCostInteger();
        RoundingMode roundingMode = null;
        if (costInteger == 1) {
            roundingMode = RoundingMode.HALF_UP;
        } else if (costInteger == 2) {
            roundingMode = RoundingMode.UP;
        } else if (costInteger == 3) {
            roundingMode = RoundingMode.DOWN;
        }
        RoundingMode finalRoundingMode = roundingMode;
        // 当前时间
        Date date = new Date();
        int impCnt = 1;
        Properties properties = new Properties();
        // 待转换的对象
        Class<BmsFeeAdjustImportVO> importVOClass = BmsFeeAdjustImportVO.class;
        // 标准模板查询
        RestMessage<List<StandardTemplateDetailsListDTO>> restMessage = maindataFeign.listStandardTemplateDetailsExecute(BmsConstant.BMS_FEE_ADJUST_IMPORT);
        if (!restMessage.isSuccess()) {
            throw new ParameterException("标准模板详情查询失败:" + restMessage.getMessage());
        }
        List<StandardTemplateDetailsListDTO> standardTemplateDetailsListDTOs = restMessage.getData();
        ToolKits.isParamNull(standardTemplateDetailsListDTOs, "运单标准模板未配置");
        for (StandardTemplateDetailsListDTO standardTemplateDetailsListDTO : standardTemplateDetailsListDTOs) {
            // 属性字段和注解属性字段值 键值对
            properties.setProperty(standardTemplateDetailsListDTO.getStdColNo(), standardTemplateDetailsListDTO.getCustColName());
        }
        // @ExcelProperty注解属性修改
        ImportUtils.setHeaderValue(properties, importVOClass);
        // EXCEL转对象
        List<BmsFeeAdjustImportVO> BmsFeeAdjustImportVOS = null;
        try {
            BmsFeeAdjustImportVOS = ExcelUtils.read(file, importVOClass);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ParameterException("EXCEL转对象失败:" + e.getMessage());
        }
        if (ObjectUtil.isEmpty(BmsFeeAdjustImportVOS)) {
            throw new PrologException(StrUtil.format("EXCEL文件内容为空,请重新导入"));
        }
        int num = 1;
        for (BmsFeeAdjustImportVO feeAdjustImportVO : BmsFeeAdjustImportVOS) {
            log.info("数据校验,导入的第{}行数据:{}",num, JSON.toJSONString(feeAdjustImportVO));
            if (ObjectUtil.isEmpty(feeAdjustImportVO.getCargoOwnerName())) {
                throw new PrologException(StrUtil.format("第{}行导入数据,货主名称不为空", num));
            }
            if (ObjectUtil.isEmpty(feeAdjustImportVO.getLoadingBillNo())) {
                throw new PrologException(StrUtil.format("第{}行导入数据,派车单号不为空", num));
            }
            if (ObjectUtil.isEmpty(feeAdjustImportVO.getAdjustAmt())) {
                throw new PrologException(StrUtil.format("第{}行导入数据,调整金额不为空", num));
            }
            num++;
        }
        Integer[] feeCltType = {10,20};
        for (BmsFeeAdjustImportVO feeAdjustImportVO : BmsFeeAdjustImportVOS) {
            log.info("数据处理,第{}行数据:{}", impCnt, JSON.toJSONString(feeAdjustImportVO));
            Criteria criteriaLoadingHeader = Criteria.forClass(BmsLoadingBillHeaderModel.class);
            Restriction r1 = Restrictions.eq(BmsLoadingBillHeaderModel::getCargoOwnerName, feeAdjustImportVO.getCargoOwnerName());
            Restriction r2 = Restrictions.eq(BmsLoadingBillHeaderModel::getLoadingBillNo, feeAdjustImportVO.getLoadingBillNo());
            Restriction r3 = Restrictions.eq(BmsLoadingBillHeaderModel::getEnterpriseId, user.getEnterpriseId());
            Restriction r4 = ObjectUtil.isEmpty(feeAdjustImportVO.getSettlementDepartment()) ? null : Restrictions.eq(BmsLoadingBillHeaderModel::getSettlementDepartment, feeAdjustImportVO.getSettlementDepartment());
            Restriction r5 = ObjectUtil.isEmpty(feeAdjustImportVO.getDriverName()) ? null : Restrictions.eq(BmsLoadingBillHeaderModel::getDriverName, feeAdjustImportVO.getDriverName());
            Restriction r6 = ObjectUtil.isEmpty(feeAdjustImportVO.getVehiclePlateNumber()) ? null : Restrictions.eq(BmsLoadingBillHeaderModel::getVehiclePlateNumber, feeAdjustImportVO.getVehiclePlateNumber());
            Restriction r7 = Restrictions.in(BmsLoadingBillHeaderModel::getFeeCltType, feeCltType);
            criteriaLoadingHeader.setRestriction(Restrictions.and(r1, r2, r3, r4, r5, r6,r7));
            List<BmsLoadingBillHeaderModel> loadingBillHeaderModels = loadingBillHeadMapper.findByCriteria(criteriaLoadingHeader);
            if (ObjectUtil.isEmpty(loadingBillHeaderModels)) {
                //log.info("第{}行数据没有匹配到派车单,费用不能调整", impCnt);
                throw new PrologException(StrUtil.format("第{}行数据没有匹配到派车单,费用不能调整", impCnt));
            }
            BigDecimal adjustAmt = new BigDecimal(feeAdjustImportVO.getAdjustAmt());
            for (BmsLoadingBillHeaderModel billHeaderModel:loadingBillHeaderModels) {
                Criteria criteriaFeeHeader = Criteria.forClass(BmsBillIncomeFeeHeaderModel.class);
                r1 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getBillId, billHeaderModel.getId());
                r2 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getBillNo, billHeaderModel.getLoadingBillNo());
                r3 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getCostStatus, 1);
                r4 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getCheckStatus, 0);
                r5 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getBillType, 20);
                criteriaFeeHeader.setRestriction(Restrictions.and(r1, r2, r3,r4,r5));
                List<BmsBillIncomeFeeHeaderModel> feeHeaderModels = incomeFeeHeaderMapper.findByCriteria(criteriaFeeHeader);
                if (ObjectUtil.isEmpty(feeHeaderModels)) {
                    throw new PrologException(StrUtil.format("第{}行数据的派车单{}没有计费正常,且是未结算的收入费用,费用不能调整", impCnt,billHeaderModel.getLoadingBillNo()));
                }
                // 修正费用主表
                BmsBillIncomeFeeHeaderModel adjustFeeHeader = feeHeaderModels.get(0);
                // 增加费用明细
                addFeeDetail(adjustFeeHeader,feeAdjustImportVO);

                List<BmsBillIncomeFeeDetailModel> detailModelList = findDetailModel(adjustFeeHeader);
                if (CollectionUtil.isNotEmpty(detailModelList)) {
                    adjustFeeHeader.setContractIncomeAmount(detailModelList.stream().filter(bmsBillIncomeFeeDetailModel -> bmsBillIncomeFeeDetailModel.getBillingSource() == 1).map(BmsBillIncomeFeeDetailModel::getTaxAmt).reduce(BigDecimal.ZERO, NumberUtil::add));
                    adjustFeeHeader.setIncomeAmount(detailModelList.stream().map(BmsBillIncomeFeeDetailModel::getTaxAmt).reduce(BigDecimal.ZERO, NumberUtil::add));
                } else {
                    adjustFeeHeader.setContractIncomeAmount(BigDecimal.ZERO);
                    adjustFeeHeader.setIncomeAmount(BigDecimal.ZERO);
                }
                adjustFeeHeader.setUpdateperson(user.getNickname());
                adjustFeeHeader.setUpdatetime(date);
                incomeFeeHeaderMapper.update(adjustFeeHeader);

                // 日志操作
                logService.addLog(LogTypeEnum.FEE, adjustFeeHeader.getId().toString(), "导入调整费用");
                logService.addLog(LogTypeEnum.LOADING_BILL, adjustFeeHeader.getId().toString(), "导入调整费用");

                if (Integer.valueOf(10).equals(billHeaderModel.getFeeCltType())) {
                    if (ObjectUtil.isEmpty(adjustFeeHeader.getOriginalFeeId())) {
                        throw new PrologException(StrUtil.format("第{}行数据的派车单{}没有记载元收入费用信息,费用不能调整", impCnt,billHeaderModel.getLoadingBillNo()));
                    }
                    List<BmsBillIncomeFeeHeaderModel> origHeaderModelList = incomeFeeHeaderMapper.findByIds(BmsBillIncomeFeeHeaderModel.class, adjustFeeHeader.getOriginalFeeId().split(","), null);
                    if (ObjectUtil.isEmpty(origHeaderModelList)) {
                        throw new PrologException(StrUtil.format("第{}行数据的派车单{}没有元收入费用,费用不能调整", impCnt,billHeaderModel.getLoadingBillNo()));
                    }

                    BigDecimal avgAdjustAmt = NumberUtil.div(adjustAmt, origHeaderModelList.size(), costPrecision, finalRoundingMode);
                    for (int i = 0; i < origHeaderModelList.size(); i++) {
                        BmsBillIncomeFeeHeaderModel origHeaderModel = origHeaderModelList.get(i);
                        if (i == origHeaderModelList.size() - 1) {
                            feeAdjustImportVO.setAdjustAmt(NumberUtil.sub(adjustAmt, NumberUtil.mul(avgAdjustAmt, (origHeaderModelList.size() - 1))).toString());
                        }
                        feeAdjustImportVO.setAdjustAmt(avgAdjustAmt.toString());
                        addFeeDetail(origHeaderModel,feeAdjustImportVO);

                        List<BmsBillIncomeFeeDetailModel> origDetailModelList = findDetailModel(origHeaderModel);
                        if (CollectionUtil.isNotEmpty(origDetailModelList)) {
                            origHeaderModel.setContractIncomeAmount(origDetailModelList.stream().filter(bmsBillIncomeFeeDetailModel -> bmsBillIncomeFeeDetailModel.getBillingSource() == 1).map(BmsBillIncomeFeeDetailModel::getTaxAmt).reduce(BigDecimal.ZERO, NumberUtil::add));
                            origHeaderModel.setIncomeAmount(origDetailModelList.stream().map(BmsBillIncomeFeeDetailModel::getTaxAmt).reduce(BigDecimal.ZERO, NumberUtil::add));
                        } else {
                            origHeaderModel.setContractIncomeAmount(BigDecimal.ZERO);
                            origHeaderModel.setIncomeAmount(BigDecimal.ZERO);
                        }
                        origHeaderModel.setUpdateperson(user.getNickname());
                        origHeaderModel.setUpdatetime(date);
                        incomeFeeHeaderMapper.update(origHeaderModel);
                        // 日志操作
                        logService.addLog(LogTypeEnum.FEE, origHeaderModel.getId().toString(), "导入调整费用");
                        logService.addLog(LogTypeEnum.LOADING_BILL, origHeaderModel.getId().toString(), "导入调整费用");
                    }
                }
            }

            impCnt++;
        }
        return impCnt--;
    }




    @Override
    public List<BmsShipBillDetailDTO> getItem(Long id) {
        List<BmsShipBillDetailDTO> list = Lists.newArrayList();
        List<Long> shipBillIdList = getShipBillIdList(id);
        if (CollectionUtil.isNotEmpty(shipBillIdList)) {
            list = shipBillIdList.stream().flatMap(shipBillId -> shipBillService.getItem(shipBillId).stream()).collect(Collectors.toList());
        }
        return list;
    }

    @Override
    public List<BmsShipBillPackageDTO> getPackage(Long id) {
        List<BmsShipBillPackageDTO> list = Lists.newArrayList();
        List<Long> shipBillIdList = getShipBillIdList(id);
        if (CollectionUtil.isNotEmpty(shipBillIdList)) {
            list = shipBillIdList.stream().flatMap(shipBillId -> shipBillService.getPackage(shipBillId).stream()).collect(Collectors.toList());
        }
        return list;
    }

    private BmsBillIncomeFeeDetailModel addFeeDetail(BmsBillIncomeFeeHeaderModel feeHeaderModel, BmsFeeAdjustImportVO feeAdjustImportVO) {
        String expenseNo = mainDataProxy.getCodeNumberByCode(BmsConstant.SHIP_BILL_EXPENSE_NO);
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        BmsBillIncomeFeeDetailModel detailModel = new BmsBillIncomeFeeDetailModel();
        detailModel.setBillNo(feeHeaderModel.getBillNo());
        detailModel.setBillId(feeHeaderModel.getBillId());
        detailModel.setExpenseCode("收入调整额");
        detailModel.setExpenseName("收入调整额");
        detailModel.setExpenseType(1);
        detailModel.setExpenseTypeName("收入");
        //detailModel.setExpenseAccountCode(detailAddVO.getExpenseAccountCode());
        //detailModel.setExpenseAccountName(detailAddVO.getExpenseAccountName());
        BigDecimal feeAmt = new BigDecimal(feeAdjustImportVO.getAdjustAmt());
        detailModel.setAmount(feeAmt);
        detailModel.setTaxPoint(BigDecimal.ZERO.toString());
        detailModel.setTaxAmt(feeAmt);
        detailModel.setIsPreTax(0);
        detailModel.setNoTaxAmt(feeAmt);
        detailModel.setTax(BigDecimal.ZERO);
        detailModel.setIsShare(BigDecimal.ZERO.toString());
        detailModel.setMemo(feeAdjustImportVO.getDemo());
        detailModel.setExpenseNo(expenseNo);
        detailModel.setExpenseStatus(0);
        detailModel.setCheckStatus(BmsConstant.CHECK_STATUS_0);
        detailModel.setBillingSource(2);
        detailModel.setBillingStatus(1);
        detailModel.setBillingDate(DateUtil.date());
//        detailModel.setBillingContract();
//        detailModel.setBillingPrice();
//        detailModel.setBillingType();
//        detailModel.setBillingFailReason();
        detailModel.setCreateperson(user.getNickname());
        detailModel.setCreatetime(DateUtil.date());
        detailModel.setUpdateperson(user.getNickname());
        detailModel.setUpdatetime(DateUtil.date());
        detailModel.setEnterpriseId(user.getEnterpriseId());
        detailModel.setEnterpriseName(user.getEnterpriseName());
        incomeFeeDetailMapper.save(detailModel);
        return detailModel;
    }

    /**
     * findDetailModel
     *
     * @param headerModel
     * @return
     */
    private List<BmsBillIncomeFeeDetailModel> findDetailModel(BmsBillIncomeFeeHeaderModel headerModel) {
        Criteria criteria = Criteria.forClass(BmsBillIncomeFeeDetailModel.class);
        Restriction r1 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getBillId, headerModel.getBillId());
        Restriction r2 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getBillNo, headerModel.getBillNo());
        Restriction r3 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getEnterpriseId, headerModel.getEnterpriseId());
        criteria.setRestriction(Restrictions.and(r1, r2, r3));
        return incomeFeeDetailMapper.findByCriteria(criteria);
    }

    /**
     * getDic
     *
     * @return
     */
    private List<SysRefdatadModel> getShipBillDic() {
        return convertorUtil.getDictionary(new String[]{
                BmsConstant.SHIPBILL_STATUS, // 运单状态
                BmsConstant.SHIPPER_TYPE, // 运输状态
                BmsConstant.ABNORMAL_STATUS, // 异常状态
                BmsConstant.ORDER_TYPE, // 订单类型
                BmsConstant.CONSIGNEE_TYPE, // 收货方类型
                BmsConstant.ORDER_BUSINESS_TYPE, // 订单业务类型
                BmsConstant.SETTLEMENT_STATUS, // 核算状态
                BmsConstant.SOURCE, // 来源
                BmsConstant.COST_STATUS, // 计费状态
                BmsConstant.SYNCHRONOUS_STATUS, // 同步状态
                BmsConstant.TEMPERATURE_REQUIREMENT,// 温度要求
                BmsConstant.LINE_CARRIER_TYPE,// 承运方类型
                BmsConstant.DELIVERY_METHOD_TYPE,// 配送方式
                BmsConstant.TRANSPORT_TYPE,// 运输模式
                // 费用计算类型
                BmsConstant.FEE_CLT_TYPE,
                BmsConstant.CHECK_STATUS
        });
    }

    /**
     * getDic
     *
     * @return
     */
    private List<SysRefdatadModel> getLoadingDic() {
        return convertorUtil.getDictionary(new String[]{
                // 核算状态
                BmsConstant.SETTLEMENT_STATUS,
                // 计费状态
                BmsConstant.COST_STATUS,
                // 同步状态
                BmsConstant.SYNCHRONOUS_STATUS,
                // 承运方类型
                BmsConstant.LINE_CARRIER_TYPE,
                // 车辆类别
                BmsConstant.VEHICLE_TYPE_CATEGORY,
                // 费用计算类型
                BmsConstant.FEE_CLT_TYPE,
                // 来源
                BmsConstant.SOURCE,
                BmsConstant.LOADING_BILL_STATUS,
                BmsConstant.CHECK_STATUS
        });
    }

    /**
     * getShipBillIdList
     *
     * @param id
     * @return
     */
    private List<Long> getShipBillIdList(Long id) {
        List<Long> shipBillIdList = Lists.newArrayList();
        BmsBillIncomeFeeHeaderModel headerModel = incomeFeeHeaderMapper.findById(id, BmsBillIncomeFeeHeaderModel.class);
        if (headerModel.getBillType() == 10) {
            shipBillIdList.add(headerModel.getBillId());
        } else {
            Criteria criteria = Criteria.forClass(BmsShipBillHeaderModel.class);
            Restriction r1 = Restrictions.eq(BmsShipBillHeaderModel::getLoadingId, headerModel.getBillId());
            Restriction r2 = Restrictions.eq(BmsShipBillHeaderModel::getEnterpriseId, headerModel.getEnterpriseId());
            criteria.setRestriction(Restrictions.and(r1, r2));
            List<BmsShipBillHeaderModel> modelList = shipBillHeadMapper.findByCriteria(criteria);
            if (CollectionUtil.isNotEmpty(modelList)) {
                shipBillIdList = modelList.stream().map(BmsShipBillHeaderModel::getId).collect(Collectors.toList());
            }
        }
        return shipBillIdList;
    }
}
