package cn.palmte.work.service;

import cn.palmte.work.bean.*;
import cn.palmte.work.config.activiti.ActProcessKeyEnum;
import cn.palmte.work.model.*;
import cn.palmte.work.utils.DateKit;
import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.jfunc.common.utils.CollectionUtil;

import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 项目预算service
 * @author xiongshiyan at 2021/10/29 , contact me with email yanshixiong@126.com or phone 15208384257
 */
@Service
public class ProjectBudgetService {
    private static final Logger logger = LoggerFactory.getLogger(ProjectBudgetService.class);
    @Autowired
    private ProjectBudgetIncomeRepository projectBudgetIncomeRepository;
    @Autowired
    private ProjectBudgetCostRepository projectBudgetCostRepository;
    @Autowired
    private ProjectBudgetCostManageRepository projectBudgetCostManageRepository;
    @Autowired
    private ProjectBudgetIncomeDetailRepository projectBudgetIncomeDetailRepository;
    @Autowired
    private ProjectBudgetIncomeDetailTempRepository projectBudgetIncomeDetailTempRepository;
    @Autowired
    private ProjectBudgetIncomePlanDetailRepository projectBudgetIncomePlanDetailRepository;
    @Autowired
    private ProjectBudgetIncomePlanDetailTempRepository projectBudgetIncomePlanDetailTempRepository;
    @Autowired
    private ProjectBudgetCostDetailRepository projectBudgetCostDetailRepository;
    @Autowired
    private ProjectBudgetCostDetailTempRepository projectBudgetCostDetailTempRepository;
    @Autowired
    private ProjectBudgetCostProjectManageDetailRepository projectBudgetCostProjectManageDetailRepository;
    @Autowired
    private ProjectBudgetCostProjectManageDetailTempRepository projectBudgetCostProjectManageDetailTempRepository;
    @Autowired
    private ProjectBudgetPlanDetailRepository projectBudgetPlanDetailRepository;
    @Autowired
    private ProjectBudgetPlanDetailTempRepository projectBudgetPlanDetailTempRepository;
    @Autowired
    private ProjectInstanceService projectInstanceService;
    @Autowired
    private ActTaskDefService actTaskDefService;
    @Autowired
    private ProjectService projectService;
    @Autowired
    private ProjectRepository projectRepository;
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private ProcurementTypeRepository procurementTypeRepository;
    @Autowired
    private ProjectBudgetService projectBudgetService;
    @Autowired
    private ProjectExtendRepository projectExtendRepository;
    @Autowired
    private ProjectBudgetRepository projectBudgetRepository;

    @Value("#{'${fourcal.fixedprojectmanagedetails}'.split('\\|')}")
    private String[] fixedProjectManageDetails;

    public void clearBudget(Project project){
        List<ProjectBudgetIncome> incomes = projectBudgetIncomeRepository.findAllByProjectIdEquals(project.getId());
        if(CollectionUtil.isNotEmpty(incomes)){
            projectBudgetIncomeRepository.deleteInBatch(incomes);
        }

        List<ProjectBudgetCost> costs = projectBudgetCostRepository.findAllByProjectIdEquals(project.getId());
        if(CollectionUtil.isNotEmpty(costs)){
            projectBudgetCostRepository.deleteInBatch(costs);
        }

        List<ProjectBudgetCostManage> costManages = projectBudgetCostManageRepository.findAllByProjectIdEquals(project.getId());
        if(CollectionUtil.isNotEmpty(costManages)){
            projectBudgetCostManageRepository.deleteInBatch(costManages);
        }

    }

    /**
     * 【除开其他其他、公司管理费用,其他的都是从资金明细中获取
     * 此处保存起,但是不用,可以起对照作用】
     */
    public void saveBudget(Project project, BudgetBean budgetBean){
        //收入记录
        income(project, budgetBean);
        //成本记录
        cost(project, budgetBean);
        //管理记录
        costManage(project, budgetBean);
    }

    private void cost(Project project, BudgetBean budgetBean) {
        ProjectBudgetCost projectBudgetCostDevice = new ProjectBudgetCost();
        projectBudgetCostDevice.setProjectId(project.getId());
        projectBudgetCostDevice.setFee(ProjectBudgetCost.FEE_PURCHASE);
        projectBudgetCostDevice.setType(ProjectBudgetCost.TYPE_DEVICE);
        projectBudgetCostDevice.setCostTaxInclude(budgetBean.getCostPurchaseDeviceTaxInclude());
        projectBudgetCostDevice.setCostTaxExclude(budgetBean.getCostPurchaseDeviceTaxExclude());
        projectBudgetCostRepository.saveAndFlush(projectBudgetCostDevice);


        ProjectBudgetCost projectBudgetCostBuild = new ProjectBudgetCost();
        projectBudgetCostBuild.setProjectId(project.getId());
        projectBudgetCostBuild.setFee(ProjectBudgetCost.FEE_PURCHASE);
        projectBudgetCostBuild.setType(ProjectBudgetCost.TYPE_BUILDING);
        projectBudgetCostBuild.setCostTaxInclude(budgetBean.getCostPurchaseBuildTaxInclude());
        projectBudgetCostBuild.setCostTaxExclude(budgetBean.getCostPurchaseBuildTaxExclude());
        projectBudgetCostRepository.saveAndFlush(projectBudgetCostBuild);

        ProjectBudgetCost projectBudgetCostService = new ProjectBudgetCost();
        projectBudgetCostService.setProjectId(project.getId());
        projectBudgetCostService.setFee(ProjectBudgetCost.FEE_PURCHASE);
        projectBudgetCostService.setType(ProjectBudgetCost.TYPE_SERVICE);
        projectBudgetCostService.setCostTaxInclude(budgetBean.getCostPurchaseServiceTaxInclude());
        projectBudgetCostService.setCostTaxExclude(budgetBean.getCostPurchaseServiceTaxExclude());
        projectBudgetCostRepository.saveAndFlush(projectBudgetCostService);

        ProjectBudgetCost projectBudgetCostOther = new ProjectBudgetCost();
        projectBudgetCostOther.setProjectId(project.getId());
        projectBudgetCostOther.setFee(ProjectBudgetCost.FEE_PURCHASE);
        projectBudgetCostOther.setType(ProjectBudgetCost.TYPE_OTHER);
        projectBudgetCostOther.setCostTaxInclude(budgetBean.getCostPurchaseOtherTaxInclude());
        projectBudgetCostOther.setCostTaxExclude(budgetBean.getCostPurchaseOtherTaxExclude());
        projectBudgetCostRepository.saveAndFlush(projectBudgetCostOther);

        ProjectBudgetCost projectBudgetCostProject = new ProjectBudgetCost();
        projectBudgetCostProject.setProjectId(project.getId());
        projectBudgetCostProject.setFee(ProjectBudgetCost.FEE_PROJECT_MANAGE);
        projectBudgetCostProject.setType(ProjectBudgetCost.TYPE_PROJECT_MANAGE);
        /*projectBudgetCostProject.setCostTaxInclude(budgetBean.getCostProjectManageTaxInclude());*/
        projectBudgetCostProject.setCostTaxExclude(budgetBean.getCostProjectManageTaxExclude());
        projectBudgetCostRepository.saveAndFlush(projectBudgetCostProject);

        ProjectBudgetCost projectBudgetCostOtherOther = new ProjectBudgetCost();
        projectBudgetCostOtherOther.setProjectId(project.getId());
        projectBudgetCostOtherOther.setFee(ProjectBudgetCost.FEE_OTHER);
        projectBudgetCostOtherOther.setType(ProjectBudgetCost.TYPE_OTHER_OTHER);
        projectBudgetCostOtherOther.setCostTaxInclude(budgetBean.getCostOtherOtherTaxInclude());
        projectBudgetCostOtherOther.setCostTaxExclude(budgetBean.getCostOtherOtherTaxExclude());
        projectBudgetCostRepository.saveAndFlush(projectBudgetCostOtherOther);

    }
    private void costManage(Project project, BudgetBean budgetBean) {
        ProjectBudgetCostManage projectBudgetCostZijin = new ProjectBudgetCostManage();
        projectBudgetCostZijin.setProjectId(project.getId());
        projectBudgetCostZijin.setType(ProjectBudgetCostManage.TYPE_EXPROPRIATION);
        projectBudgetCostZijin.setCostTaxExclude(budgetBean.getCostExpropriationTaxExclude());
        projectBudgetCostManageRepository.saveAndFlush(projectBudgetCostZijin);

        ProjectBudgetCostManage projectBudgetCostManage = new ProjectBudgetCostManage();
        projectBudgetCostManage.setProjectId(project.getId());
        projectBudgetCostManage.setType(ProjectBudgetCostManage.TYPE_COMPANY_MANAGE);
        projectBudgetCostManage.setCostTaxExclude(budgetBean.getCostCompanyManageTaxExclude());
        projectBudgetCostManageRepository.saveAndFlush(projectBudgetCostManage);
    }
    private void income(Project project, BudgetBean budgetBean) {
        ProjectBudgetIncome projectBudgetIncomeDevice = new ProjectBudgetIncome();
        projectBudgetIncomeDevice.setProjectId(project.getId());
        projectBudgetIncomeDevice.setType(ProjectBudgetIncome.TYPE_DEVICE);
        projectBudgetIncomeDevice.setIncomeTaxInclude(budgetBean.getIncomeDeviceTaxInclude());
        projectBudgetIncomeDevice.setIncomeTaxExclude(budgetBean.getIncomeDeviceTaxExclude());
        projectBudgetIncomeRepository.saveAndFlush(projectBudgetIncomeDevice);

        ProjectBudgetIncome projectBudgetIncomeEngineer = new ProjectBudgetIncome();
        projectBudgetIncomeEngineer.setProjectId(project.getId());
        projectBudgetIncomeEngineer.setType(ProjectBudgetIncome.TYPE_ENGINEER);
        projectBudgetIncomeEngineer.setIncomeTaxInclude(budgetBean.getIncomeEngineerTaxInclude());
        projectBudgetIncomeEngineer.setIncomeTaxExclude(budgetBean.getIncomeEngineerTaxExclude());
        projectBudgetIncomeRepository.saveAndFlush(projectBudgetIncomeEngineer);

        ProjectBudgetIncome projectBudgetIncomeService = new ProjectBudgetIncome();
        projectBudgetIncomeService.setProjectId(project.getId());
        projectBudgetIncomeService.setType(ProjectBudgetIncome.TYPE_SERVICE);
        projectBudgetIncomeService.setIncomeTaxInclude(budgetBean.getIncomeServiceTaxInclude());
        projectBudgetIncomeService.setIncomeTaxExclude(budgetBean.getIncomeServiceTaxExclude());
        projectBudgetIncomeRepository.saveAndFlush(projectBudgetIncomeService);
    }


    /**
     * 其实最好是通过明细表生成,不然可能有数据不一致的情况
     */
    public BudgetBean getBudget(Project project) {
        BudgetBean budgetBean = new BudgetBean();

        List<ProjectBudgetIncomeDetail> incomeDetails = projectBudgetIncomeDetailRepository.findAllByProjectIdEquals(project.getId());
        if(CollectionUtil.isNotEmpty(incomeDetails)){
            //设备类收入,含税和不含税
            List<ProjectBudgetIncomeDetail> collectDevice = incomeDetails.stream().filter(d -> d.getType() == ProjectBudgetIncomeDetail.TYPE_DEVICE).collect(Collectors.toList());
            budgetBean.setIncomeDeviceTaxInclude(getIncomeTotalTaxInclude(collectDevice));
            budgetBean.setIncomeDeviceTaxExclude(getIncomeTotalTaxExclude(collectDevice));
            budgetBean.setIncomeDeviceTax(budgetBean.getIncomeDeviceTaxInclude().subtract(budgetBean.getIncomeDeviceTaxExclude()));
            //工程类收入,含税和不含税
            List<ProjectBudgetIncomeDetail> collectEngineer = incomeDetails.stream().filter(d -> d.getType() == ProjectBudgetIncomeDetail.TYPE_ENGINEER).collect(Collectors.toList());
            budgetBean.setIncomeEngineerTaxInclude(getIncomeTotalTaxInclude(collectEngineer));
            budgetBean.setIncomeEngineerTaxExclude(getIncomeTotalTaxExclude(collectEngineer));
            budgetBean.setIncomeEngineerTax(budgetBean.getIncomeEngineerTaxInclude().subtract(budgetBean.getIncomeEngineerTaxExclude()));
            //服务类收入,含税和不含税
            List<ProjectBudgetIncomeDetail> collectService = incomeDetails.stream().filter(d -> d.getType() == ProjectBudgetIncomeDetail.TYPE_SERVICE).collect(Collectors.toList());
            budgetBean.setIncomeServiceTaxInclude(getIncomeTotalTaxInclude(collectService));
            budgetBean.setIncomeServiceTaxExclude(getIncomeTotalTaxExclude(collectService));
            budgetBean.setIncomeServiceTax(budgetBean.getIncomeServiceTaxInclude().subtract(budgetBean.getIncomeServiceTaxExclude()));
        }

        List<ProjectBudgetCostDetail> projectBudgetCostDetails = projectBudgetCostDetailRepository.findAllByProjectIdEquals(project.getId());
        if(CollectionUtil.isNotEmpty(projectBudgetCostDetails)){
            //采购成本-设备,含税和不含税
            List<ProjectBudgetCostDetail> collectDevice = projectBudgetCostDetails.stream().filter(d -> d.getType() == ProjectBudgetCostDetail.TYPE_DEVICE).collect(Collectors.toList());
            budgetBean.setCostPurchaseDeviceTaxInclude(getCostTotalTaxInclude(collectDevice));
            budgetBean.setCostPurchaseDeviceTaxExclude(getCostTotalTaxExclude(collectDevice));
            budgetBean.setCostPurchaseDeviceTax(budgetBean.getCostPurchaseDeviceTaxInclude().subtract(budgetBean.getCostPurchaseDeviceTaxExclude()));
            //采购成本-施工,含税和不含税
            List<ProjectBudgetCostDetail> collectBuild = projectBudgetCostDetails.stream().filter(d -> d.getType() == ProjectBudgetCostDetail.TYPE_BUILD).collect(Collectors.toList());
            budgetBean.setCostPurchaseBuildTaxInclude(getCostTotalTaxInclude(collectBuild));
            budgetBean.setCostPurchaseBuildTaxExclude(getCostTotalTaxExclude(collectBuild));
            budgetBean.setCostPurchaseBuildTax(budgetBean.getCostPurchaseBuildTaxInclude().subtract(budgetBean.getCostPurchaseBuildTaxExclude()));
            //采购成本-服务,含税和不含税
            List<ProjectBudgetCostDetail> collectService = projectBudgetCostDetails.stream().filter(d -> d.getType() == ProjectBudgetCostDetail.TYPE_SERVICE).collect(Collectors.toList());
            budgetBean.setCostPurchaseServiceTaxInclude(getCostTotalTaxInclude(collectService));
            budgetBean.setCostPurchaseServiceTaxExclude(getCostTotalTaxExclude(collectService));
            budgetBean.setCostPurchaseServiceTax(budgetBean.getCostPurchaseServiceTaxInclude().subtract(budgetBean.getCostPurchaseServiceTaxExclude()));
            //采购成本-其他,含税和不含税
            List<ProjectBudgetCostDetail> collectOther = projectBudgetCostDetails.stream().filter(d -> d.getType() == ProjectBudgetCostDetail.TYPE_OHTER).collect(Collectors.toList());
            budgetBean.setCostPurchaseOtherTaxInclude(getCostTotalTaxInclude(collectOther));
            budgetBean.setCostPurchaseOtherTaxExclude(getCostTotalTaxExclude(collectOther));
            budgetBean.setCostPurchaseOtherTax(budgetBean.getCostPurchaseOtherTaxInclude().subtract(budgetBean.getCostPurchaseOtherTaxExclude()));

            budgetBean.setCostPurchaseTotalTaxInclude(getCostTotalTaxInclude(collectDevice).add(getCostTotalTaxInclude(collectBuild)).add(getCostTotalTaxInclude(collectService)).add(getCostTotalTaxInclude(collectOther)));
            budgetBean.setCostPurchaseTotalTaxExclude(getCostTotalTaxExclude(collectDevice).add(getCostTotalTaxExclude(collectBuild)).add(getCostTotalTaxExclude(collectService)).add(getCostTotalTaxExclude(collectOther)));
        }

        //项目管理成本
        List<ProjectBudgetCostProjectManageDetail> projectManageDetails = projectBudgetCostProjectManageDetailRepository.findAllByProjectIdEquals(project.getId());
        if(CollectionUtil.isNotEmpty(projectManageDetails)){
            budgetBean.setCostProjectManageTaxExclude(getCostProjectManageTotalTaxExclude(projectManageDetails));
        }

        //其他其他成本
        List<ProjectBudgetCost> costs = projectBudgetCostRepository.findAllByProjectIdEquals(project.getId());
        if(CollectionUtil.isNotEmpty(costs)){
            ProjectBudgetCost projectBudgetCostOtherOther = costs.stream().filter(d -> d.getType() == ProjectBudgetCost.TYPE_OTHER_OTHER).collect(Collectors.toList()).get(0);
            budgetBean.setCostOtherOtherTaxInclude(projectBudgetCostOtherOther.getCostTaxInclude());
            budgetBean.setCostOtherOtherTaxExclude(projectBudgetCostOtherOther.getCostTaxExclude());
            budgetBean.setCostOtherOtherTax(budgetBean.getCostOtherOtherTaxInclude().subtract(budgetBean.getCostOtherOtherTaxExclude()));
        }


        //资金占用成本
        List<ProjectBudgetPlanDetail> budgetPlanDetails = projectBudgetPlanDetailRepository.findAllByProjectIdEquals(project.getId());
        if(CollectionUtil.isNotEmpty(budgetPlanDetails)){
            budgetBean.setCostExpropriationTaxExclude(getTotalCapitalInterest(budgetPlanDetails));
        }

        //公司管理成本
        List<ProjectBudgetCostManage> manages = projectBudgetCostManageRepository.findAllByProjectIdEquals(project.getId());
        if(CollectionUtil.isNotEmpty(manages)){
            ProjectBudgetCostManage costManageCompany = manages.stream().filter(d -> d.getType() == ProjectBudgetCostManage.TYPE_COMPANY_MANAGE).collect(Collectors.toList()).get(0);
            budgetBean.setCostCompanyManageTaxExclude(costManageCompany.getCostTaxExclude());
        }

        return budgetBean;
    }

    private BigDecimal getIncomeTotalTaxInclude(List<ProjectBudgetIncomeDetail> list){
        BigDecimal total = new BigDecimal(0);
        if(CollectionUtil.isEmpty(list)){
            return total;
        }

        for (ProjectBudgetIncomeDetail detail : list) {
            total = total.add(detail.getTotalTaxInclude());
        }

        return total;
    }
    private BigDecimal getIncomeTotalTaxExclude(List<ProjectBudgetIncomeDetail> list){
        BigDecimal total = new BigDecimal(0);
        if(CollectionUtil.isEmpty(list)){
            return total;
        }

        for (ProjectBudgetIncomeDetail detail : list) {
            total = total.add(detail.getTotalTaxExclude());
        }

        return total;
    }
    private BigDecimal getCostTotalTaxInclude(List<ProjectBudgetCostDetail> list){
        BigDecimal total = new BigDecimal(0);
        if(CollectionUtil.isEmpty(list)){
            return total;
        }

        for (ProjectBudgetCostDetail detail : list) {
            total = total.add(detail.getTotalTaxInclude());
        }

        return total;
    }
    private BigDecimal getCostTotalTaxExclude(List<ProjectBudgetCostDetail> list){
        BigDecimal total = new BigDecimal(0);
        if(CollectionUtil.isEmpty(list)){
            return total;
        }

        for (ProjectBudgetCostDetail detail : list) {
            total = total.add(detail.getTotalTaxExclude());
        }

        return total;
    }
    private BigDecimal getCostProjectManageTotalTaxExclude(List<ProjectBudgetCostProjectManageDetail> list){
        BigDecimal total = new BigDecimal(0);
        if(CollectionUtil.isEmpty(list)){
            return total;
        }

        for (ProjectBudgetCostProjectManageDetail detail : list) {
            total = total.add(detail.getTotal());
        }

        return total;
    }
    private BigDecimal getTotalCapitalInterest(List<ProjectBudgetPlanDetail> list){
        BigDecimal total = new BigDecimal(0);
        if(CollectionUtil.isEmpty(list)){
            return total;
        }

        for (ProjectBudgetPlanDetail detail : list) {
            total = total.add(detail.getCapitalInterest());
        }

        return total;
    }

    /**
     * 清空项目的收入明细
     */
    public void clearBudgetIncomeDetail(Project project){
        List<ProjectBudgetIncomeDetail> incomeDetails = projectBudgetIncomeDetailRepository.findAllByProjectIdEquals(project.getId());
        if(CollectionUtil.isNotEmpty(incomeDetails)){
            projectBudgetIncomeDetailRepository.deleteInBatch(incomeDetails);
        }
    }
    public void clearBudgetIncomeDetailTemp(Project project){
        List<ProjectBudgetIncomeDetailTemp> incomeDetails = projectBudgetIncomeDetailTempRepository.findAllByProjectIdEquals(project.getId());
        if(CollectionUtil.isNotEmpty(incomeDetails)){
            projectBudgetIncomeDetailTempRepository.deleteInBatch(incomeDetails);
        }
    }

    /**
     * 保存项目的收入明细
     */
    @Transactional(rollbackFor = RuntimeException.class)
    public void saveBudgetIncomeDetail(Project project, List<ProjectBudgetIncomeDetail> detailList){
        clearBudgetIncomeDetail(project);
        if(CollectionUtil.isNotEmpty(detailList)){
            for (ProjectBudgetIncomeDetail projectBudgetIncomeDetail : detailList) {
                projectBudgetIncomeDetail.setProjectId(project.getId());
            }
            projectBudgetIncomeDetailRepository.save(detailList);
        }
    }
    @Transactional(rollbackFor = RuntimeException.class)
    public void saveBudgetIncomeDetailTemp(Project project, List<ProjectBudgetIncomeDetailTemp> detailList){
        clearBudgetIncomeDetailTemp(project);
        if(CollectionUtil.isNotEmpty(detailList)){
            for (ProjectBudgetIncomeDetailTemp projectBudgetIncomeDetail : detailList) {
                projectBudgetIncomeDetail.setProjectId(project.getId());
            }
            projectBudgetIncomeDetailTempRepository.save(detailList);
        }

    }

    /**
     * 获取项目的收入明细
     */
    public List<ProjectBudgetIncomeDetail> getBudgetIncomeDetail(Project project){
        return projectBudgetIncomeDetailRepository.findAllByProjectIdEquals(project.getId());
    }
    /**
     * 获取项目的收入总数量
     */
    public BigDecimal getBudgetIncomeAmount(Project project){
        return projectBudgetIncomeDetailRepository.findAmountByProject(project.getId());
    }

    /**
     * 清空项目的收入计划
     */
    public void clearBudgetIncomePlanDetail(Project project){
        List<ProjectBudgetIncomePlanDetail> incomePlanDetails = projectBudgetIncomePlanDetailRepository.findAllByProjectIdEquals(project.getId());
        if(CollectionUtil.isNotEmpty(incomePlanDetails)){
            projectBudgetIncomePlanDetailRepository.deleteInBatch(incomePlanDetails);
        }
    }
    public void clearBudgetIncomePlanDetailTemp(Project project){
        List<ProjectBudgetIncomePlanDetailTemp> incomePlanDetails = projectBudgetIncomePlanDetailTempRepository.findAllByProjectIdEquals(project.getId());
        if(CollectionUtil.isNotEmpty(incomePlanDetails)){
            projectBudgetIncomePlanDetailTempRepository.deleteInBatch(incomePlanDetails);
        }
    }

    /**
     * 保存项目的收入计划
     */
    @Transactional(rollbackFor = RuntimeException.class)
    public void saveBudgetIncomePlanDetail(Project project, List<ProjectBudgetIncomePlanDetail> detailList){
        clearBudgetIncomePlanDetail(project);
        if(CollectionUtil.isNotEmpty(detailList)){
            for (ProjectBudgetIncomePlanDetail projectBudgetIncomePlanDetail : detailList) {
                projectBudgetIncomePlanDetail.setProjectId(project.getId());
            }
            projectBudgetIncomePlanDetailRepository.save(detailList);
        }
    }
    @Transactional(rollbackFor = RuntimeException.class)
    public void saveBudgetIncomePlanDetailTemp(Project project, List<ProjectBudgetIncomePlanDetailTemp> detailList){
        clearBudgetIncomePlanDetailTemp(project);
        if(CollectionUtil.isNotEmpty(detailList)){
            for (ProjectBudgetIncomePlanDetailTemp projectBudgetIncomePlanDetail : detailList) {
                projectBudgetIncomePlanDetail.setProjectId(project.getId());
            }
            projectBudgetIncomePlanDetailTempRepository.save(detailList);
        }

    }

    /**
     * 获取项目的收入计划
     */
    public List<ProjectBudgetIncomePlanDetail> getBudgetIncomePlanDetail(Project project){
        return projectBudgetIncomePlanDetailRepository.findAllByProjectIdEquals(project.getId());
    }
    /**
     * 获取项目的收入计划的收款金额
     */
    public BigDecimal getBudgetIncomePlanReceiveAmount(Project project){
        return projectBudgetIncomePlanDetailRepository.findReceiveAmountByProject(project.getId());
    }

    /**
     * 清空项目的成本明细
     */
    public void clearBudgetCostDetail(Project project){
        List<ProjectBudgetCostDetail> costDetails = projectBudgetCostDetailRepository.findAllByProjectIdEquals(project.getId());
        if(CollectionUtil.isNotEmpty(costDetails)){
            projectBudgetCostDetailRepository.deleteInBatch(costDetails);
        }
    }
    public void clearBudgetCostDetailTemp(Project project){
        List<ProjectBudgetCostDetailTemp> costDetails = projectBudgetCostDetailTempRepository.findAllByProjectIdEquals(project.getId());
        if(CollectionUtil.isNotEmpty(costDetails)){
            projectBudgetCostDetailTempRepository.deleteInBatch(costDetails);
        }
    }

    /**
     * 保存项目的成本明细
     */
    @Transactional(rollbackFor = RuntimeException.class)
    public void saveBudgetCostDetail(Project project, List<ProjectBudgetCostDetail> detailList){
        clearBudgetCostDetail(project);

        if(CollectionUtil.isNotEmpty(detailList)){
            for (ProjectBudgetCostDetail projectBudgetCostDetail : detailList) {
                projectBudgetCostDetail.setProjectId(project.getId());
            }
            projectBudgetCostDetailRepository.save(detailList);
        }
    }
    @Transactional(rollbackFor = RuntimeException.class)
    public void saveBudgetCostDetailTemp(Project project, List<ProjectBudgetCostDetailTemp> detailList){
        clearBudgetCostDetailTemp(project);

        if(CollectionUtil.isNotEmpty(detailList)){
            for (ProjectBudgetCostDetailTemp projectBudgetCostDetail : detailList) {
                projectBudgetCostDetail.setProjectId(project.getId());
            }
            projectBudgetCostDetailTempRepository.save(detailList);
        }
    }

    /**
     * 获取项目的成本明细
     */
    public List<ProjectBudgetCostDetail> getBudgetCostDetail(Project project){
        return projectBudgetCostDetailRepository.findAllByProjectIdEquals(project.getId());
    }
    /**
     * 获取项目的成本总数量
     */
    public BigDecimal getBudgetCostAmount(Project project){
        return projectBudgetCostDetailRepository.findAmountByProject(project.getId());
    }
    /**
     * 获取项目的项目管理总支出金额
     */
    public BigDecimal getBudgetCostUnderwrittenAmountTotal(Project project){
        return projectBudgetCostDetailRepository.findUnderwrittenAmountByProject(project.getId());
    }
    /**
     * 获取项目的成本总支出金额
     */
    public BigDecimal getBudgetCostPayAmountTotal(Project project){
        return projectBudgetCostDetailRepository.findPayAmountByProject(project.getId());
    }
    /**
     * 清空项目的项目管理成本明细
     */
    public void clearBudgetCostProjectManageDetail(Project project){
        List<ProjectBudgetCostProjectManageDetail> costDetails = projectBudgetCostProjectManageDetailRepository.findAllByProjectIdEquals(project.getId());
        if(CollectionUtil.isNotEmpty(costDetails)){
            projectBudgetCostProjectManageDetailRepository.deleteInBatch(costDetails);
        }
    }
    public void clearBudgetCostProjectManageDetailTemp(Project project){
        List<ProjectBudgetCostProjectManageDetailTemp> costDetails = projectBudgetCostProjectManageDetailTempRepository.findAllByProjectIdEquals(project.getId());
        if(CollectionUtil.isNotEmpty(costDetails)){
            projectBudgetCostProjectManageDetailTempRepository.deleteInBatch(costDetails);
        }
    }

    /**
     * 保存项目的项目管理成本明细
     */
    @Transactional(rollbackFor = RuntimeException.class)
    public void saveBudgetCostProjectManageDetail(Project project, List<ProjectBudgetCostProjectManageDetail> detailList){
        clearBudgetCostProjectManageDetail(project);
        if(CollectionUtil.isNotEmpty(detailList)){
            for (ProjectBudgetCostProjectManageDetail projectBudgetCostProjectManageDetail : detailList) {
                projectBudgetCostProjectManageDetail.setProjectId(project.getId());
            }
            projectBudgetCostProjectManageDetailRepository.save(detailList);
        }
    }
    @Transactional(rollbackFor = RuntimeException.class)
    public void saveBudgetCostProjectManageDetailTemp(Project project, List<ProjectBudgetCostProjectManageDetailTemp> detailList){
        clearBudgetCostProjectManageDetailTemp(project);
        if(CollectionUtil.isNotEmpty(detailList)){
            for (ProjectBudgetCostProjectManageDetailTemp projectBudgetCostProjectManageDetail : detailList) {
                projectBudgetCostProjectManageDetail.setProjectId(project.getId());
            }
            projectBudgetCostProjectManageDetailTempRepository.save(detailList);
        }
    }

    /**
     * 获取项目管理明细
     */
    public List<ProjectBudgetCostProjectManageDetail> getBudgetCostProjectManageDetail(Project project){
        List<ProjectBudgetCostProjectManageDetail> projectManageDetails = projectBudgetCostProjectManageDetailRepository.findAllByProjectIdEquals(project.getId());
        return projectManageDetails;
//        if(CollectionUtil.isNotEmpty(projectManageDetails)){
//            return projectManageDetails;
//        }else {
//            //默认必填的明细
//            return getFixedNotDeletable();
//        }
    }
    /**
     * 获取项目的项目管理总数量
     */
    public BigDecimal getBudgetCostProjectManageAmount(Project project){
        return projectBudgetCostProjectManageDetailRepository.findAmountByProject(project.getId());
    }
    /**
     * 获取项目的项目管理总支出金额
     */
    public BigDecimal getBudgetCostProjectManagePayAmount(Project project){
        return projectBudgetCostProjectManageDetailRepository.findPayAmountByProject(project.getId());
    }
    private List<ProjectBudgetCostProjectManageDetail> getFixedNotDeletable() {
        List<ProjectBudgetCostProjectManageDetail> projectManageDetails = new ArrayList<>(6);
        for (String fixedProjectManageDetail : fixedProjectManageDetails) {
            String[] split = fixedProjectManageDetail.split(",");
            ProjectBudgetCostProjectManageDetail detail = new ProjectBudgetCostProjectManageDetail();
            detail.setType(Integer.parseInt(split[0]));
            detail.setName(split[1]);
            detail.setPrice(new BigDecimal(0));
            detail.setAmount(new BigDecimal(0));
            detail.setDeletable(0);
            projectManageDetails.add(detail);
        }

        return projectManageDetails;
    }
    /**
     * 清空项目的资金计划明细
     */
    public void clearBudgetPlanDetail(Project project){
        List<ProjectBudgetPlanDetail> costDetails = projectBudgetPlanDetailRepository.findAllByProjectIdEquals(project.getId());
        if(CollectionUtil.isNotEmpty(costDetails)){
            projectBudgetPlanDetailRepository.deleteInBatch(costDetails);
        }
    }
    public void clearBudgetPlanDetailTemp(Project project){
        List<ProjectBudgetPlanDetailTemp> costDetails = projectBudgetPlanDetailTempRepository.findAllByProjectIdEquals(project.getId());
        if(CollectionUtil.isNotEmpty(costDetails)){
            projectBudgetPlanDetailTempRepository.deleteInBatch(costDetails);
        }
    }

    /**
     * 保存项目的资金计划明细
     */
    @Transactional(rollbackFor = RuntimeException.class)
    public void saveBudgetPlanDetail(Project project, List<ProjectBudgetPlanDetail> detailList){
        clearBudgetPlanDetail(project);
        if(CollectionUtil.isNotEmpty(detailList)){
            for (ProjectBudgetPlanDetail projectBudgetPlanDetail : detailList) {
                projectBudgetPlanDetail.setProjectId(project.getId());
                projectBudgetPlanDetail.setUnderwrittenTaxRate(project.getUnderwrittenTaxRate());
            }
            projectBudgetPlanDetailRepository.save(detailList);
        }
    }
    @Transactional(rollbackFor = RuntimeException.class)
    public void saveBudgetPlanDetailTemp(Project project, List<ProjectBudgetPlanDetailTemp> detailList){
        clearBudgetPlanDetailTemp(project);
        if(CollectionUtil.isNotEmpty(detailList)){
            for (ProjectBudgetPlanDetailTemp projectBudgetPlanDetail : detailList) {
                projectBudgetPlanDetail.setProjectId(project.getId());
                projectBudgetPlanDetail.setUnderwrittenTaxRate(project.getUnderwrittenTaxRate());
            }
            projectBudgetPlanDetailTempRepository.save(detailList);
        }
    }

    /**
     * 获取资金计划数据
     */
    public List<ProjectBudgetPlanDetail> getProjectBudgetPlanDetails(Project project){
        return projectBudgetPlanDetailRepository.findAllByProjectIdEquals(project.getId());
    }

    /**
     * 根据每个月的计算资金计划的总
     */
    public ProjectBudgetPlanDetail getProjectBudgetPlanDetailTotal(Project project, List<ProjectBudgetPlanDetail> projectBudgetPlanDetails) {
        BigDecimal deviceCost = new BigDecimal(0);
        BigDecimal engineerCost = new BigDecimal(0);
        BigDecimal projectManageCost = new BigDecimal(0);
        BigDecimal earnestMoneyCost = new BigDecimal(0);
        BigDecimal totalCost = new BigDecimal(0);
        BigDecimal saleIncome = new BigDecimal(0);
        BigDecimal earnestMoneyIncome = new BigDecimal(0);
        BigDecimal totalIncome = new BigDecimal(0);
        BigDecimal fundBalance = new BigDecimal(0);
        BigDecimal capitalInterest = new BigDecimal(0);
        BigDecimal underwrittenPlan = new BigDecimal(0);
        BigDecimal repaymentPlan = new BigDecimal(0);
        /*BigDecimal underwrittenTaxRate = project.getUnderwrittenTaxRate();*/

        if(CollectionUtil.isNotEmpty(projectBudgetPlanDetails)){
            for (ProjectBudgetPlanDetail budgetPlan : projectBudgetPlanDetails) {
                deviceCost = deviceCost.add(budgetPlan.getDeviceCost());
                engineerCost = engineerCost.add(budgetPlan.getEngineerCost());
                projectManageCost = projectManageCost.add(budgetPlan.getProjectManageCost());
                earnestMoneyCost = earnestMoneyCost.add(budgetPlan.getEarnestMoneyCost());
                totalCost = totalCost.add(budgetPlan.getTotalCost());
                saleIncome = saleIncome.add(budgetPlan.getSaleIncome());
                earnestMoneyIncome = earnestMoneyIncome.add(budgetPlan.getEarnestMoneyIncome());
                totalIncome = totalIncome.add(budgetPlan.getTotalIncome());
                /*fundBalance = fundBalance.add(budgetPlan.getFundBalance());*/
                capitalInterest = capitalInterest.add(budgetPlan.getCapitalInterest());
                underwrittenPlan = underwrittenPlan.add(budgetPlan.getUnderwrittenPlan());
                repaymentPlan = repaymentPlan.add(budgetPlan.getRepaymentPlan());
            }
        }

        //总余额等于总收入-总支出
        fundBalance = totalIncome.subtract(totalCost);


        ProjectBudgetPlanDetail projectBudgetPlanDetail = new ProjectBudgetPlanDetail();
        projectBudgetPlanDetail.setMonth("合计");
        projectBudgetPlanDetail.setDeviceCost(deviceCost);
        projectBudgetPlanDetail.setEngineerCost(engineerCost);
        projectBudgetPlanDetail.setProjectManageCost(projectManageCost);
        projectBudgetPlanDetail.setEarnestMoneyCost(earnestMoneyCost);
        projectBudgetPlanDetail.setTotalCost(totalCost);
        projectBudgetPlanDetail.setSaleIncome(saleIncome);
        projectBudgetPlanDetail.setEarnestMoneyIncome(earnestMoneyIncome);
        projectBudgetPlanDetail.setTotalIncome(totalIncome);
        projectBudgetPlanDetail.setFundBalance(fundBalance);
        /*projectBudgetPlanDetail.setUnderwrittenTaxRate(underwrittenTaxRate);*/
        projectBudgetPlanDetail.setCapitalInterest(capitalInterest);
        projectBudgetPlanDetail.setUnderwrittenPlan(underwrittenPlan);
        projectBudgetPlanDetail.setRepaymentPlan(repaymentPlan);
        return projectBudgetPlanDetail;
    }

    /**
     * 计算资金计划的表头展示数据
     */
    public ProjectBudgetPlanDetail getProjectBudgetPlanDetailTotalTitle(Project project,
                                                                        List<ProjectBudgetIncomeDetail> budgetIncomeDetail,
                                                                        List<ProjectBudgetCostDetail> budgetCostDetail,
                                                                        List<ProjectBudgetCostProjectManageDetail> budgetCostProjectManageDetail,
                                                                        List<ProjectBudgetPlanDetail> projectBudgetPlanDetails) {

        BigDecimal deviceCost = calDeviceCost(budgetCostDetail);
        BigDecimal engineerCost = calEngineerCost(budgetCostDetail);
        BigDecimal projectManageCost = calProjectManageCost(budgetCostProjectManageDetail);

        BigDecimal saleIncome = calSaleIncome(budgetIncomeDetail);

        BigDecimal earnestMoneyIncome = new BigDecimal(0);
        BigDecimal earnestMoneyCost = new BigDecimal(0);
        BigDecimal capitalInterest = new BigDecimal(0);
        BigDecimal underwrittenPlan = new BigDecimal(0);
        BigDecimal repaymentPlan = new BigDecimal(0);

        if(CollectionUtil.isNotEmpty(projectBudgetPlanDetails)){
            for (ProjectBudgetPlanDetail budgetPlan : projectBudgetPlanDetails) {
                earnestMoneyCost = earnestMoneyCost.add(budgetPlan.getEarnestMoneyCost());
                earnestMoneyIncome = earnestMoneyIncome.add(budgetPlan.getEarnestMoneyIncome());
                capitalInterest = capitalInterest.add(budgetPlan.getCapitalInterest());
                underwrittenPlan = underwrittenPlan.add(budgetPlan.getUnderwrittenPlan());
                repaymentPlan = repaymentPlan.add(budgetPlan.getRepaymentPlan());
            }
        }
        BigDecimal totalCost = deviceCost.add(engineerCost).add(projectManageCost).add(earnestMoneyCost);
        BigDecimal totalIncome = saleIncome.add(earnestMoneyIncome);

        //总余额等于总收入-总支出
        BigDecimal fundBalance = totalIncome.subtract(totalCost);


        ProjectBudgetPlanDetail projectBudgetPlanDetail = new ProjectBudgetPlanDetail();
        projectBudgetPlanDetail.setMonth("合计");
        projectBudgetPlanDetail.setDeviceCost(deviceCost);
        projectBudgetPlanDetail.setEngineerCost(engineerCost);
        projectBudgetPlanDetail.setProjectManageCost(projectManageCost);
        projectBudgetPlanDetail.setEarnestMoneyCost(earnestMoneyCost);
        projectBudgetPlanDetail.setTotalCost(totalCost);
        projectBudgetPlanDetail.setSaleIncome(saleIncome);
        projectBudgetPlanDetail.setEarnestMoneyIncome(earnestMoneyIncome);
        projectBudgetPlanDetail.setTotalIncome(totalIncome);
        projectBudgetPlanDetail.setFundBalance(fundBalance);

        projectBudgetPlanDetail.setCapitalInterest(capitalInterest);
        projectBudgetPlanDetail.setUnderwrittenPlan(underwrittenPlan);
        projectBudgetPlanDetail.setRepaymentPlan(repaymentPlan);
        return projectBudgetPlanDetail;
    }

    private BigDecimal calSaleIncome(List<ProjectBudgetIncomeDetail> budgetIncomeDetail) {
        BigDecimal saleIncome = new BigDecimal(0);
        if(CollectionUtil.isNotEmpty(budgetIncomeDetail)){
            for (ProjectBudgetIncomeDetail projectBudgetIncomeDetail : budgetIncomeDetail) {
                saleIncome = saleIncome.add(projectBudgetIncomeDetail.getTotalTaxInclude());
            }
        }
        return saleIncome;
    }

    private BigDecimal calProjectManageCost(List<ProjectBudgetCostProjectManageDetail> budgetCostProjectManageDetail) {
        BigDecimal projectManageCost = new BigDecimal(0);
        if(CollectionUtil.isNotEmpty(budgetCostProjectManageDetail)){
            for (ProjectBudgetCostProjectManageDetail projectBudgetCostProjectManageDetail : budgetCostProjectManageDetail) {
                projectManageCost = projectManageCost.add(projectBudgetCostProjectManageDetail.getTotal());
            }
        }
        return projectManageCost;
    }

    private BigDecimal calEngineerCost(List<ProjectBudgetCostDetail> budgetCostDetail) {
        BigDecimal engineerCost = new BigDecimal(0);
        if(CollectionUtil.isNotEmpty(budgetCostDetail)){
            List<ProjectBudgetCostDetail> costDetailList = budgetCostDetail.stream().filter(b -> b.getType() != ProjectBudgetCostDetail.TYPE_DEVICE).collect(Collectors.toList());
            for (ProjectBudgetCostDetail projectBudgetCostDetail : costDetailList) {
                engineerCost = engineerCost.add(projectBudgetCostDetail.getTotalTaxInclude());
            }
        }
        return engineerCost;
    }
    private BigDecimal calDeviceCost(List<ProjectBudgetCostDetail> budgetCostDetail) {
        BigDecimal deviceCost = new BigDecimal(0);
        if(CollectionUtil.isNotEmpty(budgetCostDetail)){
            List<ProjectBudgetCostDetail> costDetailList = budgetCostDetail.stream().filter(b -> b.getType() == ProjectBudgetCostDetail.TYPE_DEVICE).collect(Collectors.toList());
            for (ProjectBudgetCostDetail projectBudgetCostDetail : costDetailList) {
                deviceCost = deviceCost.add(projectBudgetCostDetail.getTotalTaxInclude());
            }
        }
        return deviceCost;
    }

    /**
     * 根据资金计划获取资金使用统计值
     * 月份去峰值月份
     * 峰值累计
     * 资金利息累计
     */
    public ProjectUnderwrittenPlanStatisticBean getProjectUnderwrittenPlanStatisticBean(List<ProjectBudgetPlanDetail> projectBudgetPlanDetails){
        ProjectUnderwrittenPlanStatisticBean bean = new ProjectUnderwrittenPlanStatisticBean();
        if(CollectionUtil.isEmpty(projectBudgetPlanDetails)){
            return bean;
        }

        BigDecimal amount = new BigDecimal(0);
        BigDecimal capitalInterest = new BigDecimal(0);
        BigDecimal max = new BigDecimal(0);
        String maxMonth = "";
        for (ProjectBudgetPlanDetail projectBudgetPlanDetail : projectBudgetPlanDetails) {
            capitalInterest = capitalInterest.add(projectBudgetPlanDetail.getCapitalInterest());
            BigDecimal underwrittenPlan = projectBudgetPlanDetail.getUnderwrittenPlan();
            amount = amount.add(underwrittenPlan);
            if(underwrittenPlan.compareTo(max)>0){
                max = underwrittenPlan;
                maxMonth = projectBudgetPlanDetail.getMonth();
            }
        }

        bean.setMaxMonth(maxMonth);
        bean.setAmount(amount);
        bean.setCapitalInterest(capitalInterest);

        return bean;
    }

    /**
     * 计算现金流量表
     */
    public CashFlowBean getCashFlowBean(Project project, List<ProjectBudgetPlanDetail> projectBudgetPlanDetails){
        CashFlowBean cashFlowBean = new CashFlowBean();
        //获取统计值
        ProjectBudgetPlanDetail detailTotal = getProjectBudgetPlanDetailTotal(project, projectBudgetPlanDetails);

        //a
        cashFlowBean.setSaleIncomeCash(detailTotal.getSaleIncome());
        //c
        cashFlowBean.setEarnestMoneyIncome(detailTotal.getEarnestMoneyIncome());
        //d
        cashFlowBean.setPurchaseCost(detailTotal.getDeviceCost()
                .add(detailTotal.getEngineerCost()));
        //f
        cashFlowBean.setEarnestMoneyCost(detailTotal.getProjectManageCost()
                .add(detailTotal.getEarnestMoneyCost())
                .add(detailTotal.getCapitalInterest()));
        //k
        cashFlowBean.setFinancingCapitalInflow(detailTotal.getUnderwrittenPlan());
        //l
        cashFlowBean.setFinancingCapitalOutflow(detailTotal.getRepaymentPlan());
        return cashFlowBean;
    }


    /**
     * 编辑预算保存项目并审核
     */
    //@Transactional(rollbackFor = RuntimeException.class)
    public void budgetEditSaveAndApprove(Project project, Project projectInDb, BudgetBean budgetBean, Admin admin, ProjectBudget projectBudget) throws Exception {
        Integer approveStatusBudget = projectInDb.getApproveStatusBudget();

        budgetEditSave(project, projectInDb, budgetBean, admin, ApproveStatusEnum.APPROVAL_PENDING, projectBudget);

        saveProjectExtend(projectInDb);

        budgetApprove(approveStatusBudget, projectInDb, admin);
    }

    public void budgetApprove(Integer approveStatusBudget, Project projectInDb, Admin admin) throws Exception {
        projectInstanceService.startFourcalProcess(projectInDb,  ActProcessKeyEnum.BUDGET);
//        int type = projectInDb.getType();
//        List<SysUserRole> userIds = new ArrayList<>();
//        if (type == 1) {
//            String sql = "select sur.user_id from sys_role sr left join sys_user_role sur on sr.id = sur.role_id where sr.is_deleted = 0 and sur.is_deleted = 0 and sr.level in (1,2,3,4,5,6)";
//            userIds = pagination.find(sql, SysUserRole.class);
//        } else if (type == 2) {
//            String sql = "select sur.user_id from sys_role sr left join sys_user_role sur on sr.id = sur.role_id where sr.is_deleted = 0 and sur.is_deleted = 0 and sr.level in (1,2,3,5,6)";
//            userIds = pagination.find(sql, SysUserRole.class);
//        } else if (type == 3) {
//            String sql = "select sur.user_id from sys_role sr left join sys_user_role sur on sr.id = sur.role_id where sr.is_deleted = 0 and sur.is_deleted = 0 and sr.level in (1,2,3,6)";
//            userIds = pagination.find(sql, SysUserRole.class);
//        }
//        List<ProjectVisible> pvs = new ArrayList<>();
//        for (SysUserRole sysUserRole : userIds) {
//            ProjectVisible pv = new ProjectVisible();
//            pv.setProjectId(projectInDb.getId());
//            pv.setType(2);
//            pv.setTid(sysUserRole.getUserId());
//            pvs.add(pv);
//        }
//        projectVisibleRepository.save(pvs);
    }

    /**
     * 编辑预算保存项目
     */
    @Transactional(rollbackFor = RuntimeException.class)
    public Project budgetEditSave(Project project, Project p, BudgetBean budgetBean, Admin admin, ApproveStatusEnum approveStatusEnum, ProjectBudget projectBudget) {
//        Project p = projectService.estimateEditProject(project, projectInDb);
        p.setOtherName(project.getOtherName());

        p.setPlanStartStr(project.getPlanStartStr());
        p.setPlanEndStr(project.getPlanEndStr());
        /// projectInDb.setApproveStatusEstimate(approveStatusEnum.getApproveStatus());

        p.setLastUpdateTime(new Date());
        p.setStatus(StatusEnum.BUDGET_ACCOUNTS.getStatus());
        p.setStatusDesc(StatusEnum.BUDGET_ACCOUNTS.getStatusDesc());
        p.setApproveStatusBudget(approveStatusEnum.getApproveStatus());
        p = projectRepository.saveAndFlush(p);

        saveProjectBudget(p, projectBudget);
        //清空重新保存概算信息
        clearBudget(p);
        saveBudget(p, budgetBean);

        clearBudgetDetail(p);
        saveBudgetDetail(p);

        return p;
    }

    private void saveProjectBudget(Project p, ProjectBudget budget) {
        ProjectBudget projectBudget = projectBudgetRepository.findFirstByProjectId(p.getId());
        try {
            BeanUtils.copyProperties(projectBudget, budget);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        
        projectBudget.setTypeDescBudget(TypeEnum.parseType(projectBudget.getTypeBudget()).getTypeDesc());
        projectBudget.setUnderwrittenModeStrBudget(UnderwrittenModeEnum.parseUnderwrittenMode(projectBudget.getUnderwrittenModeBudget()).getUnderwrittenModeStr());
        projectBudget.setCooperateTypeStrBudget(CooperateTypeEnum.parseCooperateType(projectBudget.getCooperateTypeBudget()).getCooperateTypeStr());
        projectBudget.setCertaintyStrBudget(CertaintyEnum.parseCertainty(projectBudget.getCertaintyBudget()).getCertaintyStr());
        projectBudget.setIndustryScenarioBudget(IndustrySceneEnum.parseScene(projectBudget.getIndustrySceneBudget()).getScenario());
        projectBudget.setIsSecondStrBudget(IsSecondEnum.parseIsSecond(projectBudget.getIsSecondBudget()).getIsSecondStr());
        projectBudget.setSignTypeStrBudget(SignTypeEnum.parseSignType(projectBudget.getSignTypeBudget()).getSignTypeStr());
        projectBudget.setResolvePlanStrBudget(ResolvePlanEnum.parseResolvePlan(projectBudget.getResolvePlanBudget()).getResolvePlanStr());
        projectBudgetRepository.save(projectBudget);
    }

    private void saveProjectExtend(Project p) {
        ProjectExtend extend = projectExtendRepository.findByProjectId(p.getId());
        if (extend == null) {
            extend = new ProjectExtend();
            extend.setProjectId(p.getId());
        }
        extend.setIsBudget(1);

        List<ProjectBudgetPlanDetail> projectBudgetPlanDetails = projectBudgetService.getProjectBudgetPlanDetails(p);
        ProjectUnderwrittenPlanStatisticBean bean = projectBudgetService.getProjectUnderwrittenPlanStatisticBean(projectBudgetPlanDetails);
        extend.setAdvanceInterestAmount(bean.getCapitalInterest());
        extend.setAdvancePeakAmount(bean.getAmount());

        BudgetBean budgetBean = projectBudgetService.getBudget(p);
        BigDecimal grossProfit = budgetBean.getProjectGrossProfit();
        if (grossProfit != null) {
            extend.setGrossProfit(grossProfit);
            extend.setGrossProfitMargin(budgetBean.getProjectGrossProfitRate());
        }

        List<ProjectBudgetIncomeDetail> projectBudgetIncomeDetails = projectBudgetIncomeDetailRepository.findAllByProjectIdEquals(p.getId());
        if (projectBudgetIncomeDetails.size() > 0) {
            BigDecimal contractAmount = projectBudgetIncomeDetails.stream().map(ProjectBudgetIncomeDetail::getTotalTaxInclude).reduce(new BigDecimal(0), BigDecimal::add);
            extend.setContractAmount(contractAmount);
        }

        List<ProjectBudgetCostDetail> projectBudgetCostDetails = projectBudgetCostDetailRepository.findAllByProjectIdEquals(p.getId());
        if (projectBudgetCostDetails.size() > 0) {
            ProcurementType huizhiType = procurementTypeRepository.findByName("汇智产品");
            BigDecimal huizhi = projectBudgetCostDetails.stream().filter(a -> a.getCategory() == huizhiType.getId()).map(ProjectBudgetCostDetail::getTotalTaxInclude).reduce(new BigDecimal(0), BigDecimal::add);
            extend.setHuizhiProductAmount(huizhi);
            ProcurementType huazhiType = procurementTypeRepository.findByName("华智产品");
            BigDecimal huazhi = projectBudgetCostDetails.stream().filter(a -> a.getCategory() == huazhiType.getId()).map(ProjectBudgetCostDetail::getTotalTaxInclude).reduce(new BigDecimal(0), BigDecimal::add);
            extend.setHuazhiProductAmount(huazhi);
            ProcurementType huasanType = procurementTypeRepository.findByName("华三产品");
            BigDecimal huasan = projectBudgetCostDetails.stream().filter(a -> a.getCategory() == huasanType.getId()).map(ProjectBudgetCostDetail::getTotalTaxInclude).reduce(new BigDecimal(0), BigDecimal::add);
            extend.setHuasanProductAmount(huasan);
            BigDecimal other = projectBudgetCostDetails.stream().filter(a -> a.getCategory() != huizhiType.getId() && a.getCategory() != huazhiType.getId() && a.getCategory() != huasanType.getId()).map(ProjectBudgetCostDetail::getTotalTaxInclude).reduce(new BigDecimal(0), BigDecimal::add);
            extend.setZiguangOtherAmount(other);
        }

        projectExtendRepository.save(extend);
    }

    private void saveBudgetDetail(Project p) {
        //临时表中始终是最新的详情,不管是本次修改还是以前保持的
        //收入明细
        List<ProjectBudgetIncomeDetailTemp> projectBudgetIncomeDetailTemps = projectBudgetIncomeDetailTempRepository.findAllByProjectIdEquals(p.getId());
        if(CollectionUtil.isNotEmpty(projectBudgetIncomeDetailTemps)){
            List<ProjectBudgetIncomeDetail> incomeDetails = projectBudgetIncomeDetailTemps.stream()
                    .map(ProjectBudgetIncomeDetailTemp::toProjectBudgetIncomeDetail)
                    .collect(Collectors.toList());
            projectBudgetIncomeDetailRepository.save(incomeDetails);
        }
        //收入计划
        List<ProjectBudgetIncomePlanDetailTemp> projectBudgetIncomePlanDetailTemps = projectBudgetIncomePlanDetailTempRepository.findAllByProjectIdEquals(p.getId());
        if(CollectionUtil.isNotEmpty(projectBudgetIncomePlanDetailTemps)){
            List<ProjectBudgetIncomePlanDetail> incomePlanDetails = projectBudgetIncomePlanDetailTemps.stream()
                    .map(ProjectBudgetIncomePlanDetailTemp::toProjectBudgetIncomePlanDetail)
                    .collect(Collectors.toList());
            projectBudgetIncomePlanDetailRepository.save(incomePlanDetails);
        }
        //成本明细
        List<ProjectBudgetCostDetailTemp> projectBudgetCostDetailTemps = projectBudgetCostDetailTempRepository.findAllByProjectIdEquals(p.getId());
        if(CollectionUtil.isNotEmpty(projectBudgetCostDetailTemps)){
            List<ProjectBudgetCostDetail> costDetails = projectBudgetCostDetailTemps.stream()
                    .map(ProjectBudgetCostDetailTemp::toProjectBudgetCostDetail)
                    .collect(Collectors.toList());
            projectBudgetCostDetailRepository.save(costDetails);
        }
        //项目管理明细
        List<ProjectBudgetCostProjectManageDetailTemp> projectBudgetCostProjectManageDetailTemps = projectBudgetCostProjectManageDetailTempRepository.findAllByProjectIdEquals(p.getId());
        if(CollectionUtil.isNotEmpty(projectBudgetCostProjectManageDetailTemps)){
            List<ProjectBudgetCostProjectManageDetail> costProjectManageDetails = projectBudgetCostProjectManageDetailTemps.stream()
                    .map(ProjectBudgetCostProjectManageDetailTemp::toProjectBudgetCostProjectManageDetail)
                    .collect(Collectors.toList());
            projectBudgetCostProjectManageDetailRepository.save(costProjectManageDetails);
        }
        //资金计划明细
        List<ProjectBudgetPlanDetailTemp> projectBudgetPlanDetailTemps = projectBudgetPlanDetailTempRepository.findAllByProjectIdEquals(p.getId());
        if(CollectionUtil.isNotEmpty(projectBudgetPlanDetailTemps)){
            List<ProjectBudgetPlanDetail> budgetPlanDetails = projectBudgetPlanDetailTemps.stream()
                    .map(ProjectBudgetPlanDetailTemp::toProjectBudgetPlanDetail)
                    .collect(Collectors.toList());
            projectBudgetPlanDetailRepository.save(budgetPlanDetails);
        }
    }

    private void clearBudgetDetail(Project p) {
        //收入明细
        clearBudgetIncomeDetail(p);
        //收入明细
        clearBudgetIncomePlanDetail(p);
        //成本明细
        clearBudgetCostDetail(p);
        //项目管理明细
        clearBudgetCostProjectManageDetail(p);
        //资金计划明细
        clearBudgetPlanDetail(p);
    }

    @Transactional(rollbackFor = Exception.class)
    public ResponseMsg checkIncome(Collection<Map> excelMap, Integer id) {
        int successCount = 0;
        int errorCount = 0;
        List<String> errorList = new ArrayList<>();
        List<ProjectBudgetIncomeDetailTemp> incomeDetailTempList = new ArrayList<>();
        List<ProjectBudgetIncomeDetail> incomeDetailList = new ArrayList<>();
        for (Map m : excelMap) {
            try {
                saveIncomeTemp(m, id, incomeDetailTempList);
                successCount++;
            } catch (Exception e) {
                logger.error("", e);
                errorCount++;
                if (!e.getMessage().isEmpty()) {
                    errorList.add(e.getMessage());
                }
            }
        }
        projectBudgetIncomeDetailTempRepository.save(incomeDetailTempList);
        for (ProjectBudgetIncomeDetailTemp projectBudgetIncomeDetailTemp : incomeDetailTempList) {
            ProjectBudgetIncomeDetail projectBudgetIncomeDetail = projectBudgetIncomeDetailTemp.toProjectBudgetIncomeDetail();
            incomeDetailList.add(projectBudgetIncomeDetail);
        }
        projectBudgetIncomeDetailRepository.save(incomeDetailList);
        final ResponseMsg msg = ResponseMsg.buildSuccessMsg(String.format("成功:%d, 失败:%d", successCount, errorCount));
        msg.setData(errorList);
        return msg;
    }

    private void saveIncomeTemp(Map m, Integer id, List<ProjectBudgetIncomeDetailTemp> incomeDetailTempList) throws Exception {
        ProjectBudgetIncomeDetailTemp temp = new ProjectBudgetIncomeDetailTemp();
        String key;
        Object o1;
        temp.setProjectId(id);
        key = "类别";
        o1 = m.get(key);
        String type = (String) o1;
        if ("设备类".equals(type)) {
            temp.setType(1);
        } else if ("工程类".equals(type)) {
            temp.setType(2);
        } else if ("服务类".equals(type)) {
            temp.setType(3);
        } else {
            throw new Exception("该类别不存在");
        }
        key = "名称";
        o1 = m.get(key);
        temp.setName((String) o1);
        key = "规格类型";
        o1 = m.get(key);
        temp.setName((String) o1);
        key = "参数";
        o1 = m.get(key);
        temp.setName((String) o1);
        key = "单位";
        o1 = m.get(key);
        temp.setUnit((String) o1);
        try {
            key = "数量";
            o1 = m.get(key);
            if (o1 != null) {
                temp.setAmount(new BigDecimal((String) o1));
            }
            key = "单价";
            o1 = m.get(key);
            if (o1 != null) {
                temp.setPrice(new BigDecimal((String) o1));
            }
            key = "税率(%)";
            o1 = m.get(key);
            if (o1 != null) {
                temp.setTaxRate(new BigDecimal((String) o1));
            }
        } catch (Exception e) {
            throw new Exception("数量、单价、税率需为数字");
        }
        incomeDetailTempList.add(temp);
    }

    @Transactional(rollbackFor = Exception.class)
    public ResponseMsg checkCost(Collection<Map> excelMap, Integer id) {
        int successCount = 0;
        int errorCount = 0;
        List<String> errorList = new ArrayList<>();
        List<ProjectBudgetCostDetailTemp> costDetailTempList = new ArrayList<>();
        List<ProjectBudgetCostDetail> CostDetailList = new ArrayList<>();
        for (Map m : excelMap) {
            try {
                saveCostTemp(m, id, costDetailTempList);
                successCount++;
            } catch (Exception e) {
                logger.error("", e);
                errorCount++;
                if (!e.getMessage().isEmpty()) {
                    errorList.add(e.getMessage());
                }
            }
        }
        projectBudgetCostDetailTempRepository.save(costDetailTempList);
        for (ProjectBudgetCostDetailTemp projectBudgetCostDetailTemp : costDetailTempList) {
            ProjectBudgetCostDetail projectBudgetCostDetail = projectBudgetCostDetailTemp.toProjectBudgetCostDetail();
            CostDetailList.add(projectBudgetCostDetail);
        }
        projectBudgetCostDetailRepository.save(CostDetailList);
        final ResponseMsg msg = ResponseMsg.buildSuccessMsg(String.format("成功:%d, 失败:%d", successCount, errorCount));
        msg.setData(errorList);
        return msg;
    }

    private void saveCostTemp(Map m, Integer id, List<ProjectBudgetCostDetailTemp> costDetailTempList) throws Exception {
        ProjectBudgetCostDetailTemp temp = new ProjectBudgetCostDetailTemp();
        String key;
        Object o1;
        temp.setProjectId(id);
        key = "费用项目";
        o1 = m.get(key);
        String type = (String) o1;
        if ("设备".equals(type)) {
            temp.setType(1);
        } else if ("施工".equals(type)) {
            temp.setType(2);
        } else if ("服务".equals(type)) {
            temp.setType(3);
        } else if ("其他".equals(type)) {
            temp.setType(4);
        } else {
            throw new Exception("该费用项目不存在");
        }
        key = "采购类别";
        o1 = m.get(key);
        String category = (String) o1;
        ProcurementType procurementType = procurementTypeRepository.findByName(category);
        if (procurementType != null && procurementType.getType() == temp.getType()) {
            temp.setCategory(procurementType.getId());
        } else {
            throw new Exception("该采购类别不存在或者与费用项目不匹配");
        }
        key = "名称";
        o1 = m.get(key);
        temp.setName((String) o1);
        key = "单位";
        o1 = m.get(key);
        temp.setUnit((String) o1);
        key = "签约方";
        o1 = m.get(key);
        temp.setContractParty((String) o1);
        key = "是否垫资";
        o1 = m.get(key);
        String isUnderwritten = (String) o1;
        if ("是".equals(isUnderwritten)) {
            temp.setIsUnderwritten(1);
        } else if ("否".equals(isUnderwritten)) {
            temp.setIsUnderwritten(2);
        } else {
            temp.setIsUnderwritten(0);
        }
        try {
            key = "数量";
            o1 = m.get(key);
            if (o1 != null) {
                temp.setAmount(new BigDecimal((String) o1));
            }
            key = "单价";
            o1 = m.get(key);
            if (o1 != null) {
                temp.setPrice(new BigDecimal((String) o1));
            }
            key = "税率(%)";
            o1 = m.get(key);
            if (o1 != null) {
                temp.setTaxRate(new BigDecimal((String) o1));
            }
            key = "预估垫资金额(元)";
            o1 = m.get(key);
            if (o1 != null) {
                temp.setUnderwrittenAmount(new BigDecimal((String) o1));
            }
            key = "支出金额(元)";
            o1 = m.get(key);
            if (o1 != null) {
                temp.setPayAmount(new BigDecimal((String) o1));
            }
        } catch (Exception e) {
            throw new Exception("数量、单价、税率、预估垫资金额和支出金额需为数字");
        }
        try {
            key = "支出时间";
            o1 = m.get(key);
            if (o1 != null) {
                temp.setPayTime(DateKit.getDate((String) o1, DateKit.DATE_FORMAT));
            }
        } catch (Exception e) {
            throw new Exception("支出时间需为时间格式yyyy-MM-dd");
        }
        key = "付款方式";
        o1 = m.get(key);
        temp.setPayWay((String) o1);
        key = "备注";
        o1 = m.get(key);
        temp.setRemark((String) o1);
        costDetailTempList.add(temp);
    }
}