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 com.google.common.collect.Lists;
import com.prolog.common.util.ToolKits;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.pojo.Page;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Order;
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.framework.entity.UserEntity;
import com.prolog.product.core.framework.util.PlgFxUsrUtils;
import com.prolog.rdc.tms.constant.BmsConstant;
import com.prolog.rdc.tms.constant.enums.LogTypeEnum;
import com.prolog.rdc.tms.dao.mapper.*;
import com.prolog.rdc.tms.model.dto.*;
import com.prolog.rdc.tms.model.dto.shipbill.BmsLogOperationDTO;
import com.prolog.rdc.tms.model.entity.*;
import com.prolog.rdc.tms.model.vo.*;
import com.prolog.rdc.tms.service.ArCloseAccountService;
import com.prolog.rdc.tms.service.BmsBillLogService;
import com.prolog.rdc.tms.util.ConvertorUtil;
import org.apache.ibatis.plugin.PluginException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

@Service
public class ArCloseAccountServiceImpl implements ArCloseAccountService {

    @Autowired
    private BmsIncomeSettlementMapper settlementMapper;
    @Autowired
    private BmsBillIncomeFeeDetailMapper feeDetailMapper;

    @Autowired
    private LoadingBillHeadMapper loadingBillHeadMapper;

    @Autowired
    private BmsBillIncomeFeeHeaderMapper feeHeaderMapper;
    @Autowired
    private BmsIncomeSettlementDetailMapper settlementDetailMapper;
    @Autowired
    private ConvertorUtil convertorUtil;

    @Autowired
    private BmsBillLogService logService;

    @Override
    public Page<ArSettlementOrderDTO> findList(ArSettlementQueryVO vo) throws ParseException {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        if (!user.getUserType().equals(BmsConstant.USER_TYPE_ZY)) {
            throw new PluginException("仅支持自有账号查询");
        }
        List<ArSettlementOrderDTO> dtos = Lists.newArrayList();
        Restriction r8;
        Restriction r11 = null;
        Criteria criteria = Criteria.forClass(BmsIncomeSettlementModel.class);
        Restriction r1 = ObjectUtil.isEmpty(vo.getSettlementNo()) ? null : Restrictions.like(BmsIncomeSettlementModel::getSettlementNo, "%" + vo.getSettlementNo() + "%");
        Restriction r2 = ObjectUtil.isEmpty(vo.getSettlementName()) ? null : Restrictions.like(BmsIncomeSettlementModel::getSettlementName, "%" + vo.getSettlementName() + "%");
        Restriction r3 = ObjectUtil.isEmpty(vo.getSettlementDepartment()) ? null : Restrictions.like(BmsIncomeSettlementModel::getSettlementDepartment, "%" + vo.getSettlementDepartment() + "%");
        Restriction r4 = ObjectUtil.isEmpty(vo.getSettlementCompany()) ? null : Restrictions.like(BmsIncomeSettlementModel::getSettlementCompany, "%" + vo.getSettlementCompany() + "%");
        Restriction r5 = ObjectUtil.isEmpty(vo.getStatus()) ? null : Restrictions.eq(BmsIncomeSettlementModel::getStatus, vo.getStatus());
        Restriction r6 = null;
        if (ObjectUtil.isNotEmpty(vo.getCreateStartTime()) && ObjectUtil.isNotEmpty(vo.getCreateEndTime())) {
            r6 = Restrictions.between("createtime", vo.getCreateStartTime() + " 00:00:00", vo.getCreateEndTime() + " 23:59:59");
        }
        // 大于
        if (ObjectUtil.isNotEmpty(vo.getCreateStartTime()) && ObjectUtil.isEmpty(vo.getCreateEndTime())) {
            r6 = Restrictions.gt("createtime", vo.getCreateStartTime() + " 00:00:00");
        }
        // 小于
        if (ObjectUtil.isEmpty(vo.getCreateStartTime()) && ObjectUtil.isNotEmpty(vo.getCreateEndTime())) {
            r6 = Restrictions.le("createtime", vo.getCreateEndTime() + " 23:59:59");
        }
        Restriction r7 = null;
        Restriction r13 = null;
        if (ObjectUtil.isNotEmpty(vo.getUpdateStartTime()) && ObjectUtil.isNotEmpty(vo.getUpdateEndTime())) {
            r7 = Restrictions.between("updatetime", vo.getUpdateStartTime() + " 00:00:00", vo.getUpdateEndTime() + " 23:59:59");
        }
        // 大于
        if (ObjectUtil.isNotEmpty(vo.getUpdateStartTime()) && ObjectUtil.isEmpty(vo.getUpdateEndTime())) {
            r7 = Restrictions.gt("updatetime", vo.getUpdateStartTime() + " 00:00:00");
        }
        // 小于
        if (ObjectUtil.isEmpty(vo.getUpdateStartTime()) && ObjectUtil.isNotEmpty(vo.getUpdateEndTime())) {
            r7 = Restrictions.le("updatetime", vo.getUpdateEndTime() + " 23:59:59");
        }
        if (user.getOwnedAllDataAuthFlag().equals(BmsConstant.USER_DEPARTMENT_AUTH_Y)) {
            r8 = Restrictions.in("settlementDepartmentId", user.getDepts().toArray());
        } else {
            throw new PluginException("仅支持部门权限账号查询");
        }
        r11 = Restrictions.eq(BmsIncomeSettlementModel::getCargoOwnerName, vo.getCargoOwnerName());
        Restriction r9 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
        Restriction r12 = Restrictions.ne(BmsIncomeSettlementModel::getStatus, 99);
        criteria.setRestriction(Restrictions.and(r1, r2, r3, r4, r5, r6, r7, r8, r9, r11, r13, r12));
        criteria.setOrder(Order.newInstance().desc("updatetime").desc("createtime"));
        List<SysRefdatadModel> dicData = convertorUtil.getDictionary(new String[]{
                BmsConstant.CLOSE_ACCOUNT_STATUS, // 结算状态
                BmsConstant.SETTLEMENT_CYCLE // 结算周期
        });
        PageUtils.startPage(vo.getPageNum(), vo.getPageSize());
        List<BmsIncomeSettlementModel> list = settlementMapper.findByCriteria(criteria);
        for (BmsIncomeSettlementModel bmsShipbillSettlementModel : list) {
            ArSettlementOrderDTO settlementOrderDTO = new ArSettlementOrderDTO();
            BeanUtil.copyProperties(bmsShipbillSettlementModel, settlementOrderDTO);
            settlementOrderDTO.setStatusName(ConvertorUtil.getName(dicData, BmsConstant.CLOSE_ACCOUNT_STATUS, String.valueOf(bmsShipbillSettlementModel.getStatus())));
            settlementOrderDTO.setSettlementCycleName(ConvertorUtil.getName(dicData, BmsConstant.SETTLEMENT_CYCLE, String.valueOf(bmsShipbillSettlementModel.getSettlementCycle())));
            settlementOrderDTO.setTax(bmsShipbillSettlementModel.getTax());

            Criteria sdcriteria = Criteria.forClass(BmsIncomeSettlementDetailModel.class);
            r6 = Restrictions.eq(BmsIncomeSettlementDetailModel::getSettlementId, bmsShipbillSettlementModel.getId());
            r7 = Restrictions.eq(BmsIncomeSettlementDetailModel::getEnterpriseId, user.getEnterpriseId());
            sdcriteria.setRestriction(Restrictions.and(r6, r7));
            List<BmsIncomeSettlementDetailModel> settlementDetails = settlementDetailMapper.findByCriteria(sdcriteria);
            settlementOrderDTO.setFeeIds(settlementDetails.stream().map(BmsIncomeSettlementDetailModel::getFeeId).distinct().collect(Collectors.toList()));

            dtos.add(settlementOrderDTO);
        }
        // 分页设置
        Page<ArSettlementOrderDTO> page = PageUtils.getPage(dtos);
        if (list instanceof com.github.pagehelper.Page) {
            com.github.pagehelper.Page<BmsIncomeSettlementModel> p0 = (com.github.pagehelper.Page<BmsIncomeSettlementModel>) list;
            page.setPageCount(p0.getPages());
            page.setPageNum(p0.getPageNum());
            page.setPageSize(p0.getPageSize());
            page.setTotalCount(p0.getTotal());
            page.setStartRow(p0.getStartRow());
            page.setEndRow(p0.getEndRow());
        }
        return page;
    }

    @Override
    public Page<ArCloseAccountBillDTO> findLoading(ArFeeSettlementPageVO vo) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        ToolKits.isParamNull(user, "当前用户没有操作权限");
        ToolKits.isParamNull(user.getDepts(), "当前用户没有部门权限");
        // 权限控制 仅支持自有账号
        if (!BmsConstant.USER_TYPE_ZY.equals(user.getUserType())) {
            throw new BizException("当前人员没有查询权限");
        }
        // 权限赋值
        vo.setEnterpriseId(user.getEnterpriseId());
        vo.setSettlementDepartmentTds(user.getDepts());

        // 执行查询
        PageUtils.startPage(vo.getPageNum(), vo.getPageSize());
        List<ArCloseAccountBillDTO> accountBillDTOS = loadingBillHeadMapper.pageForArSettlement(vo);
        if (CollectionUtil.isNotEmpty(accountBillDTOS)) {
            List<SysRefdatadModel> dicData = getDic();
            accountBillDTOS.forEach(dto -> {
                dto.setFeeCltTypeName(ConvertorUtil.getName(dicData, BmsConstant.FEE_CLT_TYPE, String.valueOf(dto.getFeeCltType())));
                dto.setVehicleAscriptionName(ConvertorUtil.getName(dicData, BmsConstant.VEHICLE_TYPE, String.valueOf(dto.getVehicleAscription())));
                dto.setVehicleTypeCategoryName(ConvertorUtil.getName(dicData, BmsConstant.VEHICLE_TYPE_CATEGORY, String.valueOf(dto.getVehicleTypeCategory())));
                dto.setSynchronousStatusName(ConvertorUtil.getName(dicData, BmsConstant.SYNCHRONOUS_STATUS, String.valueOf(dto.getSynchronousStatus())));
                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.setStatusName(ConvertorUtil.getName(dicData, BmsConstant.LOADING_BILL_STATUS, String.valueOf(dto.getStatus())));
                dto.setPayFeeCltTypeName(ConvertorUtil.getName(dicData, BmsConstant.FEE_CLT_TYPE, String.valueOf(dto.getPayFeeCltType())));
                dto.setBillNo(dto.getLoadingBillNo());

                Criteria feeCriteria = Criteria.forClass(BmsBillIncomeFeeDetailModel.class);
                Restriction r8 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getBillNo, dto.getLoadingBillNo());
                Restriction r9 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getBillId, dto.getBillId());
                Restriction r10 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getEnterpriseId, user.getEnterpriseId());
                feeCriteria.setRestriction(Restrictions.and(r8, r9, r10));
                List<BmsBillIncomeFeeDetailModel> feeDetailsByLoading = feeDetailMapper.findByCriteria(feeCriteria);
                if (ObjectUtil.isNotEmpty(feeDetailsByLoading)) {
                    dto.setTaxAmt(feeDetailsByLoading.stream().filter(fee -> ObjectUtil.isNotEmpty(fee.getTaxAmt())).map(BmsBillIncomeFeeDetailModel::getTaxAmt).reduce(BigDecimal.ZERO, NumberUtil::add));
                    dto.setNoTaxAmt(feeDetailsByLoading.stream().filter(fee -> ObjectUtil.isNotEmpty(fee.getNoTaxAmt())).map(BmsBillIncomeFeeDetailModel::getNoTaxAmt).reduce(BigDecimal.ZERO, NumberUtil::add));
                    dto.setTax(feeDetailsByLoading.stream().filter(fee -> ObjectUtil.isNotEmpty(fee.getTax())).map(BmsBillIncomeFeeDetailModel::getTax).reduce(BigDecimal.ZERO, NumberUtil::add));
                } else {
                    dto.setTaxAmt(BigDecimal.ZERO);
                    dto.setNoTaxAmt(BigDecimal.ZERO);
                    dto.setTax(BigDecimal.ZERO);
                }
            });
        }

        // 分页设置
        Page<ArCloseAccountBillDTO> page = PageUtils.getPage(accountBillDTOS);
        return page;
    }

    /**
     * 派车单翻译数据字典
     */
    private List<SysRefdatadModel> getDic() {
        return convertorUtil.getDictionary(new String[]{
                // 核算状态
                BmsConstant.SETTLEMENT_STATUS,
                // 计费状态
                BmsConstant.COST_STATUS,
                // 同步状态
                BmsConstant.SYNCHRONOUS_STATUS,
                // 车辆类别
                BmsConstant.VEHICLE_TYPE_CATEGORY,
                // 车辆类型
                BmsConstant.VEHICLE_TYPE,
                // 费用计算类型
                BmsConstant.FEE_CLT_TYPE,
                // 装车单状态
                BmsConstant.LOADING_BILL_STATUS});
    }

    @Override
    public ArSettlementOrderDetailDTO detail(Long id) {
        if (ObjectUtil.isEmpty(id)) {
            throw new PluginException("查询条件不能为空");
        }
        BmsIncomeSettlementModel settlementModel = settlementMapper.findById(id, BmsIncomeSettlementModel.class);
        if (ObjectUtil.isEmpty(settlementModel)) {
            throw new PluginException("查询结算费用信息为空");
        }
        List<SysRefdatadModel> dicData = convertorUtil.getDictionary(new String[]{
                BmsConstant.SETTLEMENT_CYCLE, // 结算周期
                BmsConstant.CLOSE_ACCOUNT_STATUS, // 结算状态
        });
        ArSettlementOrderDetailDTO dto = new ArSettlementOrderDetailDTO();
        BeanUtil.copyProperties(settlementModel, dto);
        dto.setSettlementCycleName(ConvertorUtil.getName(dicData, BmsConstant.SETTLEMENT_CYCLE, String.valueOf(settlementModel.getSettlementCycle())));
        dto.setStatusName(ConvertorUtil.getName(dicData, BmsConstant.CLOSE_ACCOUNT_STATUS, String.valueOf(settlementModel.getStatus())));

        return dto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(ArSettlementOrderUpdateVO vo) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        Date date = DateUtil.date();

        if (ObjectUtil.isEmpty(vo.getLoadingVOS())) {
            throw new PluginException("结算单中,费用不能为空");
        }

        // 1.判断结算名称是否存在
        Criteria criteria = Criteria.forClass(BmsIncomeSettlementModel.class);
        Restriction r1 = Restrictions.ne(BmsIncomeSettlementModel::getSettlementName, vo.getSettlementName());
        Restriction r2 = Restrictions.eq(BmsIncomeSettlementModel::getSettlementNo, vo.getSettlementNo());
        Restriction r3 = Restrictions.eq(BmsIncomeSettlementModel::getEnterpriseId, user.getEnterpriseId());
        criteria.setRestriction(Restrictions.and(r1, r2, r3));
        List<BmsIncomeSettlementModel> models = settlementMapper.findByCriteria(criteria);
        if (ObjectUtil.isNotEmpty(models)) {
            throw new PluginException("结算名称已经存在，请不要重复添加");
        }
        Criteria dcriteria = Criteria.forClass(BmsIncomeSettlementModel.class);
        Restriction r4 = Restrictions.eq("settlementNo", vo.getSettlementNo());
        Restriction r5 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
        dcriteria.setRestriction(Restrictions.and(r4, r5));
        List<BmsIncomeSettlementModel> settlementModels = settlementMapper.findByCriteria(dcriteria);
        if (ObjectUtil.isEmpty(settlementModels)) {
            throw new PluginException("获取应收结算单信息为空");
        }
        Integer status = settlementModels.get(0).getStatus();
        if (0 != status) {
            throw new PluginException("只有草稿状态下的应收结算单才能修改");
        }
        Criteria sdCriteria = Criteria.forClass(BmsIncomeSettlementDetailModel.class);
        Restriction r6 = Restrictions.eq(BmsIncomeSettlementDetailModel::getSettlementId, vo.getSettlementId());
        Restriction r7 = Restrictions.eq(BmsIncomeSettlementDetailModel::getEnterpriseId, user.getEnterpriseId());
        sdCriteria.setRestriction(Restrictions.and(r6, r7));
        List<BmsIncomeSettlementDetailModel> sourceStlDetailModelList = settlementDetailMapper.findByCriteria(sdCriteria);
        if (ObjectUtil.isEmpty(sourceStlDetailModelList)) {
            throw new PluginException("获取应收结算单明细信息为空");
        }
        List<String> copySourceExpenseNoList = sourceStlDetailModelList.stream().map(BmsIncomeSettlementDetailModel::getExpenseNo).collect(Collectors.toList());

        List<BmsBillIncomeFeeDetailModel> newStlDetailModelList = Lists.newArrayList();
        List<String> newExpenseNoList = Lists.newArrayList();
        TreeMap<Long, String> billIdMap = new TreeMap<>();
        if (ObjectUtil.isNotEmpty(vo.getLoadingVOS())) {
            for (SettlementLoadingVO loadingVO : vo.getLoadingVOS()) {
                billIdMap.put(loadingVO.getBillId(), "billId");
                Criteria feeCriteria = Criteria.forClass(BmsBillIncomeFeeDetailModel.class);
                Restriction r8 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getBillNo, loadingVO.getBillNo());
                Restriction r9 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getBillId, loadingVO.getBillId());
                Restriction r10 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getEnterpriseId, user.getEnterpriseId());
                feeCriteria.setRestriction(Restrictions.and(r8, r9, r10));
                List<BmsBillIncomeFeeDetailModel> feeDetails = feeDetailMapper.findByCriteria(feeCriteria);
                if (ObjectUtil.isEmpty(feeDetails)) {
                    continue;
                }
                newStlDetailModelList.addAll(feeDetails);

                List<String> expenseNos = feeDetails.stream().map(BmsBillIncomeFeeDetailModel::getExpenseNo).collect(Collectors.toList());
                newExpenseNoList.addAll(expenseNos);
            }
        }

        List<BmsLoadingBillHeaderModel> loadingBillHeaderModels = loadingBillHeadMapper.findByIds(BmsLoadingBillHeaderModel.class, billIdMap.keySet().toArray(), null);

        Map<String, List<BmsLoadingBillHeaderModel>> departmentMap = loadingBillHeaderModels.stream().collect(Collectors.groupingBy(BmsLoadingBillHeaderModel::getSettlementDepartment));
        if (departmentMap.size() > 1) {
            throw new PluginException("只有相同结算部门才能一起结算");
        }
        Map<String, List<BmsLoadingBillHeaderModel>> cargoOwnerNameMap = loadingBillHeaderModels.stream().collect(Collectors.groupingBy(BmsLoadingBillHeaderModel::getCargoOwnerName));
        if (cargoOwnerNameMap.size() > 1) {
            throw new PluginException("只有相同货主才能一起结算");
        }

        // 更新源费用单信息
        List<String> sourceExpenseNoList = sourceStlDetailModelList.stream().map(BmsIncomeSettlementDetailModel::getExpenseNo).collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(newExpenseNoList)) {
            // 获取删除掉的费用单
            sourceExpenseNoList.removeAll(newExpenseNoList);
        }
        if (ObjectUtil.isNotEmpty(sourceExpenseNoList) && sourceExpenseNoList.size() > 0) {
            // 剔除的费用,更新为对账确认
            this.updateSettlement(sourceExpenseNoList, 2, user, date);
        }
        // 删除源应收结算单
        Criteria sCriteria = Criteria.forClass(BmsIncomeSettlementDetailModel.class);
        Restriction r10 = Restrictions.in(BmsIncomeSettlementDetailModel::getExpenseNo, copySourceExpenseNoList.toArray());
        Restriction r11 = Restrictions.eq(BmsIncomeSettlementDetailModel::getEnterpriseId, user.getEnterpriseId());
        sCriteria.setRestriction(Restrictions.and(r10, r11));
        settlementDetailMapper.deleteByCriteria(sCriteria);

        // 更新应收结算单信息
        BmsIncomeSettlementModel shipbillSettlementModel = settlementModels.get(0);
        BeanUtil.copyProperties(vo, shipbillSettlementModel);
        shipbillSettlementModel.setUpdatetime(DateUtil.date());
        shipbillSettlementModel.setUpdateperson(user.getNickname());
        shipbillSettlementModel.setTax(vo.getTaxAmt().subtract(vo.getNoTaxAmt()));
        shipbillSettlementModel.setSettlementCycle(vo.getSettlementCycle());
        settlementMapper.update(shipbillSettlementModel);

        // 新增应收结算单
        logService.addLog(LogTypeEnum.SETTLEMENT, shipbillSettlementModel.getId().toString(), "应收结算单盘点");
        logService.addLog(LogTypeEnum.LOADING_BILL, shipbillSettlementModel.getId().toString(), "应收结算单盘点");

        List<BmsBillIncomeFeeHeaderModel> allFeeHeaders = Lists.newArrayList();
        loadingBillHeaderModels.stream().forEach(loading -> {
            Criteria feeCriteria = Criteria.forClass(BmsBillIncomeFeeHeaderModel.class);
            Restriction r20 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getBillNo, loading.getLoadingBillNo());
            Restriction r21 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getBillId, loading.getId());
            Restriction r22 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getEnterpriseId, user.getEnterpriseId());
            feeCriteria.setRestriction(Restrictions.and(r20, r21, r22));
            List<BmsBillIncomeFeeHeaderModel> feeHeaderModels = feeHeaderMapper.findByCriteria(feeCriteria);
            if (ObjectUtil.isNotEmpty(feeHeaderModels)) {
                allFeeHeaders.addAll(feeHeaderModels);
            }
        });
        List<String> newFeeExpenseNos = Lists.newArrayList();
        for (BmsBillIncomeFeeDetailModel feeDetailModel : newStlDetailModelList) {
            BmsIncomeSettlementDetailModel bmsShipbillSettlementModel = new BmsIncomeSettlementDetailModel();
            BeanUtil.copyProperties(feeDetailModel, bmsShipbillSettlementModel);
            bmsShipbillSettlementModel.setId(null);
            bmsShipbillSettlementModel.setSettlementId(settlementModels.get(0).getId());
            bmsShipbillSettlementModel.setCreateperson(user.getNickname());
            bmsShipbillSettlementModel.setCreatetime(DateUtil.date());
            bmsShipbillSettlementModel.setUpdateperson(user.getNickname());
            bmsShipbillSettlementModel.setUpdatetime(DateUtil.date());
            bmsShipbillSettlementModel.setEnterpriseId(user.getEnterpriseId());
            bmsShipbillSettlementModel.setEnterpriseName(user.getEnterpriseName());
            bmsShipbillSettlementModel.setFeeDetailId(feeDetailModel.getId());

            List<BmsBillIncomeFeeHeaderModel> currFeeHeaders = allFeeHeaders.stream().filter(fee -> fee.getBillId().equals(feeDetailModel.getBillId()) && fee.getBillNo().equals(feeDetailModel.getBillNo())).collect(Collectors.toList());
            if (ObjectUtil.isNotEmpty(currFeeHeaders)) {
                bmsShipbillSettlementModel.setFeeId(currFeeHeaders.get(0).getId());
                bmsShipbillSettlementModel.setBillType(currFeeHeaders.get(0).getBillType());
            }
            settlementDetailMapper.save(bmsShipbillSettlementModel);
            if (!copySourceExpenseNoList.contains(bmsShipbillSettlementModel.getExpenseNo())) {
                newFeeExpenseNos.add(bmsShipbillSettlementModel.getExpenseNo());
            }
        }
        // 盘点进来的费用明细
        if (ObjectUtil.isNotEmpty(newFeeExpenseNos) && newFeeExpenseNos.size() > 0) {
            updateSettlement(newFeeExpenseNos, 3, user, date);
        }
    }

    private void updateSettlement(List<String> sourceExpenseNoList, int checkStatus, UserEntity user, Date date) {
        String logMemo = null;
        if (3 == checkStatus) {
            logMemo = "应收结算单做成";
        } else if (2 == checkStatus) {
            logMemo = "修改结算单状态为对账确认";
        } else {
            logMemo = "应收结算单审核完成";
        }
        TreeMap<Long, String> billIdMap = new TreeMap<>();
        for (String expenseNo : sourceExpenseNoList) {
            Criteria criteria = Criteria.forClass(BmsBillIncomeFeeDetailModel.class);
            Restriction r1 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getExpenseNo, expenseNo);
            Restriction r2 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getEnterpriseId, user.getEnterpriseId());
            criteria.setRestriction(Restrictions.and(r1, r2));
            List<BmsBillIncomeFeeDetailModel> feeDetailModels = feeDetailMapper.findByCriteria(criteria);
            if (ObjectUtil.isEmpty(feeDetailModels)) {
                throw new PluginException("获取费用单信息为空");
            }

            BmsBillIncomeFeeDetailModel feeDetailModel = feeDetailModels.get(0);
            feeDetailModel.setCheckStatus(checkStatus);
            feeDetailModel.setUpdatetime(DateUtil.date());
            feeDetailModel.setUpdateperson(user.getNickname());
            feeDetailMapper.update(feeDetailModel);
            billIdMap.put(feeDetailModel.getBillId(), feeDetailModel.getBillNo());

            // 新增费用单
            logService.addLog(LogTypeEnum.STATEMENT, feeDetailModel.getId().toString(), logMemo);

            if (ObjectUtil.isNotEmpty(feeDetailModel.getOriginalFeeDetailId())) {
                BmsBillIncomeFeeDetailModel origIncomeFeeDetail = feeDetailMapper.findById(feeDetailModel.getOriginalFeeDetailId(), BmsBillIncomeFeeDetailModel.class);
                if (ObjectUtil.isNotEmpty(origIncomeFeeDetail)) {
                    origIncomeFeeDetail.setUpdateperson(user.getNickname());
                    origIncomeFeeDetail.setUpdatetime(date);
                    origIncomeFeeDetail.setCheckStatus(checkStatus);
                    feeDetailMapper.update(origIncomeFeeDetail);
                    // 新增费用单日志
                    logService.addLog(LogTypeEnum.STATEMENT, origIncomeFeeDetail.getId().toString(), logMemo);
                }
            }
        }
        if (ObjectUtil.isEmpty(billIdMap)) {
            return;
        }
        for (Long billId : billIdMap.keySet()) {
            Criteria criteriaFeeHeader = Criteria.forClass(BmsBillIncomeFeeHeaderModel.class);
            Restriction r1 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getBillNo, billIdMap.get(billId));
            Restriction r2 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getBillId, billId);
            Restriction r3 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getEnterpriseId, user.getEnterpriseId());
            criteriaFeeHeader.setRestriction(Restrictions.and(r1, r2, r3));
            List<BmsBillIncomeFeeHeaderModel> feeHeaderModels = feeHeaderMapper.findByCriteria(criteriaFeeHeader);
            if (ObjectUtil.isEmpty(feeHeaderModels)) {
                throw new PluginException("获取费用单主表信息为空");
            }
            BmsBillIncomeFeeHeaderModel feeHeaderModel = feeHeaderModels.get(0);

            feeHeaderModel.setUpdateperson(user.getNickname());
            feeHeaderModel.setUpdatetime(date);
            feeHeaderModel.setCheckStatus(checkStatus);
            feeHeaderMapper.update(feeHeaderModel);
            // 新增费用单日志
            logService.addLog(LogTypeEnum.LOADING_BILL, feeHeaderModel.getId().toString(), logMemo);
            logService.addLog(LogTypeEnum.SETTLEMENT, feeHeaderModel.getId().toString(), logMemo);

            if (ObjectUtil.isNotEmpty(feeHeaderModel.getOriginalFeeId())) {
                List<BmsBillIncomeFeeHeaderModel> origIncomeFees = feeHeaderMapper.findByIds(BmsBillIncomeFeeHeaderModel.class, feeHeaderModel.getOriginalFeeId().split(","), null);
                if (ObjectUtil.isNotEmpty(origIncomeFees)) {
                    String finalLogMemo = logMemo;
                    origIncomeFees.stream().forEach(origIncomeFee -> {
                        origIncomeFee.setUpdateperson(user.getNickname());
                        origIncomeFee.setUpdatetime(date);
                        origIncomeFee.setCheckStatus(checkStatus);
                        feeHeaderMapper.update(origIncomeFee);
                        // 新增费用单日志
                        logService.addLog(LogTypeEnum.SHIP_BILL, origIncomeFee.getId().toString(), finalLogMemo);
                        logService.addLog(LogTypeEnum.SETTLEMENT, origIncomeFee.getId().toString(), finalLogMemo);
                    });
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void audit(List<Long> ids) {
        if (ObjectUtil.isEmpty(ids)) {
            throw new PluginException("查询条件不能为空");
        }
        Long[] idArr = ids.stream().toArray(Long[]::new);
        List<BmsIncomeSettlementModel> settlementModels = settlementMapper.findByIds(BmsIncomeSettlementModel.class, idArr, null);
        if (ObjectUtil.isEmpty(settlementModels)) {
            throw new PluginException("查询结算费用信息为空");
        }
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        Date date = DateUtil.date();
        for (BmsIncomeSettlementModel settlementModel : settlementModels) {
            settlementModel.setUpdateperson(user.getNickname());
            settlementModel.setUpdatetime(date);
            settlementModel.setStatus(2);
            settlementMapper.update(settlementModel);
            // 新增应收结算单日志
            logService.addLog(LogTypeEnum.SETTLEMENT, settlementModel.getId().toString(), "结算审核完成");
            logService.addLog(LogTypeEnum.LOADING_BILL, settlementModel.getId().toString(), "结算审核完成");

            // 修改费用单状态为应收结算单审核
            Criteria criteria = Criteria.forClass(BmsIncomeSettlementDetailModel.class);
            Restriction r1 = Restrictions.eq(BmsIncomeSettlementDetailModel::getSettlementId, settlementModel.getId());
            criteria.setRestriction(Restrictions.and(r1));
            List<BmsIncomeSettlementDetailModel> detailModelList = settlementDetailMapper.findByCriteria(criteria);
            if (ObjectUtil.isEmpty(detailModelList)) {
                throw new PluginException("查询结算当详情为空");
            }
            List<String> expenseNos = detailModelList.stream().map(BmsIncomeSettlementDetailModel::getExpenseNo).collect(Collectors.toList());
            updateSettlement(expenseNos, 4, user, date);
        }
    }

    @Override
    public Page<BmsIncomeFeeDetailDTO> feeList(SettlementFeeQueryVO vo) {
        if (ObjectUtil.isEmpty(vo)) {
            throw new PluginException("查询条件不能为空");
        }
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        PageUtils.startPage(vo.getPageNum(), vo.getPageSize());
        vo.setEnterpriseId(user.getEnterpriseId());
        List<BmsIncomeFeeDetailDTO> feeList = settlementDetailMapper.queryArCloseAccountFeeList(vo);

        for (BmsIncomeFeeDetailDTO dto : feeList) {
            dto.setExpenseTypeName("收入");
            dto.setExpenseType(1);
            dto.setBillingStatusName(dto.getBillingStatus() == 1 ? "计费成功" : "未计费");
            dto.setBillingSourceName(dto.getBillingSource() == 1 ? "价格表生成" : "手工录入");
        }
        // 分页设置
        Page<BmsIncomeFeeDetailDTO> page = PageUtils.getPage(feeList);
        return page;
    }

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void invalid(Long id) {
        BmsIncomeSettlementModel settlementModel = settlementMapper.findById(id, BmsIncomeSettlementModel.class);
        if (ObjectUtil.isEmpty(settlementModel)) {
            throw new PluginException("查询结算费用信息为空");
        }
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        Date date = DateUtil.date();
        settlementModel.setUpdatetime(date);
        settlementModel.setUpdateperson(user.getNickname());
        settlementModel.setStatus(99);
        settlementMapper.update(settlementModel);

        // 新增应收结算单日志
        logService.addLog(LogTypeEnum.SETTLEMENT, settlementModel.getId().toString(), "应收结算单作废");
        logService.addLog(LogTypeEnum.LOADING_BILL, settlementModel.getId().toString(), "应收结算单作废");

        // 查询结算当详情
        Criteria criteria = Criteria.forClass(BmsIncomeSettlementDetailModel.class);
        Restriction r1 = Restrictions.eq(BmsIncomeSettlementDetailModel::getSettlementId, settlementModel.getId());
        criteria.setRestriction(Restrictions.and(r1));
        List<BmsIncomeSettlementDetailModel> detailModelList = settlementDetailMapper.findByCriteria(criteria);
        if (ObjectUtil.isEmpty(detailModelList)) {
            throw new PluginException("查询应收结算单详情为空");
        }
        List<String> expenseNos = detailModelList.stream().map(BmsIncomeSettlementDetailModel::getExpenseNo).collect(Collectors.toList());
        updateSettlement(expenseNos, 2, user, date);
    }
}