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.DriverSettlementOrderUpdateVO;
import com.prolog.rdc.tms.model.vo.DriverSettlementQueryVO;
import com.prolog.rdc.tms.model.vo.SettlementFeeQueryVO;
import com.prolog.rdc.tms.model.vo.SettlementLoadingVO;
import com.prolog.rdc.tms.model.vo.settlement.driver.DriverFeeSettlementPageVO;
import com.prolog.rdc.tms.service.BmsBillLogService;
import com.prolog.rdc.tms.service.DriverCloseAccountService;
import com.prolog.rdc.tms.util.ConvertorUtil;
import org.apache.ibatis.plugin.PluginException;
import org.springframework.beans.BeanUtils;
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 DriverCloseAccountServiceImpl implements DriverCloseAccountService {

    @Autowired
    private BmsPaySettlementMapper settlementMapper;
    @Autowired
    private BmsBillPayFeeDetailMapper feeDetailMapper;

    @Autowired
    private LoadingBillHeadMapper loadingBillHeadMapper;

    @Autowired
    private BmsBillPayFeeHeaderMapper feeHeaderMapper;
    @Autowired
    private BmsPaySettlementDetailMapper settlementDetailMapper;
    @Autowired
    private ConvertorUtil convertorUtil;

    @Autowired
    private BmsBillLogService logService;

    @Override
    public Page<DriverSettlementOrderDTO> findList(DriverSettlementQueryVO vo) throws ParseException {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        if (!user.getUserType().equals(BmsConstant.USER_TYPE_ZY)) {
            throw new PluginException("仅支持自有账号查询");
        }
        List<DriverSettlementOrderDTO> dtos = Lists.newArrayList();
        Restriction r8;
        Restriction r11 = null;
        Criteria criteria = Criteria.forClass(BmsPaySettlementModel.class);
        Restriction r1 = ObjectUtil.isEmpty(vo.getSettlementNo()) ? null : Restrictions.like(BmsPaySettlementModel::getSettlementNo, "%" + vo.getSettlementNo() + "%");
        Restriction r2 = ObjectUtil.isEmpty(vo.getSettlementName()) ? null : Restrictions.like(BmsPaySettlementModel::getSettlementName, "%" + vo.getSettlementName() + "%");
        Restriction r3 = ObjectUtil.isEmpty(vo.getSettlementDepartment()) ? null : Restrictions.like(BmsPaySettlementModel::getSettlementDepartment, "%" + vo.getSettlementDepartment() + "%");
        Restriction r4 = ObjectUtil.isEmpty(vo.getSettlementCompany()) ? null : Restrictions.like(BmsPaySettlementModel::getSettlementCompany, "%" + vo.getSettlementCompany() + "%");
        //vo.setStatus(0);
        Restriction r5 = ObjectUtil.isEmpty(vo.getStatus()) ? null : Restrictions.eq(BmsPaySettlementModel::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(BmsPaySettlementModel::getCarrierType, 2);
        Restriction r9 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
        Restriction r12 = Restrictions.ne("status", 99);
        Restriction r15 = Restrictions.eq(BmsPaySettlementModel::getPayFeeType, 2);
        Restriction r16 = Restrictions.eq(BmsPaySettlementModel::getCarrierName, vo.getCarrierName());
        criteria.setRestriction(Restrictions.and(r1, r2, r3, r4, r5, r6, r7, r8, r9, r11, r13, r12, r15, r16));
        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<BmsPaySettlementModel> list = settlementMapper.findByCriteria(criteria);
        for (BmsPaySettlementModel bmsShipbillSettlementModel : list) {
            DriverSettlementOrderDTO settlementOrderDTO = new DriverSettlementOrderDTO();
            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(BmsPaySettlementDetailModel.class);
            r6 = Restrictions.eq(BmsPaySettlementDetailModel::getSettlementId, bmsShipbillSettlementModel.getId());
            r7 = Restrictions.eq(BmsPaySettlementDetailModel::getEnterpriseId, user.getEnterpriseId());
            sdcriteria.setRestriction(Restrictions.and(r6, r7));
            List<BmsPaySettlementDetailModel> settlementDetails = settlementDetailMapper.findByCriteria(sdcriteria);

            settlementOrderDTO.setFeeIds(settlementDetails.stream().map(BmsPaySettlementDetailModel::getFeeId).distinct().collect(Collectors.toList()));
            dtos.add(settlementOrderDTO);
        }
        // 分页设置
        Page<DriverSettlementOrderDTO> page = PageUtils.getPage(dtos);
        if (list instanceof com.github.pagehelper.Page) {
            com.github.pagehelper.Page<BmsPaySettlementModel> p0 = (com.github.pagehelper.Page<BmsPaySettlementModel>) 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<DriverCloseAccountBillDTO> findLoading(DriverFeeSettlementPageVO 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());

        List<DriverCloseAccountBillDTO> driverCloseAccountBillDTOS = Lists.newArrayList();
        // 执行查询
        PageUtils.startPage(vo.getPageNum(), vo.getPageSize());
        List<DriverledgerBillDTO> driverledgerBillDTOs = loadingBillHeadMapper.pageForDriverSettlement(vo);
        if (CollectionUtil.isNotEmpty(driverledgerBillDTOs)) {
            List<SysRefdatadModel> dicData = getDic();
            driverledgerBillDTOs.forEach(driverledgerBillDTO -> {
                DriverCloseAccountBillDTO dto = new DriverCloseAccountBillDTO();
                BeanUtil.copyProperties(driverledgerBillDTO, dto);
                dto.setFeeCltTypeName(ConvertorUtil.getName(dicData, BmsConstant.FEE_CLT_TYPE, String.valueOf(driverledgerBillDTO.getFeeCltType())));
                dto.setVehicleAscriptionName(ConvertorUtil.getName(dicData, BmsConstant.VEHICLE_TYPE, String.valueOf(driverledgerBillDTO.getVehicleAscription())));
                dto.setVehicleTypeCategoryName(ConvertorUtil.getName(dicData, BmsConstant.VEHICLE_TYPE_CATEGORY, String.valueOf(driverledgerBillDTO.getVehicleTypeCategory())));
                dto.setSynchronousStatusName(ConvertorUtil.getName(dicData, BmsConstant.SYNCHRONOUS_STATUS, String.valueOf(driverledgerBillDTO.getSynchronousStatus())));
                dto.setCostStatusName(ConvertorUtil.getName(dicData, BmsConstant.COST_STATUS, String.valueOf(driverledgerBillDTO.getCostStatus())));
                dto.setSettlementStatusName(ConvertorUtil.getName(dicData, BmsConstant.SETTLEMENT_STATUS, String.valueOf(driverledgerBillDTO.getSettlementStatus())));
                dto.setStatusName(ConvertorUtil.getName(dicData, BmsConstant.LOADING_BILL_STATUS, String.valueOf(driverledgerBillDTO.getStatus())));
                dto.setPayFeeCltTypeName(ConvertorUtil.getName(dicData, BmsConstant.FEE_CLT_TYPE, String.valueOf(driverledgerBillDTO.getPayFeeCltType())));
                dto.setBillNo(driverledgerBillDTO.getLoadingBillNo());

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

        // 分页设置
        Page<DriverCloseAccountBillDTO> page = PageUtils.getPage(driverCloseAccountBillDTOS);
        if (driverledgerBillDTOs instanceof com.github.pagehelper.Page) {
            com.github.pagehelper.Page<DriverledgerBillDTO> p0 = (com.github.pagehelper.Page<DriverledgerBillDTO>) driverledgerBillDTOs;
            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;
    }

    /**
     * 派车单翻译数据字典
     */
    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 DriverSettlementOrderDetailDTO detail(Long id) {
        if (ObjectUtil.isEmpty(id)) {
            throw new PluginException("查询条件不能为空");
        }
        BmsPaySettlementModel settlementModel = settlementMapper.findById(id, BmsPaySettlementModel.class);
        if (ObjectUtil.isEmpty(settlementModel)) {
            throw new PluginException("查询结算费用信息为空");
        }
        List<SysRefdatadModel> dicData = convertorUtil.getDictionary(new String[]{
                BmsConstant.SETTLEMENT_CYCLE, // 结算周期
                BmsConstant.CLOSE_ACCOUNT_STATUS, // 结算状态
        });
        DriverSettlementOrderDetailDTO dto = new DriverSettlementOrderDetailDTO();
        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(DriverSettlementOrderUpdateVO vo) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        if (ObjectUtil.isEmpty(vo.getLoadingVOS())) {
            throw new PluginException("结算单中,费用不能为空");
        }
        // 1.判断结算名称是否存在
        Criteria criteria = Criteria.forClass(BmsPaySettlementModel.class);
        Restriction r1 = Restrictions.ne(BmsPaySettlementModel::getSettlementName, vo.getSettlementName());
        Restriction r2 = Restrictions.eq(BmsPaySettlementModel::getSettlementNo, vo.getSettlementNo());
        Restriction r3 = Restrictions.eq(BmsPaySettlementModel::getEnterpriseId, user.getEnterpriseId());
        criteria.setRestriction(Restrictions.and(r1, r2, r3));
        List<BmsPaySettlementModel> models = settlementMapper.findByCriteria(criteria);
        if (ObjectUtil.isNotEmpty(models)) {
            throw new PluginException("结算名称已经存在，请不要重复添加");
        }
        Criteria dcriteria = Criteria.forClass(BmsPaySettlementModel.class);
        Restriction r4 = Restrictions.eq("settlementNo", vo.getSettlementNo());
        Restriction r5 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
        dcriteria.setRestriction(Restrictions.and(r4, r5));
        List<BmsPaySettlementModel> 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(BmsPaySettlementDetailModel.class);
        Restriction r6 = Restrictions.eq(BmsPaySettlementDetailModel::getSettlementId, vo.getSettlementId());
        Restriction r7 = Restrictions.eq(BmsPaySettlementDetailModel::getEnterpriseId, user.getEnterpriseId());
        sdcriteria.setRestriction(Restrictions.and(r6, r7));
        List<BmsPaySettlementDetailModel> sourceStlDetailModelList = settlementDetailMapper.findByCriteria(sdcriteria);
        if (ObjectUtil.isEmpty(sourceStlDetailModelList)) {
            throw new PluginException("获取结算单明细信息为空");
        }
        List<String> copySourceExpenseNoList = sourceStlDetailModelList.stream().map(BmsPaySettlementDetailModel::getExpenseNo).collect(Collectors.toList());

        List<BmsBillPayFeeDetailModel> 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(BmsBillPayFeeDetailModel.class);
                Restriction r8 = Restrictions.eq(BmsBillPayFeeDetailModel::getBillNo, loadingVO.getBillNo());
                Restriction r9 = Restrictions.eq(BmsBillPayFeeDetailModel::getBillId, loadingVO.getBillId());
                Restriction r10 = Restrictions.eq(BmsBillPayFeeDetailModel::getEnterpriseId, user.getEnterpriseId());
                feeCriteria.setRestriction(Restrictions.and(r8, r9, r10));
                List<BmsBillPayFeeDetailModel> feeDetails = feeDetailMapper.findByCriteria(feeCriteria);
                if (ObjectUtil.isEmpty(feeDetails)) {
                    continue;
                }
                newStlDetailModelList.addAll(feeDetails);

                List<String> expenseNos = feeDetails.stream().map(BmsBillPayFeeDetailModel::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<Integer, List<BmsLoadingBillHeaderModel>> carrierTypeMap = loadingBillHeaderModels.stream().collect(Collectors.groupingBy(BmsLoadingBillHeaderModel::getCarrierType));
        if (carrierTypeMap.size() > 1) {
            throw new PluginException("只有相同承运商类型才能一起结算");
        }
        Map<String, List<BmsLoadingBillHeaderModel>> driverNameMap = loadingBillHeaderModels.stream().collect(Collectors.groupingBy(BmsLoadingBillHeaderModel::getDriverName));
        if (driverNameMap.size() > 1) {
            throw new PluginException("只有相同司机姓名才能一起结算");
        }
        Map<String, List<BmsLoadingBillHeaderModel>> driverPhoneNumberMap = loadingBillHeaderModels.stream().collect(Collectors.groupingBy(BmsLoadingBillHeaderModel::getDriverPhoneNumber));
        if (driverPhoneNumberMap.size() > 1) {
            throw new PluginException("只有相同司机手机号才能一起结算");
        }
        Map<String, List<BmsLoadingBillHeaderModel>> vehiclePlateNumberMap = loadingBillHeaderModels.stream().collect(Collectors.groupingBy(BmsLoadingBillHeaderModel::getVehiclePlateNumber));
        if (vehiclePlateNumberMap.size() > 1) {
            throw new PluginException("只有相同车牌号才能一起结算");
        }
        Date date = DateUtil.date();
        // 更新源费用单信息
        List<String> sourceExpenseNoList = sourceStlDetailModelList.stream().map(BmsPaySettlementDetailModel::getExpenseNo).collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(newExpenseNoList)) {
            // 获取删除掉的费用单
            sourceExpenseNoList.removeAll(newExpenseNoList);
        }
        if (ObjectUtil.isNotEmpty(sourceExpenseNoList) && sourceExpenseNoList.size() > 0) {
            // 剔除的费用,更新为对账提交
            this.updateSettlement(sourceExpenseNoList,0, user,date);
        }

        // 删除源结算单
        Criteria sCriteria = Criteria.forClass(BmsPaySettlementDetailModel.class);
        Restriction r10 = Restrictions.in(BmsPaySettlementDetailModel::getExpenseNo, copySourceExpenseNoList.toArray());
        Restriction r11 = Restrictions.eq(BmsPaySettlementDetailModel::getEnterpriseId, user.getEnterpriseId());
        sCriteria.setRestriction(Restrictions.and(r10, r11));
        settlementDetailMapper.deleteByCriteria(sCriteria);

        // 更新结算单信息
        BmsPaySettlementModel shipbillSettlementModel = settlementModels.get(0);
        BeanUtils.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.PAY_SETTLEMENT, shipbillSettlementModel.getId().toString(), "司机结算单盘点修改");
        logService.addLog(LogTypeEnum.LOADING_BILL, shipbillSettlementModel.getId().toString(), "司机结算单盘点修改");

        List<BmsBillPayFeeHeaderModel> allFeeHeaders = Lists.newArrayList();
        loadingBillHeaderModels.stream().forEach(loading -> {
            Criteria feeCriteria = Criteria.forClass(BmsBillPayFeeHeaderModel.class);
            Restriction r20 = Restrictions.eq(BmsBillPayFeeHeaderModel::getBillNo, loading.getLoadingBillNo());
            Restriction r21 = Restrictions.eq(BmsBillPayFeeHeaderModel::getBillId, loading.getId());
            Restriction r22 = Restrictions.eq(BmsBillPayFeeHeaderModel::getEnterpriseId, user.getEnterpriseId());
            feeCriteria.setRestriction(Restrictions.and(r20, r21, r22));
            List<BmsBillPayFeeHeaderModel> feeHeaderModels = feeHeaderMapper.findByCriteria(feeCriteria);
            if (ObjectUtil.isNotEmpty(feeHeaderModels)) {
                allFeeHeaders.addAll(feeHeaderModels);
            }
        });
        List<String> newFeeExpenseNos = Lists.newArrayList();
        for (BmsBillPayFeeDetailModel billPayFeeDetailModel : newStlDetailModelList) {
            BmsPaySettlementDetailModel bmsShipbillSettlementModel = new BmsPaySettlementDetailModel();
            BeanUtil.copyProperties(billPayFeeDetailModel, 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(billPayFeeDetailModel.getId());
            List<BmsBillPayFeeHeaderModel> currFeeHeaders = allFeeHeaders.stream().filter(fee -> fee.getBillId().equals(billPayFeeDetailModel.getBillId()) && fee.getBillNo().equals(billPayFeeDetailModel.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 (0 == checkStatus){
            logMemo = "修改结算单状态为未结算";
        } else {
            logMemo = "司机结算单审核完成";
        }
        TreeMap<Long, String> billIdMap = new TreeMap<>();
        for (String expenseNo : sourceExpenseNoList) {
            Criteria criteria = Criteria.forClass(BmsBillPayFeeDetailModel.class);
            Restriction r1 = Restrictions.eq(BmsBillPayFeeDetailModel::getExpenseNo, expenseNo);
            Restriction r2 = Restrictions.eq(BmsBillPayFeeDetailModel::getEnterpriseId, user.getEnterpriseId());
            criteria.setRestriction(Restrictions.and(r1, r2));
            List<BmsBillPayFeeDetailModel> feeDetailModels = feeDetailMapper.findByCriteria(criteria);
            if (ObjectUtil.isEmpty(feeDetailModels)) {
                throw new PluginException("获取费用单信息为空");
            }
            for (BmsBillPayFeeDetailModel feeDetailModel : feeDetailModels) {
                feeDetailModel.setCheckStatus(checkStatus);
                feeDetailModel.setUpdatetime(date);
                feeDetailModel.setUpdateperson(user.getNickname());
                feeDetailMapper.update(feeDetailModel);
                // 新增费用单日志
                logService.addLog(LogTypeEnum.PAY_SETTLEMENT, feeDetailModel.getId().toString(), logMemo);

                billIdMap.put(feeDetailModel.getBillId(), feeDetailModel.getBillNo());
            }
        }
        if (ObjectUtil.isEmpty(billIdMap)) {
            return;
        }
        for (Long billId:billIdMap.keySet()) {
            Criteria criteriaFeeHeader = Criteria.forClass(BmsBillPayFeeHeaderModel.class);
            Restriction r1 = Restrictions.eq(BmsBillPayFeeHeaderModel::getBillNo, billIdMap.get(billId));
            Restriction r2 = Restrictions.eq(BmsBillPayFeeHeaderModel::getBillId, billId);
            Restriction r3 = Restrictions.eq(BmsBillPayFeeHeaderModel::getEnterpriseId, user.getEnterpriseId());
            criteriaFeeHeader.setRestriction(Restrictions.and(r1, r2,r3));
            List<BmsBillPayFeeHeaderModel> feeHeaderModels = feeHeaderMapper.findByCriteria(criteriaFeeHeader);
            if (ObjectUtil.isEmpty(feeHeaderModels)) {
                throw new PluginException("获取费用单主表信息为空");
            }
            BmsBillPayFeeHeaderModel 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.PAY_SETTLEMENT, feeHeaderModel.getId().toString(), logMemo);
        }
    }

    @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<BmsPaySettlementModel> settlementModels = settlementMapper.findByIds(BmsPaySettlementModel.class, idArr, null);
        if (ObjectUtil.isEmpty(settlementModels)) {
            throw new PluginException("查询结算费用信息为空");
        }
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        Date date = DateUtil.date();
        for (BmsPaySettlementModel settlementModel : settlementModels) {
            settlementModel.setUpdateperson(user.getNickname());
            settlementModel.setUpdatetime(date);
            settlementModel.setStatus(2);
            settlementMapper.update(settlementModel);
            // 新增结算单日志
            logService.addLog(LogTypeEnum.PAY_SETTLEMENT, settlementModel.getId().toString(), "结算审核完成");
            logService.addLog(LogTypeEnum.LOADING_BILL, settlementModel.getId().toString(), "结算审核完成");

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

    @Override
    public Page<BmsPayFeeDetailDTO> 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<BmsPayFeeDetailDTO> feeList = settlementDetailMapper.queryDriverFeeList(vo);

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

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

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

        settlementModel.setUpdatetime(DateUtil.date());
        settlementModel.setUpdateperson(user.getNickname());
        settlementModel.setStatus(99);
        settlementMapper.update(settlementModel);

        // 新增结算单
        logService.addLog(LogTypeEnum.PAY_SETTLEMENT, settlementModel.getId().toString(), "司机结算单作废");
        logService.addLog(LogTypeEnum.LOADING_BILL, settlementModel.getId().toString(), "司机结算单作废");

        // 查询结算当详情
        Long settlementId = settlementModel.getId();
        Criteria criteria = Criteria.forClass(BmsPaySettlementDetailModel.class);
        Restriction r1 = Restrictions.eq(BmsPaySettlementDetailModel::getSettlementId, settlementId);
        criteria.setRestriction(Restrictions.and(r1));
        List<BmsPaySettlementDetailModel> detailModelList = settlementDetailMapper.findByCriteria(criteria);
        if (ObjectUtil.isEmpty(detailModelList)) {
            throw new PluginException("查询结算当详情为空");
        }

        for (BmsPaySettlementDetailModel settlementDetailModel : detailModelList) {
            // 查询费用单
            BmsBillPayFeeDetailModel feeDetailModel = feeDetailMapper.findById(settlementDetailModel.getFeeDetailId(), BmsBillPayFeeDetailModel.class);
            if (ObjectUtil.isEmpty(feeDetailModel)) {
                throw new PluginException("查询费用单信息为空");
            }
            feeDetailModel.setUpdatetime(date);
            feeDetailModel.setUpdateperson(user.getNickname());
            feeDetailModel.setCheckStatus(1);
            feeDetailMapper.update(feeDetailModel);

            // 新增费用单日志
            logService.addLog(LogTypeEnum.PAY_SETTLEMENT, feeDetailModel.getId().toString(), "修改结算状态为对账提交");
        }
        List<String> expenseNos = detailModelList.stream().map(BmsPaySettlementDetailModel::getExpenseNo).collect(Collectors.toList());
        updateSettlement(expenseNos,0,user,date);
    }
}