package com.ecep.contract.task;

import com.ecep.contract.*;
import com.ecep.contract.controller.project.cost.ProjectCostImportItemsFromContractsTasker;
import com.ecep.contract.model.ContractFileTypeLocal;
import com.ecep.contract.service.*;
import com.ecep.contract.vo.*;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.ObservableMap;
import javafx.util.converter.NumberStringConverter;
import lombok.Data;
import org.springframework.util.StringUtils;

import java.io.File;
import java.text.NumberFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

@Data
public class ContractVerifyComm {
    // Project
    private ProjectService projectService;
    private ProjectSaleTypeRequireFileTypeService saleTypeRequireFileTypeService;
    private ProjectSaleTypeService saleTypeService;
    private ProjectCostService projectCostService;
    private ProjectQuotationService projectQuotationService;
    private ProjectBidService projectBidService;
    // Contract
    private ContractService contractService;
    private ContractFileService contractFileService;
    private ContractFileTypeService contractFileTypeService;
    private ContractBidVendorService contractBidVendorService;

    // Company
    private CompanyService companyService;
    private CompanyFileService companyFileService;
    // Vendor
    private VendorService vendorService;
    private VendorGroupService vendorGroupService;
    private VendorGroupRequireFileTypeService vendorGroupRequireFileTypeService;
    private ExtendVendorInfoService extendVendorInfoService;
    // Customer
    private CompanyCustomerService companyCustomerService;
    private CompanyCustomerFileService companyCustomerFileService;
    private CompanyExtendInfoService companyExtendInfoService;
    // Employee
    private EmployeeService employeeService;

    private ProjectService getProjectService() {
        if (projectService == null) {
            projectService = SpringApp.getBean(ProjectService.class);
        }
        return projectService;
    }

    private ProjectSaleTypeService getSaleTypeService() {
        if (saleTypeService == null) {
            saleTypeService = SpringApp.getBean(ProjectSaleTypeService.class);
        }
        return saleTypeService;
    }

    ProjectCostService getProjectCostService() {
        if (projectCostService == null) {
            projectCostService = SpringApp.getBean(ProjectCostService.class);
        }
        return projectCostService;
    }

    ProjectQuotationService getProjectQuotationService() {
        if (projectQuotationService == null) {
            projectQuotationService = SpringApp.getBean(ProjectQuotationService.class);
        }
        return projectQuotationService;
    }

    ProjectBidService getProjectBidService() {
        if (projectBidService == null) {
            projectBidService = SpringApp.getBean(ProjectBidService.class);
        }
        return projectBidService;
    }

    private ProjectSaleTypeRequireFileTypeService getSaleTypeRequireFileTypeService() {
        if (saleTypeRequireFileTypeService == null) {
            saleTypeRequireFileTypeService = SpringApp.getBean(ProjectSaleTypeRequireFileTypeService.class);
        }
        return saleTypeRequireFileTypeService;
    }

    public ContractService getContractService() {
        if (contractService == null) {
            contractService = SpringApp.getBean(ContractService.class);
        }
        return contractService;
    }

    private ContractFileService getContractFileService() {
        if (contractFileService == null) {
            contractFileService = SpringApp.getBean(ContractFileService.class);
        }
        return contractFileService;
    }

    private ContractFileTypeService getContractFileTypeService() {
        if (contractFileTypeService == null) {
            contractFileTypeService = SpringApp.getBean(ContractFileTypeService.class);
        }
        return contractFileTypeService;
    }

    private ContractBidVendorService getContractBidVendorService() {
        if (contractBidVendorService == null) {
            contractBidVendorService = SpringApp.getBean(ContractBidVendorService.class);
        }
        return contractBidVendorService;
    }

    private CompanyService getCompanyService() {
        if (companyService == null) {
            companyService = SpringApp.getBean(CompanyService.class);
        }
        return companyService;
    }

    private CompanyFileService getCompanyFileService() {
        if (companyFileService == null) {
            companyFileService = SpringApp.getBean(CompanyFileService.class);
        }
        return companyFileService;
    }

    private VendorGroupService getVendorGroupService() {
        if (vendorGroupService == null) {
            vendorGroupService = SpringApp.getBean(VendorGroupService.class);
        }
        return vendorGroupService;
    }

    private VendorGroupRequireFileTypeService getVendorGroupRequireFileTypeService() {
        if (vendorGroupRequireFileTypeService == null) {
            vendorGroupRequireFileTypeService = SpringApp.getBean(VendorGroupRequireFileTypeService.class);
        }
        return vendorGroupRequireFileTypeService;
    }

    private ExtendVendorInfoService getExtendVendorInfoService() {
        if (extendVendorInfoService == null) {
            extendVendorInfoService = SpringApp.getBean(ExtendVendorInfoService.class);
        }
        return extendVendorInfoService;
    }

    private VendorService getVendorService() {
        if (vendorService == null) {
            vendorService = SpringApp.getBean(VendorService.class);
        }
        return vendorService;
    }

    private CompanyCustomerService getCompanyCustomerService() {
        if (companyCustomerService == null) {
            companyCustomerService = SpringApp.getBean(CompanyCustomerService.class);
        }
        return companyCustomerService;
    }

    private CompanyCustomerFileService getCompanyCustomerFileService() {
        if (companyCustomerFileService == null) {
            companyCustomerFileService = SpringApp.getBean(CompanyCustomerFileService.class);
        }
        return companyCustomerFileService;
    }

    private CompanyExtendInfoService getCompanyExtendInfoService() {
        if (companyExtendInfoService == null) {
            companyExtendInfoService = SpringApp.getBean(CompanyExtendInfoService.class);
        }
        return companyExtendInfoService;
    }

    private EmployeeService getEmployeeService() {
        if (employeeService == null) {
            employeeService = SpringApp.getBean(EmployeeService.class);
        }
        return employeeService;
    }

    /**
     *
     */
    private ObservableMap<ContractFileType, ContractFileTypeLocal> fileTypeLocalMap = null;
    private Locale locale = Locale.getDefault();

    /**
     * 是否验证企业存储目录
     */
    private SimpleBooleanProperty verifyCompanyPath = new SimpleBooleanProperty(true);
    /**
     * 是否验证企业状态
     */
    private SimpleBooleanProperty verifyCompanyStatus = new SimpleBooleanProperty(true);
    /**
     * 是否验证企业文件(资信报告)
     */
    private SimpleBooleanProperty verifyCompanyCredit = new SimpleBooleanProperty(true);
    /**
     * 是否验证客户
     */
    private SimpleBooleanProperty verifyCustomer = new SimpleBooleanProperty(true);
    /**
     * 是否验证客户文件(合同文件)
     */
    private SimpleBooleanProperty verifyCustomerFiles = new SimpleBooleanProperty(true);
    /**
     * 是否验证客户子合同日期
     */
    private SimpleBooleanProperty verifyCustomerSubContractDate = new SimpleBooleanProperty(true);
    /**
     * 是否验证供应商
     */
    private SimpleBooleanProperty verifyVendor = new SimpleBooleanProperty(true);
    /**
     * 是否验证供应商文件(供应商合同)
     */
    private SimpleBooleanProperty verifyVendorFiles = new SimpleBooleanProperty(true);

    /**
     * 合同合规性检测
     *
     * @param contract 要验证的合同对象
     * @param holder   输出
     */
    public void verify(ContractVo contract, MessageHolder holder) {
        LocalDate setupDate = contract.getSetupDate();
        if (setupDate == null) {
            holder.error("未设置合同提交日期");
            return;
        }
        Integer companyId = contract.getCompanyId();
        if (companyId == null) {
            holder.error("未关联企业");
            return;
        }
        CompanyVo company = getCompanyService().findById(companyId);
        if (company == null) {
            holder.error("合同关联公司 #" + companyId + " 异常，无法读取");
            return;
        }
        company = getCompanyService().findById(company.getId());
        verify(company, contract, holder);
    }

    public void verify(CompanyVo company, ContractVo contract, MessageHolder holder) {
        LocalDate setupDate = contract.getSetupDate();
        Integer handlerId = contract.getHandlerId();
        if (handlerId == null) {
            handlerId = contract.getEmployeeId();
        }
        if (handlerId == null) {
            holder.error("未关联处理人");
            return;
        }

        EmployeeVo employee = getEmployeeService().findById(handlerId);
        if (employee == null) {
            holder.error("关联处理人 #" + handlerId + " 异常，无法读取");
            return;
        }

        if (contract.getAmount() == null || contract.getAmount() <= 0) {
            holder.error("合同金额小于等于0");
        }

        CompanyExtendInfoVo companyExtendInfo = getCompanyExtendInfoService().findByCompany(company);
        if (companyExtendInfo == null) {
            CompanyExtendInfoVo extendInfo = new CompanyExtendInfoVo();
            extendInfo.setCompanyId(company.getId());
            extendInfo.setDisableVerify(false);
            companyExtendInfo = getCompanyExtendInfoService().save(extendInfo);
        }

        if (companyExtendInfo.isDisableVerify()) {
            holder.debug("公司设定不做校验");
        } else {
            if (verifyCompanyPath.get()) {
                if (!getCompanyService().existsCompanyPath(company)) {
                    holder.error("公司目录未设置");
                } else {
                    if (!getCompanyService().checkCompanyPathInBasePath(company)) {
                        holder.error("公司目录未在规定目录下");
                    }
                }
            }

            if (verifyCompanyStatus.get()) {
                getCompanyService().verifyEnterpriseStatus(company, setupDate, holder);
            }

            if (verifyCompanyCredit.get()) {
                getCompanyFileService().verify(company, contract.getSetupDate(), holder);
            }
        }

        // 合同类型
        switch (contract.getPayWay()) {
            case RECEIVE -> {
                // 销售合同
                verifyAsCustomer(company, companyExtendInfo, contract, holder);

                // 销售合同下的采购合同
                List<ContractVo> list = getContractService().findAllBySaleContract(contract);
                if (!list.isEmpty()) {
                    for (ContractVo v : list) {
                        MessageHolder subHolder = holder.sub(v.getCode() + " -> ");
                        subHolder.info("采购合同 ： " + v.getName());
                        verify(v, subHolder);
                        if (getContractService().existsContractPath(v)) {
                            if (!getContractService().checkContractPathInBasePath(v)) {
                                holder.error("合同目录未在规定目录下");
                            }
                        } else {
                            holder.error("合同目录未设置");
                        }
                    }

                    DoubleSummaryStatistics statistics = list.stream().mapToDouble(c -> {
                        return Objects.requireNonNullElse(c.getAmount(), 0.0);
                    }).summaryStatistics();
                    NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale);

                    holder.debug("采购合同金额合计：" + numberFormat.format(statistics.getSum()));
                    holder.debug("采购合同金额平均值：" + numberFormat.format(statistics.getAverage()));
                    holder.debug("采购合同金额最大值：" + numberFormat.format(statistics.getMax()));
                    holder.debug("采购合同金额最小值：" + numberFormat.format(statistics.getMin()));
                    if (contract.getAmount() != null && statistics.getSum() > contract.getAmount()) {
                        holder.warn("采购合同金额合计大于销售合同金额");
                    }
                }

                break;
            }
            case PAY -> {
                verifyAsVendor(company, contract, holder);
                break;
            }
            case OTHER -> {
                holder.error("合同付款类型：其他");
                break;
            }
            default -> {
                holder.error("合同付款类型：未设置");
            }
        }
    }

    private void verifyAsVendor(CompanyVo company, ContractVo contract, MessageHolder holder) {
        // 供应商，检查评价表
        ExtendVendorInfoVo vendorInfo = getExtendVendorInfoService().findByContract(contract);
        if (vendorInfo == null) {
            ExtendVendorInfoVo info = getExtendVendorInfoService().newInstanceByContract(contract);
            vendorInfo = getExtendVendorInfoService().save(info);
            holder.info("创建供应商信息 #" + vendorInfo.getId());
        }
        VendorGroupVo group = null;
        if (vendorInfo.getGroupId() != null) {
            group = getVendorGroupService().findById(vendorInfo.getGroupId());
        }
        boolean assignedProvider = vendorInfo.isAssignedProvider();
        if (assignedProvider) {
            holder.debug("采购信息中设定为指定供应商");
        }

        if (verifyCustomerSubContractDate.get()) {
            // 检查子合同日期是否在销售合同之后
            if (!vendorInfo.isPrePurchase()) {
                String parentCode = contract.getParentCode();
                if (StringUtils.hasText(parentCode)) {
                    ContractVo parent = getContractService().findByCode(parentCode);
                    if (parent != null) {
                        if (contract.getSetupDate().isBefore(parent.getSetupDate())) {
                            holder.warn("采购合同：" + contract.getCode() + " 提交日期在销售合同之前");
                        }
                    }
                }
            }
        }
        if (verifyVendor.get()) {
            getVendorService().verify(contract, holder);
        }

        if (verifyVendorFiles.get()) {
            holder.debug("核验文件...");
            verifyVendorFile(group, assignedProvider, contract, holder);
        }
    }

    private void verifyVendorFile(VendorGroupVo group, boolean assignedProvider, ContractVo contract,
                                  MessageHolder holder) {
        if (group == null) {
            return;
        }
        boolean loseFile = false;
        ContractFileService fileService = getContractFileService();
        List<ContractFileVo> files = fileService.findAllByContract(contract);
        List<VendorGroupRequireFileTypeVo> list = getVendorGroupRequireFileTypeService().findByGroupId(group.getId());
        if (list != null) {
            for (VendorGroupRequireFileTypeVo item : list) {
                ContractFileType fileType = item.getFileType();
                if (fileType == null) {
                    continue;
                }
                if (fileType == ContractFileType.QuotationSheet && assignedProvider
                        && group.isRequireQuotationSheetForBid()) {
                    continue;
                }
                if (!hasFileType(files, fileType)) {
                    holder.error("供应商" + getFileTypeLocalValue(fileType) + "未上传");
                    loseFile = true;
                }

            }
        }

        // 供应商比价
        if (group.isPriceComparison()) {
            if (assignedProvider) {
                holder.debug("指定供应商, 跳过供应商比价");
            } else {
                boolean requireQuotation = group.isRequireQuotationSheetForBid();
                List<ContractBidVendorVo> bidVendors = getContractBidVendorService().findByContract(contract);
                if (bidVendors == null || bidVendors.isEmpty()) {
                    holder.error("未上报供应商比价");
                } else {
                    for (ContractBidVendorVo bidVendor : bidVendors) {
                        if (bidVendor.getCompanyId() == null) {
                            holder.warn("供应商比价：#" + bidVendor.getId() + " 未关联供应商");
                            continue;
                        }

                        CompanyVo company = getCompanyService().findById(bidVendor.getCompanyId());
                        ContractFileVo contractFile = fileService.findById(bidVendor.getQuotationSheetFileId());
                        // 报价表文件不存在
                        if (contractFile == null) {
                            if (requireQuotation && bidVendor.getCompanyId().equals(contract.getCompanyId())) {
                                holder.debug("供应商类型启用了允许选中供应商不必须要有报价表");
                            } else {
                                holder.error("供应商比价：" + company.getName() + " 未上传/关联报价表");
                                loseFile = true;
                            }
                        } else {
                            ContractFileType type = contractFile.getType();
                            if (type == null) {
                                continue;
                            }
                            if (type != ContractFileType.QuotationSheet) {
                                holder.error("供应商比价：" + contractFile.getFileName() + " 报价表记录异常，类型错误");
                                loseFile = true;
                            } else {
                                if (StringUtils.hasText(contractFile.getFileName())) {
                                    File file = new File(contract.getPath(), contractFile.getFileName());
                                    if (!file.exists()) {
                                        holder.error("供应商比价：" + file.getName() + " 报价表记录异常，文件不存在");
                                        loseFile = true;
                                    }
                                } else {
                                    holder.error("供应商比价：" + company.getName() + " 报价表记录异常");
                                    loseFile = true;
                                }
                            }

                        }
                    }
                }
            }
        }
        if (loseFile && files.isEmpty()) {
            holder.warn("!上传文件空!");
        }
    }

    ContractFileTypeLocalVo getFileTypeLocal(ContractFileType type) {
        return getContractFileTypeService().findByType(getLocale(), type);
    }

    String getFileTypeLocalValue(ContractFileType type) {
        ContractFileTypeLocalVo fileTypeLocal = getFileTypeLocal(type);
        if (fileTypeLocal == null) {
            return type.name();
        }
        return fileTypeLocal.getValue();
    }

    private boolean hasFileType(List<ContractFileVo> files, ContractFileType fileType) {
        if (files == null || files.isEmpty()) {
            return false;
        }
        for (ContractFileVo file : files) {
            if (file.getType() == fileType) {
                return true;
            }
        }
        return false;
    }

    private void verifyAsCustomer(CompanyVo company, CompanyExtendInfoVo companyExtendInfo, ContractVo contract,
                                  MessageHolder holder) {
        boolean valiad = true;
        ProjectVo project = null;
        Integer projectId = contract.getProject();
        if (projectId == null) {
            // 收款的合同时，检查是否关联了项目，如果没有则创建
            if (contract.getPayWay() == ContractPayWay.RECEIVE) {
                project = getProjectService().findByCode(contract.getCode());
                if (project == null) {
                    holder.info("创建关联项目");
                    try {
                        project = getProjectService().newInstanceByContract(contract);
                        project = getProjectService().save(project);
                    } catch (Exception e) {
                        holder.error("创建关联项目失败: " + e.getMessage());
                        throw new RuntimeException("code=" + contract.getCode(), e);
                    }
                }
                contract.setProject(project.getId());
                contract = getContractService().save(contract);
            }
        } else {
            project = getProjectService().findById(projectId);
        }

        if (project != null) {
            holder.info("验证项目信息:" + project.getCode() + " " + project.getName());
            verifyProject(contract, project, holder.sub("项目"));

            Integer saleTypeId = project.getSaleTypeId();

            if (saleTypeId != null) {
                ProjectSaleTypeVo saleType = getSaleTypeService().findById(saleTypeId);
                if (saleType != null) {
                    if (getContractService().existsContractPath(contract)) {
                        saleType = getSaleTypeService().findById(saleType.getId());
                        project.setSaleTypeId(saleType.getId());
                        if (!contract.getPath().startsWith(saleType.getPath())) {
                            holder.error("合同目录未在销售类型目录下");
                        }
                    }
                }
            }
        }

        if (!companyExtendInfo.isDisableVerify()) {
            if (!verifyCustomerContract(contract, holder)) {
                valiad = false;
            }

            if (verifyCustomerFiles.get()) {
                holder.debug("核验文件...");
                if (!verifyContractFileAsCustomer(project, contract, holder)) {
                    valiad = false;
                }
            }
        }
    }

    /**
     * 客户，检查评估表
     */
    private boolean verifyCustomerContract(ContractVo contract, MessageHolder holder) {
        if (!verifyCustomer.get()) {
            return false;
        }
        boolean valid = true;
        Integer companyId = contract.getCompanyId();
        CompanyVo company = getCompanyService().findById(companyId);
        if (company == null) {
            holder.warn("合同未关联公司");
            valid = false;
        }

        CompanyCustomerVo companyCustomer = getCompanyCustomerService().findByCompany(company);
        if (companyCustomer == null) {
            holder.warn("合同未关联客户");
            valid = false;
        } else {
            if (!StringUtils.hasText(companyCustomer.getPath())) {
                holder.warn("客户未设置文件夹");
                valid = false;
            }
            LocalDate developDate = companyCustomer.getDevelopDate();
            if (developDate == null) {
                holder.warn("客户未设置开发日期");
                valid = false;
            }
            if (!verifyCustomerFileByContract(companyCustomer, contract, holder)) {
                valid = false;
            }
        }
        return valid;
    }

    private boolean verifyCustomerFileByContract(CompanyCustomerVo companyCustomer, ContractVo contract,
                                                 MessageHolder holder) {
        List<LocalDate> verifyDates = new ArrayList<>();
        LocalDate minDate = LocalDate.of(2022, 1, 1);
        LocalDate developDate = companyCustomer.getDevelopDate();
        if (developDate != null) {
            if (developDate.isAfter(minDate)) {
                minDate = developDate;
            }
        }
        if (contract.getSetupDate() != null) {
            LocalDate setupDate = contract.getSetupDate();
            if (setupDate.isBefore(developDate)) {
                holder.error("合同提交日期 " + setupDate + " 早于客户开发日期 " + developDate + ".");
                return false;
            }
            if (setupDate.isBefore(minDate)) {
                holder.debug("合同提交日期 " + setupDate + " 早于 " + minDate + ", 跳过");
            } else {
                verifyDates.add(setupDate);
            }
        }
        if (contract.getStartDate() != null) {
            LocalDate startDate = contract.getStartDate();
            if (startDate.isBefore(developDate)) {
                holder.warn("合同起始日期 " + startDate + " 早于客户开发日期 " + developDate + ".");
            }

            if (startDate.isBefore(minDate)) {
                holder.debug("合同起始日期 " + startDate + " 早于 " + minDate + ", 跳过");
            } else {
                verifyDates.add(startDate);
            }
        }
        if (contract.getOrderDate() != null) {
            LocalDate orderDate = contract.getOrderDate();
            if (orderDate.isBefore(developDate)) {
                holder.error("合同签订日期 " + orderDate + " 早于客户开发日期 " + developDate + ".");
                return false;
            }
            if (orderDate.isBefore(minDate)) {
                holder.debug("合同签订日期 " + orderDate + " 早于 " + minDate + ", 跳过");
            } else {
                verifyDates.add(orderDate);
            }
        }

        if (verifyDates.isEmpty()) {
            holder.warn("合同没有符合可核验的日期");
            return false;
        }

        // 客户
        List<CompanyCustomerFileVo> files = getCompanyCustomerFileService().findAllByCustomer(companyCustomer);
        if (files == null || files.isEmpty()) {
            holder.warn("未见客户评估表");
            return false;
        }

        for (LocalDate verifyDate : verifyDates) {
            CompanyCustomerFileVo customerFile = files.stream()
                    .filter(v -> v.getSignDate() != null && v.isValid())
                    .filter(v -> v.getType() == CustomerFileType.EvaluationForm)
                    .filter(v -> MyDateTimeUtils.dateValidFilter(verifyDate, v.getSignDate(),
                            v.getSignDate().plusYears(1), 7))
                    .findFirst().orElse(null);
            if (customerFile != null) {
                return true;
            }
        }

        CompanyCustomerFileVo latestFile = files.stream()
                .filter(v -> v.getSignDate() != null && v.isValid())
                .filter(v -> v.getType() == CustomerFileType.EvaluationForm)
                .max(Comparator.comparing(CompanyCustomerFileVo::getSignDate))
                .orElse(null);

        if (latestFile == null) {
            holder.error("未匹配的客户评估");
            return false;
        }

        holder.error("客户评估已过期，最后一个客户评估报告日期：" + latestFile.getSignDate() + ", 检测日期："
                + verifyDates.stream().map(LocalDate::toString).collect(Collectors.joining(", ")));
        return false;
    }

    private void verifyProject(ContractVo contract, ProjectVo project, MessageHolder holder) {
        Integer saleTypeId = project.getSaleTypeId();
        ProjectSaleTypeVo saleType = null;
        if (saleTypeId == null) {
            String code = contract.getCode();
            if (code != null && code.length() > 5) {
                saleType = getSaleTypeService().findByCode(code.substring(0, 1));
                if (saleType != null) {
                    project.setSaleTypeId(saleType.getId());
                    holder.info("根据合同代码设置项目销售类型：" + saleType.getName());
                }
            }
        } else {
            saleType = getSaleTypeService().findById(saleTypeId);
        }

        if (saleType == null) {
            holder.warn("销售类型未设置");
        }
        if (project.getAmount() == null || project.getAmount() <= 0) {
            holder.error("金额小于等于0");
        }

        //
        boolean needImport = false;

        ProjectCostService projectCostService = getProjectCostService();
        ProjectCostVo autoCost = projectCostService.findAutoCostByProject(project);
        if (autoCost == null) {
            // 创建 V0 项目成本
            ProjectCostVo cost = projectCostService.newInstanceByProject(project);
            cost.setVersion(0);
            cost.setApplicantId(EmployeeService.DEFAULT_SYSTEM_EMPLOYEE_ID);
            cost.setApplyTime(LocalDateTime.now());
            cost.setDescription("自动导入");
            autoCost = projectCostService.save(cost);
            needImport = true;
        } else {
            // 检查 V0 项目成本
            if (autoCost.getGrossProfitMargin() <= 0) {
                NumberFormat instance = NumberFormat.getNumberInstance(getLocale());
                instance.setMaximumFractionDigits(2);
                NumberStringConverter converter = new NumberStringConverter(instance);
                holder.warn("V0项目成本毛利率异常：" + converter.toString(autoCost.getGrossProfitMargin()) + "<=0%");
                needImport = true;
            }
        }

        if (needImport && !autoCost.isImportLock()) {
            holder.debug("更新V0项目成本");
            ProjectCostVo cost = projectCostService.findAutoCostByProject(project);
            if (cost == null) {
                cost = projectCostService.newInstanceByProject(project);
                cost.setVersion(0);
                cost = projectCostService.save(cost);
            }
            ProjectCostImportItemsFromContractsTasker tasker = new ProjectCostImportItemsFromContractsTasker();
            tasker.setCost(cost);

        }

        // 检查最新的项目成本，默认 V1
        ProjectCostVo latestCost = projectCostService.findLatestByProject(project);
        if (latestCost == null) {
            ProjectCostVo cost = projectCostService.newInstanceByProject(project);
            cost.setVersion(1);
            Integer applicantId = project.getApplicantId();
            if (applicantId == null) {
                applicantId = contract.getEmployeeId();
            }
            cost.setApplicantId(applicantId);
            cost.setApplyTime(project.getCreated().atTime(LocalTime.now()));
            latestCost = projectCostService.save(cost);
        } else {
            //
            if (latestCost.getGrossProfitMargin() <= 0) {
                NumberFormat instance = NumberFormat.getNumberInstance(getLocale());
                instance.setMaximumFractionDigits(2);
                NumberStringConverter converter = new NumberStringConverter(instance);
                holder.warn("V" + latestCost.getVersion() + "项目成本毛利率异常："
                        + converter.toString(latestCost.getGrossProfitMargin()) + "<=0%");
            } else if (latestCost.getGrossProfitMargin() >= 50) {
                NumberFormat instance = NumberFormat.getNumberInstance(getLocale());
                instance.setMaximumFractionDigits(2);
                NumberStringConverter converter = new NumberStringConverter(instance);
                holder.warn("V" + latestCost.getVersion() + "项目成本毛利率异常："
                        + converter.toString(latestCost.getGrossProfitMargin()) + ">=50%");
            }
        }

        if (project.isUseBid()) {
            List<ProjectBidVo> bids = getProjectBidService().findAllByProject(project);
            if (bids.isEmpty()) {
                holder.warn("投标未创建");
            }
        }
        if (project.isUseOffer()) {
            List<ProjectQuotationVo> quotations = getProjectQuotationService().findAllByProject(project);
            if (quotations.isEmpty()) {
                holder.warn("报价未创建");
            }
        }
    }

    private boolean verifyContractFileAsCustomer(ProjectVo project, ContractVo contract, MessageHolder holder) {
        boolean loseFile = false;
        List<ContractFileVo> files = getContractFileService().findAllByContract(contract);
        if (project != null) {
            // 投标
            if (project.isUseBid()) {
                // 投标审批表
                if (!hasFileType(files, ContractFileType.BidApprovalForm)) {
                    holder.error(getFileTypeLocalValue(ContractFileType.BidApprovalForm) + "未上传");
                    loseFile = true;
                }
                // 中标通知书
                if (!hasFileType(files, ContractFileType.BidAcceptanceLetter)) {
                    holder.error(getFileTypeLocalValue(ContractFileType.BidAcceptanceLetter) + "未上传");
                    loseFile = true;
                }
            }
            // 报价
            if (project.isUseOffer()) {
                if (!hasFileType(files, ContractFileType.QuotationApprovalForm)) {
                    holder.error(getFileTypeLocalValue(ContractFileType.QuotationApprovalForm) + "未上传");
                    loseFile = true;
                }
            }
            Integer saleTypeId = project.getSaleTypeId();
            ProjectSaleTypeVo saleType = getSaleTypeService().findById(saleTypeId);
            if (saleType != null) {
                List<ProjectSaleTypeRequireFileTypeVo> list = getSaleTypeRequireFileTypeService()
                        .findBySaleTypeId(saleType.getId());
                for (ProjectSaleTypeRequireFileTypeVo item : list) {
                    ContractFileType fileType = item.getFileType();
                    if (fileType != null) {
                        if (!hasFileType(files, fileType)) {
                            holder.error(getFileTypeLocalValue(fileType) + "未上传");
                            loseFile = true;
                        }
                    }
                }
                saleType = getSaleTypeService().findById(saleType.getId());
                if (saleType.isCriticalProjectDecision()) {
                    if (contract.getAmount() != null && contract.getAmount() >= saleType.getCriticalProjectLimit()) {
                        holder.debug("合同金额 " + contract.getAmount() + " 超过 " + saleType.getCriticalProjectLimit());
                        if (!hasFileType(files, ContractFileType.CriticalProjectDecisionRecord)) {
                            holder.error(getFileTypeLocalValue(ContractFileType.CriticalProjectDecisionRecord) + "未上传");
                            loseFile = true;
                        }
                    }
                }
            }
        }
        if (loseFile && files.isEmpty()) {
            holder.warn("!上传文件空!");
        }

        return !loseFile;
    }
}
