package com.ecep.contract.service; import java.io.File; import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.ecep.contract.vo.CompanyOldNameVo; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import com.ecep.contract.CompanyFileType; import com.ecep.contract.MessageHolder; import com.ecep.contract.MyDateTimeUtils; import com.ecep.contract.SpringApp; import com.ecep.contract.constant.CloudServiceConstant; import com.ecep.contract.constant.CompanyConstant; import com.ecep.contract.model.Company; import com.ecep.contract.model.CompanyFile; import com.ecep.contract.model.CompanyOldName; import com.ecep.contract.util.FileUtils; import com.ecep.contract.util.ParamUtils; import com.ecep.contract.vm.CompanyFileViewModel; import com.ecep.contract.vo.CompanyFileVo; import com.ecep.contract.vo.CompanyVo; import javafx.collections.ObservableList; @Service public class CompanyFileService extends QueryService { public List findByCompany(CompanyVo company) { if (company == null) { return List.of(); } return findAll(ParamUtils.equal("company", company.getId()), Pageable.unpaged()).getContent(); } public List findByCompanyAndPath(CompanyVo company, String absolutePath) { return findAll(ParamUtils.builder().equals("company", company.getId()).equals("filePath", absolutePath).build(), Pageable.unpaged()).getContent(); } public boolean reBuildingFiles(CompanyVo company, MessageHolder holder) { List dbFiles = findByCompany(company); List retrieveFiles = new ArrayList<>(); boolean modfied = false; Map map = new HashMap<>(); // 排除掉数据库中重复的 for (CompanyFileVo dbFile : dbFiles) { String filePath = dbFile.getFilePath(); // 没有文件信息,无效记录,删除 if (!StringUtils.hasText(filePath)) { delete(dbFile); modfied = true; continue; } // 目录不存在,删除 File dir = new File(filePath); if (!dir.exists()) { delete(dbFile); modfied = true; continue; } CompanyFileVo old = map.put(filePath, dbFile); // 目录有重复删除 if (old != null) { delete(old); modfied = true; } } Map directoryMap = new HashMap<>(); // 公司目录 if (StringUtils.hasText(company.getPath())) { File dir = new File(company.getPath()); directoryMap.put(company.getName(), dir); } // 获取所有曾用名 List oldNames = SpringApp.getBean(CompanyOldNameService.class).findAllByCompany(company); for (CompanyOldNameVo companyOldName : oldNames) { String path = companyOldName.getPath(); if (StringUtils.hasText(path)) { File dir = new File(path); directoryMap.put(companyOldName.getName(), dir); } } for (Map.Entry entry : directoryMap.entrySet()) { String companyName = entry.getKey(); File dir = entry.getValue(); if (!StringUtils.hasText(companyName)) { continue; } if (dir == null || !dir.exists()) { continue; } File[] files = dir.listFiles(); if (files == null) { // 文件系统出错或者没有相关文件 continue; } for (File file : files) { // 只处理文件 if (!file.isFile() || FileUtils.isHiddenFile(file)) { continue; } String filePath = file.getAbsolutePath(); if (!map.containsKey(filePath)) { // 未记录 CompanyFileVo filled = fillFileType(file, holder); retrieveFiles.add(filled); } } } holder.info("导入 " + retrieveFiles.size() + " 个文件"); if (retrieveFiles.isEmpty()) { return modfied; } // update db retrieveFiles.forEach(v -> { v.setCompanyId(company.getId()); save(v); }); return true; } /** * 从文件名生成公司文件对象,文件已经存在公司对应的存储目录下 * * @param file 文件 * @param holder 状态输出 * @return 公司文件对象 */ private CompanyFileVo fillFileType(File file, MessageHolder holder) { String fileName = file.getName(); CompanyFileVo companyFile = new CompanyFileVo(); companyFile.setType(CompanyFileType.General); companyFile.setFilePath(file.getAbsolutePath()); fillApplyDateAndExpiringDateAbsent(file, companyFile); // 天眼查 基础版企业信用报告 if (fileName.contains(CloudServiceConstant.TYC_ENTERPRISE_BASIC_REPORT) || fileName.contains(CloudServiceConstant.TYC_ENTERPRISE_MAJOR_REPORT) || fileName.contains(CloudServiceConstant.TYC_ENTERPRISE_ANALYSIS_REPORT)) { companyFile.setType(CompanyFileType.CreditReport); fillExpiringDateAbsent(companyFile); return companyFile; } // 天眼查 企业信用信息公示报告 if (fileName.contains(CloudServiceConstant.TYC_ENTERPRISE_CREDIT_REPORT)) { companyFile.setType(CompanyFileType.CreditInfoPublicityReport); return companyFile; } // 集团相关方平台 元素征信 企业征信报告 if (fileName.contains(CloudServiceConstant.RK_VENDOR_NAME) && fileName.contains(CloudServiceConstant.RK_ENTERPRISE_CREDIT_REPORT)) { companyFile.setType(CompanyFileType.CreditReport); fillExpiringDateAbsent(companyFile); return companyFile; } // 营业执照 if (fileName.contains(CompanyConstant.BUSINESS_LICENSE)) { companyFile.setType(CompanyFileType.BusinessLicense); return companyFile; } // 其他企业信用报告 if (fileName.contains(CompanyConstant.ENTERPRISE_REPORT)) { companyFile.setType(CompanyFileType.CreditReport); fillExpiringDateAbsent(companyFile); return companyFile; } return companyFile; } /** * 补齐有效期 */ private void fillExpiringDateAbsent(CompanyFileVo file) { LocalDate expiringDate = file.getExpiringDate(); if (expiringDate == null) { LocalDate applyDate = file.getApplyDate(); if (applyDate != null) { expiringDate = applyDate.plusYears(1); file.setExpiringDate(expiringDate); } } } private static void fillApplyDateAndExpiringDateAbsent(File file, CompanyFileVo companyFile) { LocalDate applyDate = companyFile.getApplyDate(); if (applyDate != null) { return; } String fileName = file.getName(); Pattern pattern = Pattern.compile(MyDateTimeUtils.REGEX_DATE); Matcher matcher = pattern.matcher(fileName); while (matcher.find()) { // 找到第一个日期,记作起始日期 String date = matcher.group(); try { LocalDate n = LocalDate.parse(date); companyFile.setApplyDate(n); // 如果 截至日期未设置,则第二个日期记作截至日期(如有) LocalDate expiringDate = companyFile.getExpiringDate(); if (expiringDate == null) { while (matcher.find()) { date = matcher.group(); try { n = LocalDate.parse(date); companyFile.setExpiringDate(n); break; } catch (Exception ignored) { } } } break; } catch (Exception ignored) { } } } public void verify(CompanyVo company, LocalDate verifyDate, MessageHolder holder) { // 查询公司的资信评估报告 List files = findFileByCompanyAndType(company, CompanyFileType.CreditReport); CompanyFileVo companyFile = files.stream() .filter(v -> v.getApplyDate() != null && v.getExpiringDate() != null) .filter(v -> MyDateTimeUtils.dateValidFilter(verifyDate, v.getApplyDate(), v.getExpiringDate(), 30)) .findFirst().orElse(null); if (companyFile == null) { List dates = new ArrayList<>(); files.stream() .filter(v -> v.getApplyDate() != null && !verifyDate.isBefore(v.getApplyDate())) .max(Comparator.comparing(CompanyFileVo::getApplyDate)) .map(CompanyFileVo::getApplyDate) .ifPresent(dates::add); files.stream() .filter(v -> v.getExpiringDate() != null && !verifyDate.isAfter(v.getExpiringDate())) .min(Comparator.comparing(CompanyFileVo::getApplyDate)) .map(CompanyFileVo::getApplyDate) .ifPresent(dates::add); if (dates.isEmpty()) { holder.error("未匹配到资信评估报告"); } else if (dates.size() == 1) { holder.error("未匹配到资信评估报告, 最接近日期:" + dates.getFirst()); } else { LocalDate localDate = dates.stream().max(LocalDate::compareTo).orElse(null); holder.error("未匹配到资信评估报告, 最接近日期:" + localDate); } } } private List findFileByCompanyAndType(CompanyVo company, CompanyFileType companyFileType) { return findAll(ParamUtils.builder().equals("company", company.getId()).equals("type", companyFileType).build(), Pageable.unpaged()).getContent(); } public LocalDate getNextCreditReportDate(CompanyVo company, Consumer state) { // TODO Auto-generated method stub throw new UnsupportedOperationException("Unimplemented method 'getNextCreditReportDate'"); } public void copyAsMatched(CompanyVo company, LocalDate applyDate, Consumer state) { // TODO Auto-generated method stub throw new UnsupportedOperationException("Unimplemented method 'copyAsMatched'"); } public void copyAsMatchedByContract(CompanyVo company, ObservableList list) { // TODO Auto-generated method stub throw new UnsupportedOperationException("Unimplemented method 'copyAsMatchedByContract'"); } /** * 移动文件到企业目录下 * * @param company 企业对象 * @param files 要被移动的文件集合,需要从中选择需要的 * @param holder 状态输出 */ public boolean retrieveFromDownloadFiles(CompanyVo company, File[] files, MessageHolder holder) { Map map = new HashMap<>(); File home = new File(company.getPath()); map.put(company.getName(), home); List retrieveFiles = new ArrayList<>(); List oldNames = SpringApp.getBean(CompanyOldNameService.class).findAllByCompany(company); // 获取所有曾用名 for (CompanyOldNameVo companyOldName : oldNames) { String name = companyOldName.getName(); if (!StringUtils.hasText(name)) { continue; } File dir = null; String path = companyOldName.getPath(); if (StringUtils.hasText(path)) { dir = new File(path); } map.put(name, dir); } // 对所有文件进行遍历 for (int i = 0; i < files.length; i++) { File file = files[i]; // 只处理文件 if (!file.isFile()) { continue; } MessageHolder sub = holder.sub("[" + (i + 1) + "/" + files.length + "]"); String fileName = file.getName(); sub.info(fileName); for (Map.Entry entry : map.entrySet()) { String companyName = entry.getKey(); // 必须要包含公司名称否则无法区分 if (!fileName.contains(companyName)) { continue; } // 文件存储的目的地目录 File dir = entry.getValue(); if (dir == null) { dir = home; } CompanyFileVo filled = fillDownloadFileType(company, file, companyName, dir, sub); if (filled != null) { retrieveFiles.add(filled); } } } holder.info("导入 " + retrieveFiles.size() + " 个文件"); if (retrieveFiles.isEmpty()) { return false; } // update db retrieveFiles.forEach(v -> { v.setCompanyId(company.getId()); save(v); }); return true; } /** * 从文件名生成公司文件对象 * 文件从下载目录中导入 * * @param company 公司对象 * @param file 导入的文件对象 * @param companyName 公司名称 * @param destDir 目标目录 * @param holder 状态输出 * @return 生成的公司文件对象,如果无法转换则返回null */ private CompanyFileVo fillDownloadFileType(CompanyVo company, File file, String companyName, File destDir, MessageHolder holder) { String fileName = file.getName(); // 天眼查的报告 // 目前只有 基础版企业信用报告, 企业信用信息公示报告下载保存时的文件名中没有天眼查 if (CloudTycService.isTycReport(fileName)) { CompanyFileVo companyFile = new CompanyFileVo(); companyFile.setType(CompanyFileType.CreditReport); fillApplyDateAbsent(file, companyFile); String destFileName = fileName; // 重命名 基础版企业信用报告 for (String report : Arrays.asList( CloudServiceConstant.TYC_ENTERPRISE_ANALYSIS_REPORT, CloudServiceConstant.TYC_ENTERPRISE_BASIC_REPORT, CloudServiceConstant.TYC_ENTERPRISE_MAJOR_REPORT)) { if (fileName.contains(report)) { LocalDate applyDate = companyFile.getApplyDate(); if (applyDate == null) { applyDate = LocalDate.now(); companyFile.setApplyDate(applyDate); } String formatted = MyDateTimeUtils.format(applyDate); String extension = StringUtils.getFilenameExtension(fileName); destFileName = String.format("%s_%s_%s_%s.%s", companyName, CloudServiceConstant.TYC_NAME, report, formatted, extension); } } // 重新设置 企业分析报告 未普通文件 // if (fileName.contains(CloudTycService.TYC_ENTERPRISE_ANALYSIS_REPORT)) { // companyFile.setType(General); // } File dest = new File(destDir, destFileName); // 移动文件 if (!file.renameTo(dest)) { // 移动失败时 holder.warn(fileName + " 无法移动到 " + dest.getAbsolutePath()); return null; } holder.info(fileName + " 移动到 " + dest.getAbsolutePath()); companyFile.setFilePath(dest.getAbsolutePath()); // if (companyFile.getExpiringDate() == null) { if (companyFile.getApplyDate() != null) { companyFile.setExpiringDate(companyFile.getApplyDate().plusYears(1)); } } return companyFile; } // 企业信用信息公示报告 if (fileName.contains(CloudServiceConstant.TYC_ENTERPRISE_CREDIT_REPORT)) { CompanyFileVo companyFile = new CompanyFileVo(); companyFile.setType(CompanyFileType.CreditInfoPublicityReport); fillApplyDateAbsent(file, companyFile); File dest = new File(destDir, fileName); // 移动文件 if (!file.renameTo(dest)) { if (dest.exists()) { // 尝试删除已经存在的文件 if (!dest.delete()) { holder.warn("覆盖时,无法删除已存在的文件 " + dest.getAbsolutePath()); return null; } if (file.renameTo(dest)) { List files = findByCompanyAndPath(company, dest.getAbsolutePath()); if (!files.isEmpty()) { companyFile = files.getFirst(); } } else { holder.error(fileName + " 无法覆盖到 " + dest.getAbsolutePath()); return null; } } else { holder.error(fileName + " 无法移动到 " + dest.getAbsolutePath()); return null; } } holder.info(fileName + " 移动到 " + dest.getAbsolutePath()); companyFile.setFilePath(dest.getAbsolutePath()); return companyFile; } return null; } /** * 当 ApplyDate 未设置时,尝试使用文件名中包含的日期 */ private static void fillApplyDateAbsent(File file, CompanyFileVo companyFile) { LocalDate applyDate = companyFile.getApplyDate(); if (applyDate != null) { return; } String fileName = file.getName(); // 从文件名中提取日期 LocalDate picked = MyDateTimeUtils.pickLocalDate(fileName); if (picked != null) { companyFile.setApplyDate(picked); } } }