diff --git a/client/src/main/java/com/ecep/contract/WebSocketClientTasker.java b/client/src/main/java/com/ecep/contract/WebSocketClientTasker.java index e950cdd..0eec871 100644 --- a/client/src/main/java/com/ecep/contract/WebSocketClientTasker.java +++ b/client/src/main/java/com/ecep/contract/WebSocketClientTasker.java @@ -72,10 +72,10 @@ public interface WebSocketClientTasker { webSocketService.withSession(session -> { try { session.submitTask(this, locale, args); - holder.addMessage(Level.INFO, "已提交任务到服务器: " + getTaskName()); + holder.info("已提交任务到服务器: " + getTaskName()); } catch (JsonProcessingException e) { String errorMsg = "任务提交失败: " + e.getMessage(); - holder.addMessage(Level.SEVERE, errorMsg); + holder.warn(errorMsg); throw new RuntimeException("任务提交失败: " + e.getMessage(), e); } }); diff --git a/client/src/main/java/com/ecep/contract/controller/company/CompanyWindowController.java b/client/src/main/java/com/ecep/contract/controller/company/CompanyWindowController.java index 748c6b8..e8fe9c7 100644 --- a/client/src/main/java/com/ecep/contract/controller/company/CompanyWindowController.java +++ b/client/src/main/java/com/ecep/contract/controller/company/CompanyWindowController.java @@ -75,10 +75,6 @@ public class CompanyWindowController @Autowired private CompanyService companyService; - @Autowired - private CompanyCustomerService companyCustomerService; - @Autowired - private VendorService vendorService; public BorderPane root; public TabPane tabPane; @@ -95,7 +91,7 @@ public class CompanyWindowController public Tab purchaseBillVoucherTab; public Tab otherTab; /* - + */ public TextField nameField; public TextField shortNameField; @@ -206,7 +202,8 @@ public class CompanyWindowController logger.debug("onCustomerTabShown"); } getLoadedFuture().thenAcceptAsync(company -> { - companyCustomerProperty.set(companyCustomerService.findByCompany(company)); + CompanyCustomerVo customerVo = getCachedBean(CompanyCustomerService.class).findByCompany(company); + companyCustomerProperty.set(customerVo); }).exceptionally(ex -> { UITools.showExceptionAndWait(ex.getMessage(), ex); return null; @@ -242,6 +239,7 @@ public class CompanyWindowController if (logger.isDebugEnabled()) { logger.debug("onVendorTabShown company {}", company.getName()); } + VendorService vendorService = getBean(VendorService.class); companyVendorProperty.set(vendorService.findByCompany(company)); }).exceptionally(ex -> { UITools.showExceptionAndWait(ex.getMessage(), ex); @@ -256,6 +254,7 @@ public class CompanyWindowController CompanyCompositeUpdateTasker task = new CompanyCompositeUpdateTasker(); task.setCompany(getEntity()); UITools.showTaskDialogAndWait("更新企业信息", task, null); + refresh(); } /** @@ -266,6 +265,7 @@ public class CompanyWindowController CompanyVerifyTasker task = new CompanyVerifyTasker(); task.setCompany(company); UITools.showTaskDialogAndWait("企业合规性验证", task, null); + refresh(); } public void onCompanyOpenInExplorerAction(ActionEvent event) { @@ -276,7 +276,7 @@ public class CompanyWindowController if (!StringUtils.hasText(path)) { ButtonType buttonType = UITools.showConfirmation("目录未设置", "是否创建目录").join(); if (buttonType == ButtonType.OK) { - if (companyService.makePathAbsent(company)) { + if (companyService.makePathAbsent(company, (level, message) -> setStatus(message))) { save(company); } } else { diff --git a/client/src/main/java/com/ecep/contract/controller/tab/CompanyTabSkinBase.java b/client/src/main/java/com/ecep/contract/controller/tab/CompanyTabSkinBase.java index f410d10..52844cd 100644 --- a/client/src/main/java/com/ecep/contract/controller/tab/CompanyTabSkinBase.java +++ b/client/src/main/java/com/ecep/contract/controller/tab/CompanyTabSkinBase.java @@ -8,7 +8,6 @@ import org.springframework.util.StringUtils; import com.ecep.contract.controller.company.AbstCompanyBasedTabSkin; import com.ecep.contract.controller.company.CompanyWindowController; -import com.ecep.contract.model.CompanyOldName; import com.ecep.contract.service.CompanyOldNameService; import com.ecep.contract.vo.CompanyOldNameVo; import com.ecep.contract.vo.CompanyVo; @@ -23,19 +22,16 @@ import javafx.scene.control.Tab; import javafx.scene.control.TextField; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; +import javafx.stage.DirectoryChooser; import javafx.stage.Modality; import javafx.util.converter.LocalDateStringConverter; -import lombok.Setter; /** - * + * 公司基础信息标签页皮肤 */ - public class CompanyTabSkinBase extends AbstCompanyBasedTabSkin implements TabSkin { - @Setter - private CompanyOldNameService companyOldNameService; public CompanyTabSkinBase(CompanyWindowController controller) { super(controller); @@ -49,7 +45,8 @@ public class CompanyTabSkinBase @Override public void initializeTab() { - LocalDateStringConverter localDateStringConverter = new LocalDateStringConverter(DateTimeFormatter.ISO_LOCAL_DATE, null); + LocalDateStringConverter localDateStringConverter = new LocalDateStringConverter( + DateTimeFormatter.ISO_LOCAL_DATE, null); controller.nameField.textProperty().bind(viewModel.getName()); controller.shortNameField.textProperty().bindBidirectional(viewModel.getShortName()); @@ -70,7 +67,8 @@ public class CompanyTabSkinBase controller.regAddressField.textProperty().bindBidirectional(viewModel.getRegAddress()); controller.addressField.textProperty().bindBidirectional(viewModel.getAddress()); controller.registeredCapitalField.textProperty().bindBidirectional(viewModel.getRegisteredCapital()); - controller.registeredCapitalCurrencyField.textProperty().bindBidirectional(viewModel.getRegisteredCapitalCurrency()); + controller.registeredCapitalCurrencyField.textProperty() + .bindBidirectional(viewModel.getRegisteredCapitalCurrency()); controller.legalRepresentativeField.textProperty().bindBidirectional(viewModel.getLegalRepresentative()); controller.operationPeriodBeginField.setConverter(localDateStringConverter); @@ -89,7 +87,7 @@ public class CompanyTabSkinBase private void onCompanyPathCreatePathAction(ActionEvent event) { CompanyVo company = getEntity(); - if (getCompanyService().makePathAbsent(company)) { + if (getCompanyService().makePathAbsent(company, ((level, message) -> setStatus(message)))) { save(company); } else { setStatus("目录存在或创建失败"); @@ -97,7 +95,33 @@ public class CompanyTabSkinBase } private void onCompanyPathChangePathAction(ActionEvent event) { - + DirectoryChooser chooser = new DirectoryChooser(); + CompanyVo entity = getEntity(); + String path = entity.getPath(); + File initialDirectory = null; + + // 如果当前已经设置了目录并且路径有效,则设置初始目录为该目录 + if (StringUtils.hasText(path)) { + File dir = new File(path); + if (dir.exists()) { + initialDirectory = dir; + } + } + + // 如果没有有效的初始目录,则使用基础路径 + if (initialDirectory == null) { + initialDirectory = getCompanyService().getBasePath(); + } + + if (initialDirectory != null) { + chooser.setInitialDirectory(initialDirectory); + } + + File newDirectory = chooser.showDialog(getTab().getContent().getScene().getWindow()); + if (newDirectory != null) { + entity.setPath(newDirectory.getAbsolutePath()); + save(entity); + } } private void onCompanyPathSameAsNameAction(ActionEvent event) { @@ -150,18 +174,16 @@ public class CompanyTabSkinBase layout.getChildren().addAll(nameField, nameLabel, saveAsOldName, ambiguity, ambiguityLabel); - alert.setContentText("context"); alert.setHeaderText(null); alert.setTitle("企业更名"); alert.getDialogPane().setContent(layout); -// alert.setResultConverter(param -> { -// -// return null; -// }); - + // alert.setResultConverter(param -> { + // + // return null; + // }); alert.setOnCloseRequest(dialogEvent -> { ButtonType buttonType = alert.getResult(); @@ -206,9 +228,6 @@ public class CompanyTabSkinBase } private CompanyOldNameService getCompanyOldNameService() { - if (companyOldNameService == null) { - companyOldNameService = getBean(CompanyOldNameService.class); - } - return companyOldNameService; + return getCachedBean(CompanyOldNameService.class); } } diff --git a/client/src/main/java/com/ecep/contract/controller/tab/CompanyTabSkinContract.java b/client/src/main/java/com/ecep/contract/controller/tab/CompanyTabSkinContract.java index 308ab99..5b2383c 100644 --- a/client/src/main/java/com/ecep/contract/controller/tab/CompanyTabSkinContract.java +++ b/client/src/main/java/com/ecep/contract/controller/tab/CompanyTabSkinContract.java @@ -126,18 +126,21 @@ public class CompanyTabSkinContract contractTabToolBtn1.setOnAction(event -> { CompletableFuture.runAsync(() -> { // 计算主合同编号 + ContractService contractService = getViewModelService(); for (ContractViewModel model : dataSet) { - ContractVo contract = getViewModelService().findById(model.getId().get()); + ContractVo contract = contractService.findById(model.getId().get()); if (contract == null) { continue; } try { - if (getViewModelService().updateParentCode(contract)) { - ContractVo updated = getViewModelService().save(contract); + if (contractService.updateParentCode(contract)) { + ContractVo updated = contractService.save(contract); model.update(updated); } } catch (NoSuchElementException e) { model.getParentCode().set(e.getMessage()); + } catch (Exception e) { + setStatus("计算主合同编号失败 " + e.getMessage()); } } }); diff --git a/client/src/main/java/com/ecep/contract/controller/tab/CompanyTabSkinFile.java b/client/src/main/java/com/ecep/contract/controller/tab/CompanyTabSkinFile.java index d337884..74023f8 100644 --- a/client/src/main/java/com/ecep/contract/controller/tab/CompanyTabSkinFile.java +++ b/client/src/main/java/com/ecep/contract/controller/tab/CompanyTabSkinFile.java @@ -6,36 +6,31 @@ import java.time.LocalDate; import java.util.List; import java.util.function.Consumer; -import com.ecep.contract.service.CompanyFileTypeService; -import com.ecep.contract.service.ContractFileTypeService; -import com.ecep.contract.vo.CompanyFileTypeLocalVo; -import com.ecep.contract.vo.CompanyFileVo; -import com.ecep.contract.vo.CompanyVo; import org.springframework.util.FileSystemUtils; import org.springframework.util.StringUtils; import com.ecep.contract.CompanyFileType; import com.ecep.contract.DesktopUtils; import com.ecep.contract.MyDateTimeUtils; -import com.ecep.contract.MyProperties; import com.ecep.contract.constant.CloudServiceConstant; import com.ecep.contract.controller.company.AbstCompanyTableTabSkin; import com.ecep.contract.controller.company.CompanyWindowController; import com.ecep.contract.controller.table.EditableEntityTableTabSkin; import com.ecep.contract.controller.table.cell.CompanyFilePathTableCell; -import com.ecep.contract.model.Company; -import com.ecep.contract.model.CompanyFile; -import com.ecep.contract.model.CompanyFileTypeLocal; +import com.ecep.contract.controller.table.cell.CompanyFileTypeTableCell; import com.ecep.contract.service.CloudTycService; import com.ecep.contract.service.CompanyFileService; +import com.ecep.contract.service.CompanyFileTypeService; +import com.ecep.contract.task.CompanyFileMoveTasker; +import com.ecep.contract.task.CompanyFileResetTasker; +import com.ecep.contract.task.CompanyFileRetrieveFromDownloadDirTasker; import com.ecep.contract.util.FxmlPath; import com.ecep.contract.util.UITools; import com.ecep.contract.vm.CompanyFileViewModel; +import com.ecep.contract.vo.CompanyFileVo; +import com.ecep.contract.vo.CompanyVo; import javafx.application.Platform; -import javafx.beans.binding.Bindings; -import javafx.collections.FXCollections; -import javafx.collections.ObservableMap; import javafx.event.ActionEvent; import javafx.event.Event; import javafx.scene.control.Button; @@ -53,7 +48,7 @@ public class CompanyTabSkinFile implements TabSkin, EditableEntityTableTabSkin { public TableColumn idColumn; - public TableColumn typeColumn; + public TableColumn typeColumn; public TableColumn filePathColumn; public TableColumn applyDateColumn; public TableColumn expiringDateColumn; @@ -65,9 +60,6 @@ public class CompanyTabSkinFile public MenuItem fileTable_menu_del; public MenuItem fileTable_menu_copy_as_matched_by_contract; - private final ObservableMap fileTypeLocalMap = FXCollections - .observableHashMap(); - public CompanyTabSkinFile(CompanyWindowController controller) { super(controller); setDragAndDrop(true); @@ -96,10 +88,12 @@ public class CompanyTabSkinFile idColumn.setCellValueFactory(param -> param.getValue().getId()); - typeColumn.setCellValueFactory(param -> Bindings.valueAt(fileTypeLocalMap, param.getValue().getType()) - .map(CompanyFileTypeLocalVo::getValue)); + typeColumn.setCellValueFactory(param -> param.getValue().getType()); + typeColumn.setCellFactory(CompanyFileTypeTableCell.forTableColumn(getCachedBean(CompanyFileTypeService.class))); + filePathColumn.setCellValueFactory(param -> param.getValue().getFilePath()); filePathColumn.setCellFactory(param -> new CompanyFilePathTableCell<>(viewModel.getPath())); + applyDateColumn.setCellValueFactory(param -> param.getValue().getApplyDate()); expiringDateColumn.setCellValueFactory(param -> param.getValue().getExpiringDate()); @@ -107,85 +101,39 @@ public class CompanyTabSkinFile fileTable_menu_del.setOnAction(this::onTableDeleteAction); fileTable_menu_copy_as_matched_by_contract.setOnAction(this::onTableCopyAsMatchedByContractAction); fileTable_menu_copy_as_matched_by_contract.setOnMenuValidation(this::onTableCopyAsMatchedMenuValidation); - - fileTypeLocalMap.putAll(getCachedBean(CompanyFileTypeService.class).findAll(getLocale())); } private void onTableResetAction(ActionEvent event) { - runAsync(() -> { - if (getViewModelService().reBuildingFiles(getParent(), (level, msg) -> setStatus(msg))) { - loadTableDataSet(); - } - }); + // 创建本地任务 + CompanyFileResetTasker tasker = new CompanyFileResetTasker(); + tasker.setCompany(getParent()); + UITools.showTaskDialogAndWait("重置公司文件", tasker, null); + if (tasker.isFilesUpdated()) { + loadTableDataSet(); + } } /** * 从 下载目录 中查找相关的资质文件 */ private void onTableRetrieveFromDownloadDirAction(ActionEvent event) { - CompanyVo company = getParent(); - MyProperties myProperties = getBean(MyProperties.class); - File dir = myProperties.getDownloadDirectory(); - if (!dir.exists()) { - setStatus("下载目录 " + dir.getAbsolutePath() + " 不存在,请检查"); - return; - } - - setStatus("开始检索 下载 文件夹:" + dir.getAbsolutePath() + "..."); - File[] files = dir.listFiles(File::isFile); - if (files == null) { - setStatus("检索 下载 文件夹失败"); - return; - } - if (files.length == 0) { - setStatus("下载 文件夹没有文件"); - return; - } - setStatus("下载 文件夹中共有文件 " + files.length + " 个文件"); - - if (getParentService().retrieveFromDownloadFiles(company, files, (level, msg) -> setStatus(msg))) { - // fixed if update - viewModel.update(company); - loadTableDataSet(); - } + // 创建本地任务 + CompanyFileRetrieveFromDownloadDirTasker tasker = new CompanyFileRetrieveFromDownloadDirTasker(); + tasker.setCompany(getEntity()); + UITools.showTaskDialogAndWait("从下载目录检索文件", tasker, null); + loadTableDataSet(); } /** * 把文件从 老系统中移到 \\10.84.209.8\项目信息\相关方信息 目录中 */ private void onTableMoveFileAction(ActionEvent event) { - CompanyFileService companyFileService = getCompanyFileService(); - CompanyVo company = getParent(); - List list = companyFileService.findByCompany(company); - if (list.isEmpty()) { - return; - } - if (getParentService().makePathAbsent(company)) { - save(company); - } - - String path = company.getPath(); - if (!StringUtils.hasText(path)) { - setStatus("异常, 企业目录未设置"); - return; - } - File companyPath = new File(path); - for (CompanyFileVo companyFile : list) { - String filePath = companyFile.getFilePath(); - if (StringUtils.hasText(filePath)) { - File file = new File(filePath); - if (file.exists()) { - if (file.getParentFile().equals(companyPath)) { - continue; - } - File dest = new File(companyPath, file.getName()); - if (file.renameTo(dest)) { - companyFile.setFilePath(dest.getAbsolutePath()); - companyFileService.save(companyFile); - setStatus(file.getName() + " 移动到 " + companyPath.getName()); - } - } - } + // 创建本地任务 + CompanyFileMoveTasker tasker = new CompanyFileMoveTasker(); + tasker.setCompany(getParent()); + UITools.showTaskDialogAndWait("移动公司文件", tasker, null); + if (tasker.isFilesMoved()) { + loadTableDataSet(); } } @@ -195,7 +143,6 @@ public class CompanyTabSkinFile private void onTableCopyAsMatchedByContractAction(ActionEvent event) { UITools.showDialogAndWait("复制资信评估报告", "按当前评估报告复制一个合同中最匹配的", list -> { getViewModelService().copyAsMatchedByContract(getParent(), list); - onTableCopyAsMatchedAction_(msg -> { Platform.runLater(() -> { list.add(msg); diff --git a/client/src/main/java/com/ecep/contract/controller/table/cell/CompanyFileTypeTableCell.java b/client/src/main/java/com/ecep/contract/controller/table/cell/CompanyFileTypeTableCell.java new file mode 100644 index 0000000..5458eff --- /dev/null +++ b/client/src/main/java/com/ecep/contract/controller/table/cell/CompanyFileTypeTableCell.java @@ -0,0 +1,86 @@ +package com.ecep.contract.controller.table.cell; + +import com.ecep.contract.CompanyFileType; +import com.ecep.contract.SpringApp; +import com.ecep.contract.service.CompanyFileTypeService; +import com.ecep.contract.vo.CompanyFileTypeLocalVo; +import javafx.scene.control.TableCell; +import javafx.scene.control.TableColumn; +import javafx.util.Callback; + +/** + * 公司文件类型单元格,用于在表格中显示公司文件类型信息 + */ +public class CompanyFileTypeTableCell extends AsyncUpdateTableCell { + private CompanyFileTypeService companyFileTypeService; + + /** + * 创建一个用于表格列的单元格工厂 + */ + public static Callback, TableCell> forTableColumn( + CompanyFileTypeService service) { + return param -> new CompanyFileTypeTableCell<>(service); + } + + public CompanyFileTypeTableCell() { + } + + public CompanyFileTypeTableCell(CompanyFileTypeService service) { + setService(service); + } + + @Override + protected CompanyFileTypeService getServiceBean() { + if (companyFileTypeService == null) { + companyFileTypeService = SpringApp.getBean(CompanyFileTypeService.class); + } + return companyFileTypeService; + } + + @Override + protected CompanyFileTypeLocalVo initialize() { + CompanyFileType item = getItem(); + if (item == null) { + return null; + } + return getServiceBean().findByLocaleAndType(com.ecep.contract.Desktop.instance.getActiveEmployee().localeProperty().get(), item); + } + + @Override + public String format(CompanyFileTypeLocalVo entity) { + if (entity != null && entity.getValue() != null) { + return entity.getValue(); + } + CompanyFileType item = getItem(); + if (item != null) { + // 根据枚举值返回对应的中文名称 + switch (item) { + case General -> { + return "普通文件"; + } + case CreditReport -> { + return "资信评估报告"; + } + case BusinessLicense -> { + return "营业执照"; + } + case QualificationCertificate -> { + return "资质证书"; + } + case CreditInfoPublicityReport -> { + return "企业信用信息公示报告"; + } + case OperationCertificate -> { + return "操作证"; + } + case FrameworkAgreement -> { + return "框架协议"; + } + default -> { + return item.name(); + } + } + } + return "未知类型"; + } +} \ No newline at end of file diff --git a/client/src/main/java/com/ecep/contract/serializer/ProxyObjectDeserializerModifier.java b/client/src/main/java/com/ecep/contract/serializer/ProxyObjectDeserializerModifier.java index 189e35f..f9929f2 100644 --- a/client/src/main/java/com/ecep/contract/serializer/ProxyObjectDeserializerModifier.java +++ b/client/src/main/java/com/ecep/contract/serializer/ProxyObjectDeserializerModifier.java @@ -24,6 +24,7 @@ public class ProxyObjectDeserializerModifier extends BeanDeserializerModifier { } @Override + @SuppressWarnings("unchecked") public JsonDeserializer modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer deserializer) { // 检查是否是IdentityEntity的实现类 diff --git a/client/src/main/java/com/ecep/contract/service/CompanyFileService.java b/client/src/main/java/com/ecep/contract/service/CompanyFileService.java index ced6a50..ca39e3d 100644 --- a/client/src/main/java/com/ecep/contract/service/CompanyFileService.java +++ b/client/src/main/java/com/ecep/contract/service/CompanyFileService.java @@ -48,200 +48,6 @@ public class CompanyFileService extends QueryService 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); @@ -295,197 +101,4 @@ public class CompanyFileService extends QueryService 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); - } - } } diff --git a/client/src/main/java/com/ecep/contract/service/CompanyService.java b/client/src/main/java/com/ecep/contract/service/CompanyService.java index 3652718..74cfbb3 100644 --- a/client/src/main/java/com/ecep/contract/service/CompanyService.java +++ b/client/src/main/java/com/ecep/contract/service/CompanyService.java @@ -6,7 +6,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import javafx.util.StringConverter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.Cacheable; @@ -16,13 +15,13 @@ import org.springframework.util.StringUtils; import com.ecep.contract.MessageHolder; import com.ecep.contract.MyDateTimeUtils; -import com.ecep.contract.SpringApp; import com.ecep.contract.constant.CompanyConstant; -import com.ecep.contract.model.Company; import com.ecep.contract.util.FileUtils; import com.ecep.contract.vm.CompanyViewModel; import com.ecep.contract.vo.CompanyVo; +import javafx.util.StringConverter; + @Service @CacheConfig(cacheNames = "company") public class CompanyService extends QueryService { @@ -117,20 +116,22 @@ public class CompanyService extends QueryService { } } - public boolean makePathAbsent(CompanyVo company) { + public boolean makePathAbsent(CompanyVo company, MessageHolder holder) { String path = company.getPath(); if (StringUtils.hasText(path)) { File file = new File(path); if (file.exists()) { + // holder.error("存储目录已存在,请检查:" + file.getAbsolutePath()); return false; } } - File dir = makePath(company); + File dir = makePath(company, holder.sub("父级")); if (dir == null) { return false; } if (!dir.exists()) { + holder.info("父级目录不存在:" + dir.getAbsolutePath()); return false; } company.setPath(dir.getAbsolutePath()); @@ -144,71 +145,39 @@ public class CompanyService extends QueryService { * @param company 要创建的企业对象 * @return 目录 */ - public File makePath(CompanyVo company) { + public File makePath(CompanyVo company, MessageHolder holder) { File basePath = getBasePath(); if (!basePath.exists()) { + holder.error("存储目录不存在:" + basePath.getAbsolutePath()); return null; } String companyName = company.getName(); String district = company.getDistrict(); - if (StringUtils.hasText(district)) { - String parentPrefix = FileUtils.getParentPrefixByDistrict(district); - if (parentPrefix != null) { - File parent = new File(basePath, parentPrefix); - if (!parent.exists()) { - if (!parent.mkdir()) { - return null; - } - } - String fileName = FileUtils.escapeFileName(companyName); - File dir = new File(parent, fileName); - if (!dir.exists()) { - if (!dir.mkdir()) { - return null; - } - } - return dir; + if (!StringUtils.hasText(district)) { + holder.error("区域异常:未设置"); + return null; + } + String parentPrefix = FileUtils.getParentPrefixByDistrict(district); + if (parentPrefix == null) { + holder.error("区域异常:" + district); + return null; + } + File parent = new File(basePath, parentPrefix); + if (!parent.exists()) { + if (!parent.mkdir()) { + holder.error("创建目录失败:" + parent.getAbsolutePath()); + return null; } } - return null; - } - - - /** - * 移动文件到企业目录下 - * - * @param company 企业对象 - * @param files 要被移动的文件集合,需要从中选择需要的 - * @param holder 状态输出 - */ - public boolean retrieveFromDownloadFiles(CompanyVo company, File[] files, MessageHolder holder) { - // - boolean companyChanged = makePathAbsent(company); - - if (!StringUtils.hasText(company.getPath())) { - // fixed 要退出,需要保存 - if (companyChanged) { - save(company); + String fileName = FileUtils.escapeFileName(companyName); + File dir = new File(parent, fileName); + if (!dir.exists()) { + if (!dir.mkdir()) { + holder.error("创建目录失败:" + dir.getAbsolutePath()); + return null; } - holder.error("存储目录未设置,请检查"); - return false; } - - File home = new File(company.getPath()); - if (!home.exists()) { - // fixed 要退出,需要保存 - if (companyChanged) { - company = save(company); - } - holder.error(company.getPath() + " 不存在,无法访问,请检查或者修改"); - return false; - } - CompanyFileService fileService = SpringApp.getBean(CompanyFileService.class); - boolean retrieved = fileService.retrieveFromDownloadFiles(company, files, holder); - if (companyChanged) { - save(company); - } - return retrieved; + return dir; } @Override diff --git a/client/src/main/java/com/ecep/contract/service/ContractService.java b/client/src/main/java/com/ecep/contract/service/ContractService.java index 0f3c93e..032b97a 100644 --- a/client/src/main/java/com/ecep/contract/service/ContractService.java +++ b/client/src/main/java/com/ecep/contract/service/ContractService.java @@ -3,6 +3,7 @@ package com.ecep.contract.service; import java.io.File; import java.time.LocalDate; import java.util.List; +import java.util.Objects; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheConfig; @@ -12,17 +13,17 @@ import org.springframework.cache.annotation.Caching; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; import com.ecep.contract.MessageHolder; import com.ecep.contract.constant.ContractConstant; +import com.ecep.contract.util.ContractUtils; import com.ecep.contract.util.ParamUtils; import com.ecep.contract.vm.ContractViewModel; -import com.ecep.contract.vo.VendorVo; import com.ecep.contract.vo.ContractFileVo; import com.ecep.contract.vo.ContractVo; import com.ecep.contract.vo.ProjectVo; - -import io.micrometer.common.util.StringUtils; +import com.ecep.contract.vo.VendorVo; @Service @CacheConfig(cacheNames = "contract") @@ -69,8 +70,21 @@ public class ContractService extends QueryService } public boolean updateParentCode(ContractVo contract) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'updateParentCode'"); + String parentCode = ContractUtils.getParentCode(contract.getCode()); + if (!StringUtils.hasText(parentCode)) { + return false; + } + // fixed + if (Objects.equals(contract.getParentCode(), parentCode)) { + // 已经相同,跳过 + return false; + } + ContractVo parent = findOneByProperty("code", parentCode); + if (parent == null) { + return false; + } + contract.setParentCode(parent.getCode()); + return true; } @Cacheable(key = "'code-'+#p0") @@ -105,7 +119,7 @@ public class ContractService extends QueryService public List findAllBySaleContract(ContractVo contract) { String parentCode = contract.getCode(); - if (StringUtils.isEmpty(parentCode)) { + if (StringUtils.hasText(parentCode)) { return List.of(); } return findAll(ParamUtils.equal("parentCode", parentCode), Pageable.unpaged()).getContent(); diff --git a/client/src/main/java/com/ecep/contract/task/CompanyCompositeUpdateTasker.java b/client/src/main/java/com/ecep/contract/task/CompanyCompositeUpdateTasker.java index 27f36a2..9170b05 100644 --- a/client/src/main/java/com/ecep/contract/task/CompanyCompositeUpdateTasker.java +++ b/client/src/main/java/com/ecep/contract/task/CompanyCompositeUpdateTasker.java @@ -4,7 +4,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.ecep.contract.MessageHolder; -import com.ecep.contract.constant.CloudServiceConstant; +import com.ecep.contract.WebSocketClientTasker; import com.ecep.contract.vo.CompanyVo; import lombok.Setter; @@ -12,7 +12,7 @@ import lombok.Setter; /** * 合并更新 */ -public class CompanyCompositeUpdateTasker extends Tasker { +public class CompanyCompositeUpdateTasker extends Tasker implements WebSocketClientTasker { private static final Logger logger = LoggerFactory.getLogger(CompanyCompositeUpdateTasker.class); @Setter private CompanyVo company; @@ -20,14 +20,17 @@ public class CompanyCompositeUpdateTasker extends Tasker { @Override protected Object execute(MessageHolder holder) throws Exception { updateTitle("合并更新 " + company.getName()); + return callRemoteTask(holder, getLocale(), company.getId()); + } - holder.debug("1. 从 " + CloudServiceConstant.RK_NAME + " 更新..."); - updateProgress(0.1, 1); - holder.debug("2. 从 " + CloudServiceConstant.U8_NAME + " 更新..."); - updateProgress(0.3, 1); - holder.debug("3. 从 " + CloudServiceConstant.TYC_NAME + " 更新..."); - updateProgress(1, 1); - return null; + @Override + public String getTaskName() { + return "CompanyCompositeUpdateTasker"; + } + + @Override + public void updateProgress(long workDone, long max) { + super.updateProgress(workDone, max); } } diff --git a/client/src/main/java/com/ecep/contract/task/CompanyFileMoveTasker.java b/client/src/main/java/com/ecep/contract/task/CompanyFileMoveTasker.java new file mode 100644 index 0000000..5e3169c --- /dev/null +++ b/client/src/main/java/com/ecep/contract/task/CompanyFileMoveTasker.java @@ -0,0 +1,123 @@ +package com.ecep.contract.task; + +import java.io.File; + +import org.springframework.util.StringUtils; + +import com.ecep.contract.MessageHolder; +import com.ecep.contract.service.CompanyFileService; +import com.ecep.contract.service.CompanyService; +import com.ecep.contract.vo.CompanyFileVo; +import com.ecep.contract.vo.CompanyVo; + +import lombok.Getter; +import lombok.Setter; + +/** + * 公司文件移动任务类 + * 用于将文件从老系统中移动到指定的企业目录中 + */ +public class CompanyFileMoveTasker extends Tasker { + @Getter + @Setter + private CompanyVo company; + + @Getter + private boolean filesMoved = false; + + @Override + protected Boolean execute(MessageHolder holder) throws Exception { + updateTitle("移动公司文件"); + updateProgress(0, 100); + + if (company == null) { + holder.error("公司对象为空"); + updateProgress(100, 100); + return false; + } + + try { + holder.info("开始移动公司文件:" + company.getName()); + updateProgress(10, 100); + + // 获取CompanyFileService + CompanyFileService companyFileService = getCachedBean(CompanyFileService.class); + CompanyService companyService = getCachedBean(CompanyService.class); + + // 获取公司的所有文件 + holder.info("获取公司文件列表..."); + java.util.List list = companyFileService.findByCompany(company); + updateProgress(20, 100); + + if (list.isEmpty()) { + holder.info("该公司没有文件需要移动"); + updateProgress(100, 100); + return false; + } + + holder.info("共有" + list.size() + "个文件需要处理"); + + // 确保公司目录存在 + holder.info("检查并创建公司目录..."); + if (companyService.makePathAbsent(company, holder)) { + company = companyService.save(company); + holder.info("公司目录已创建"); + } + updateProgress(30, 100); + + // 检查公司路径 + String path = company.getPath(); + if (!StringUtils.hasText(path)) { + holder.error("异常, 企业目录未设置"); + updateProgress(100, 100); + return false; + } + + File companyPath = new File(path); + int movedCount = 0; + int totalFiles = list.size(); + + // 逐个处理文件 + for (int i = 0; i < list.size(); i++) { + CompanyFileVo companyFile = list.get(i); + String filePath = companyFile.getFilePath(); + + // 更新进度 + updateProgress(30 + (i * 70) / totalFiles, 100); + + if (StringUtils.hasText(filePath)) { + File file = new File(filePath); + if (file.exists()) { + if (file.getParentFile().equals(companyPath)) { + holder.info("文件已在目标位置:" + file.getName()); + continue; + } + + File dest = new File(companyPath, file.getName()); + holder.info("移动文件:" + file.getName() + " -> " + companyPath.getName()); + + if (file.renameTo(dest)) { + companyFile.setFilePath(dest.getAbsolutePath()); + companyFileService.save(companyFile); + holder.info("文件移动成功:" + file.getName()); + movedCount++; + filesMoved = true; + } else { + holder.warn("文件移动失败:" + file.getName()); + } + } else { + holder.warn("文件不存在:" + filePath); + } + } + } + + holder.info("文件移动完成,成功移动" + movedCount + "个文件"); + updateProgress(100, 100); + return filesMoved; + } catch (Exception e) { + holder.error("文件移动过程中发生错误:" + e.getMessage()); + updateProgress(100, 100); + throw e; + } + } +} \ No newline at end of file diff --git a/client/src/main/java/com/ecep/contract/task/CompanyFileResetTasker.java b/client/src/main/java/com/ecep/contract/task/CompanyFileResetTasker.java new file mode 100644 index 0000000..ab4f76b --- /dev/null +++ b/client/src/main/java/com/ecep/contract/task/CompanyFileResetTasker.java @@ -0,0 +1,274 @@ +package com.ecep.contract.task; + +import java.io.File; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.springframework.util.StringUtils; + +import com.ecep.contract.CompanyFileType; +import com.ecep.contract.MessageHolder; +import com.ecep.contract.MyDateTimeUtils; +import com.ecep.contract.constant.CloudServiceConstant; +import com.ecep.contract.constant.CompanyConstant; +import com.ecep.contract.service.CompanyFileService; +import com.ecep.contract.service.CompanyOldNameService; +import com.ecep.contract.util.FileUtils; +import com.ecep.contract.vo.CompanyFileVo; +import com.ecep.contract.vo.CompanyOldNameVo; +import com.ecep.contract.vo.CompanyVo; + +import lombok.Getter; +import lombok.Setter; + +/** + * 公司文件重置任务类 + * 用于本地执行公司文件重置操作,不通过WebSocket调用远程服务 + */ +public class CompanyFileResetTasker extends Tasker { + @Getter + @Setter + private CompanyVo company; + + @Getter + @Setter + private boolean filesUpdated = false; + + private CompanyFileService getCompanyFileService() { + return getCachedBean(CompanyFileService.class); + } + + private CompanyOldNameService getCompanyOldNameService() { + return getCachedBean(CompanyOldNameService.class); + } + + @Override + protected Boolean execute(MessageHolder holder) throws Exception { + updateTitle("重置公司文件"); + updateProgress(0, 100); + + if (company == null) { + holder.error("公司对象为空"); + updateProgress(100, 100); + return false; + } + + try { + holder.info("开始重置公司文件:" + company.getName()); + updateProgress(10, 100); + + boolean result = reBuildingFiles(company, holder); + + if (result) { + holder.info("公司文件重置成功"); + setFilesUpdated(true); + } else { + holder.info("公司文件重置完成,但没有更新任何文件"); + setFilesUpdated(false); + } + + updateProgress(100, 100); + return result; + } catch (Exception e) { + holder.error("公司文件重置失败:" + e.getMessage()); + updateProgress(100, 100); + throw e; + } + } + + public boolean reBuildingFiles(CompanyVo company, MessageHolder holder) { + CompanyFileService companyFileService = getCompanyFileService(); + boolean modfied = false; + List dbFiles = companyFileService.findByCompany(company); + holder.debug("现有 " + dbFiles.size() + " 条文件记录"); + + Map map = new HashMap<>(); + // 排除掉数据库中重复的 + for (CompanyFileVo dbFile : dbFiles) { + String filePath = dbFile.getFilePath(); + // 没有文件信息,无效记录,删除 + if (!StringUtils.hasText(filePath)) { + companyFileService.delete(dbFile); + holder.info("删除无效记录:" + filePath); + modfied = true; + continue; + } + + // 目录不存在,删除 + File dir = new File(filePath); + if (!dir.exists()) { + companyFileService.delete(dbFile); + holder.info("删除不存在目录记录:" + filePath); + modfied = true; + continue; + } + + CompanyFileVo old = map.put(filePath, dbFile); + // 目录有重复删除 + if (old != null) { + companyFileService.delete(old); + holder.info("删除重复目录记录:" + filePath); + modfied = true; + } + } + + Map directoryMap = new HashMap<>(); + + // 公司目录 + if (StringUtils.hasText(company.getPath())) { + File dir = new File(company.getPath()); + directoryMap.put(company.getName(), dir); + } + + // 获取所有曾用名 + List oldNames = getCompanyOldNameService().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; + } + holder.debug("目录 " + companyName + " 下有 " + files.length + " 个文件"); + for (File file : files) { + // 只处理文件 + if (!file.isFile() || FileUtils.isHiddenFile(file)) { + continue; + } + String filePath = file.getAbsolutePath(); + if (!map.containsKey(filePath)) { + // 未记录 + CompanyFileVo filled = fillFileType(file, holder); + filled.setCompanyId(company.getId()); + companyFileService.save(filled); + holder.info("导入 " + file.getName() + " "); + modfied = true; + } + } + } + return modfied; + } + + /** + * 从文件名生成公司文件对象,文件已经存在公司对应的存储目录下 + * + * @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) { + } + } + + } +} \ No newline at end of file diff --git a/client/src/main/java/com/ecep/contract/task/CompanyFileRetrieveFromDownloadDirTasker.java b/client/src/main/java/com/ecep/contract/task/CompanyFileRetrieveFromDownloadDirTasker.java new file mode 100644 index 0000000..0a7b393 --- /dev/null +++ b/client/src/main/java/com/ecep/contract/task/CompanyFileRetrieveFromDownloadDirTasker.java @@ -0,0 +1,306 @@ +package com.ecep.contract.task; + +import java.io.File; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +import com.ecep.contract.CompanyFileType; +import com.ecep.contract.MessageHolder; +import com.ecep.contract.MyDateTimeUtils; +import com.ecep.contract.MyProperties; +import com.ecep.contract.constant.CloudServiceConstant; +import com.ecep.contract.service.CloudTycService; +import com.ecep.contract.service.CompanyFileService; +import com.ecep.contract.service.CompanyOldNameService; +import com.ecep.contract.vo.CompanyFileVo; +import com.ecep.contract.vo.CompanyOldNameVo; +import com.ecep.contract.vo.CompanyVo; + +import lombok.Getter; +import lombok.Setter; + +/** + * 从下载目录检索公司文件的本地任务器 + * 用于在客户端本地执行从下载目录检索相关资质文件的操作 + */ +public class CompanyFileRetrieveFromDownloadDirTasker extends Tasker { + private static final Logger logger = LoggerFactory.getLogger(CompanyFileRetrieveFromDownloadDirTasker.class); + + @Getter + @Setter + private CompanyVo company; + + @Getter + @Setter + private String downloadDirPath; + @Getter + @Setter + private boolean companyPathChanged = false; + + private CompanyFileService getCompanyFileService() { + return getCachedBean(CompanyFileService.class); + } + + private CompanyOldNameService getCompanyOldNameService() { + return getCachedBean(CompanyOldNameService.class); + } + + @Override + protected Object execute(MessageHolder holder) throws Exception { + updateTitle("从下载目录检索文件"); + + // 获取下载目录 + File dir; + if (StringUtils.hasText(downloadDirPath)) { + dir = new File(downloadDirPath); + } else { + // 如果没有提供下载目录,则使用配置中的 + MyProperties myProperties = getBean(MyProperties.class); + dir = myProperties.getDownloadDirectory(); + } + + // 检查下载目录是否存在 + if (!dir.exists()) { + String errorMsg = "下载目录 " + dir.getAbsolutePath() + " 不存在,请检查"; + holder.warn(errorMsg); + return false; + } + + // 开始检索下载文件夹 + holder.info("开始检索 下载 文件夹:" + dir.getAbsolutePath() + "..."); + File[] files = dir.listFiles(File::isFile); + + // 检查检索是否成功 + if (files == null) { + String errorMsg = "检索 下载 文件夹失败"; + holder.error(errorMsg); + return false; + } + + // 检查文件夹是否有文件 + if (files.length == 0) { + String errorMsg = "下载 文件夹没有文件"; + holder.info(errorMsg); + return false; + } + + // 报告文件夹中的文件数量 + holder.info("下载 文件夹中共有文件 " + files.length + " 个文件"); + updateProgress(20, 100); + // + companyPathChanged = getCompanyService().makePathAbsent(company, holder); + if (companyPathChanged) { + holder.info("企业目录已创建或更新:" + company.getPath()); + company = getCompanyService().save(company); + } + updateProgress(25, 100); + + // 检查企业目录是否存在 + if (!StringUtils.hasText(company.getPath())) { + holder.error("企业存储目录未设置,请检查"); + return false; + } + + // 检查企业目录是否存在 + File home = new File(company.getPath()); + if (!home.exists()) { + holder.error(company.getPath() + " 不存在,无法访问,请检查或者修改"); + return false; + } + + // 获取所有曾用名 + List oldNames = getCompanyOldNameService().findAllByCompany(company); + holder.info("企业曾用名共有 " + oldNames.size() + " 个"); + + // 按照 企业名字 移动到对应的曾用名目录 + Map oldNameOfDir = new HashMap<>(); + oldNameOfDir.put(company.getName(), home); + toMap(oldNames, oldNameOfDir); + updateProgress(30, 100); + + // 执行文件检索操作 + for (int i = 0; i < files.length; i++) { + + updateProgress(30 + (i * 50) / files.length, 100); + + File file = files[i]; + // 只处理文件 + if (!file.isFile()) { + continue; + } + + MessageHolder sub = holder.sub("[" + (i + 1) + "/" + files.length + "]"); + String fileName = file.getName(); + + for (Map.Entry entry : oldNameOfDir.entrySet()) { + String companyName = entry.getKey(); + // 必须要包含公司名称否则无法区分 + if (!fileName.contains(companyName)) { + sub.debug(fileName); + continue; + } + + // 文件存储的目的地目录 + File destPath = entry.getValue(); + if (destPath == null) { + destPath = home; + } + sub.info(fileName + " -> " + destPath); + + CompanyFileVo filled = fillDownloadFileType(company, file, companyName, destPath, sub); + if (filled != null) { + filled.setCompanyId(company.getId()); + getCompanyFileService().save(filled); + holder.info("导入 " + fileName + " 到 " + destPath.getAbsolutePath()); + } + } + } + + updateProgress(100, 100); + return null; + } + + void toMap(List oldNames, Map oldNameOfDir) { + for (CompanyOldNameVo oldName : oldNames) { + String name = oldName.getName(); + if (!StringUtils.hasText(name)) { + continue; + } + File dir = null; + String path = oldName.getPath(); + if (StringUtils.hasText(path)) { + dir = new File(path); + } + oldNameOfDir.put(name, dir); + } + } + + /** + * 从文件名生成公司文件对象 + * 文件从下载目录中导入 + * + * @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 = getCompanyFileService().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); + } + } + +} \ No newline at end of file diff --git a/client/src/main/java/com/ecep/contract/task/CompanyVerifyTasker.java b/client/src/main/java/com/ecep/contract/task/CompanyVerifyTasker.java index f3adb37..8a6cf78 100644 --- a/client/src/main/java/com/ecep/contract/task/CompanyVerifyTasker.java +++ b/client/src/main/java/com/ecep/contract/task/CompanyVerifyTasker.java @@ -1,20 +1,35 @@ package com.ecep.contract.task; import com.ecep.contract.MessageHolder; +import com.ecep.contract.WebSocketClientTasker; import com.ecep.contract.vo.CompanyVo; import lombok.Getter; import lombok.Setter; -public class CompanyVerifyTasker extends Tasker { +public class CompanyVerifyTasker extends Tasker implements WebSocketClientTasker { @Getter @Setter private CompanyVo company; + @Getter + @Setter + boolean passed = false; + @Override protected Object execute(MessageHolder holder) throws Exception { updateTitle("验证企业是否符合合规要求"); - return null; + return callRemoteTask(holder, getLocale(), company.getId()); + } + + @Override + public String getTaskName() { + return "CompanyVerifyTasker"; + } + + @Override + public void updateProgress(long workDone, long max) { + super.updateProgress(workDone, max); } } diff --git a/client/src/main/java/com/ecep/contract/task/Tasker.java b/client/src/main/java/com/ecep/contract/task/Tasker.java index 3410bf3..e1867b2 100644 --- a/client/src/main/java/com/ecep/contract/task/Tasker.java +++ b/client/src/main/java/com/ecep/contract/task/Tasker.java @@ -50,7 +50,7 @@ public abstract class Tasker extends Task { @SuppressWarnings("unchecked") K bean = (K) cachedMap.get(requiredType); if (bean == null) { - bean = getBean(requiredType); + bean = SpringApp.getBean(requiredType); cachedMap.put(requiredType, bean); } return bean; diff --git a/common/src/main/java/com/ecep/contract/util/ContractUtils.java b/common/src/main/java/com/ecep/contract/util/ContractUtils.java new file mode 100644 index 0000000..0bee02c --- /dev/null +++ b/common/src/main/java/com/ecep/contract/util/ContractUtils.java @@ -0,0 +1,28 @@ +package com.ecep.contract.util; + +import org.springframework.util.StringUtils; + +import com.ecep.contract.vo.ContractVo; + +public class ContractUtils { + /** + * 检查合同代码是否是子合同代码 + * + * @param code 合同代码 + * @return 是否是子合同代码 + */ + public static boolean isSubContractCode(String code) { + return StringUtils.hasText(code) && code.contains("-"); + } + + public static String getParentCode(String code) { + if (!isSubContractCode(code)) { + return null; + } + int index = code.indexOf("-"); + if (index <= 4) { + return null; + } + return code.substring(0, index); + } +} diff --git a/docs/task/voable_service_implementation_analysis.md b/docs/task/voable_service_implementation_analysis.md index 45443eb..afa03b7 100644 --- a/docs/task/voable_service_implementation_analysis.md +++ b/docs/task/voable_service_implementation_analysis.md @@ -113,49 +113,49 @@ 经过检查,以下Service已经实现了`VoableService`接口: -| Service名称 | 实现接口 | 实现方法 | 方法实现内容 | 导入包情况 | +| Service名称 | 实现接口 | 实现方法 | 导入包 | 备注 | |------------|------------|------------|------------|------------| -| ContractService | ✅ | ✅ | 将ContractVo对象的属性映射到Contract实体对象中 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractVo`包 | -| CompanyService | ✅ | ✅ | 将CompanyVo的15个属性(name、shortName、uniscid、legalRepresentative等)映射到Company实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.CompanyVo`包 | -| CompanyCustomerService | ✅ | ✅ | 将CompanyCustomerVo的属性映射到CompanyCustomer实体,并处理了customerCatalogId的关联查询 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.CompanyCustomerVo`包 | -| ProjectService | ✅ | ✅ | 将ProjectVo的12个属性映射到Project实体,并处理了多个关联对象(项目类型、销售类型等)的查询逻辑 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ProjectVo`包 | -| VendorService | ✅ | ✅ | 将VendorVo的属性(type、protocolProvider、developDate等)映射到Vendor实体,并处理了catalog和contact的关联查询 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.VendorVo`包 | -| BankService | ✅ | ✅ | 将BankVo的code和name属性映射到Bank实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.BankVo`包 | -| DepartmentService | ✅ | ✅ | 将DepartmentVo的code、name、active属性映射到Department实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.DepartmentVo`包 | -| EmployeeService | ✅ | ✅ | 将EmployeeVo的10个属性映射到Employee实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.EmployeeVo`包 | -| FunctionService | ✅ | ✅ | 将FunctionVo的code、name、icon等属性映射到Function实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.FunctionVo`包 | -| ProjectCostItemService | ✅ | ✅ | 将ProjectCostItemVo的属性映射到ProjectCostItem实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ProjectCostItemVo`包 | -| EmployeeRoleService | ✅ | ✅ | 将EmployeeRoleVo的name、code、description等属性映射到EmployeeRole实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.EmployeeRoleVo`包 | -| PermissionService | ✅ | ✅ | 将PermissionVo的name、code、description等属性映射到Permission实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.PermissionVo`包 | -| ProductTypeService | ✅ | ✅ | 将ProductTypeVo的name、code、description等属性映射到ProductType实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ProductTypeVo`包 | -| ProjectFundPlanService | ✅ | ✅ | 将ProjectFundPlanVo的projectId、planDate、amount等属性映射到ProjectFundPlan实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ProjectFundPlanVo`包 | -| ProjectIndustryService | ✅ | ✅ | 将ProjectIndustryVo的name、code等属性映射到ProjectIndustry实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ProjectIndustryVo`包 | -| ProjectSaleTypeService | ✅ | ✅ | 将ProjectSaleTypeVo的name、code等属性映射到ProjectSaleType实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ProjectSaleTypeVo`包 | -| ProjectTypeService | ✅ | ✅ | 将ProjectTypeVo的name、code等属性映射到ProjectType实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ProjectTypeVo`包 | -| ProductUsageService | ✅ | ✅ | 将ProductUsageVo的name、code等属性映射到ProductUsage实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ProductUsageVo`包 | -| CustomerSatisfactionSurveyService | ✅ | ✅ | 将CustomerSatisfactionSurveyVo的customerId、projectId、score等属性映射到CustomerSatisfactionSurvey实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.CustomerSatisfactionSurveyVo`包 | -| InventoryService | ✅ | ✅ | 将InventoryVo的productName、productType、quantity等属性映射到Inventory实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.InventoryVo`包 | -| InventoryHistoryPriceService | ✅ | ✅ | 将InventoryHistoryPriceVo的inventoryId、price、changeDate等属性映射到InventoryHistoryPrice实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.InventoryHistoryPriceVo`包 | -| SalesBillVoucherService | ✅ | ✅ | 将SalesBillVoucherVo的refId、code、makerDate、modifyDate、verifierDate、description等属性映射到SalesBillVoucher实体,并正确处理company、order、employee、maker、verifier等关联实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.SalesBillVoucherVo`包 | -| ExtendVendorInfoService | ✅ | ✅ | 将ExtendVendorInfoVo的codeSequenceNumber、assignedProvider、prePurchase等属性映射到ExtendVendorInfo实体,并正确处理contract、group等关联实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ExtendVendorInfoVo`包 | -| ContractItemService | ✅ | ✅ | 将ContractItemVo的基本属性映射到ContractItem实体,并正确处理contract、inventory、creator、updater等关联实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractItemVo`包 | -| ContractTypeService | ✅ | ✅ | 将ContractTypeVo的name、code、catalog、title、direction等属性映射到ContractType实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractTypeVo`包 | -| ContractFileTypeService | ✅ | ✅ | 将ContractFileTypeLocalVo的id、lang、type、value、description、suggestFileName等属性映射到ContractFileTypeLocal实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractFileTypeLocalVo`包 | -| SaleOrdersService | ✅ | ✅ | 将SalesOrderVo的code、makerDate、verifierDate、description等属性映射到SalesOrder实体,并正确处理contract、employee、maker、verifier等关联实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.SalesOrderVo`包 | -| ContractKindService | ✅ | ✅ | 将ContractKindVo的name、code、title等属性映射到ContractKind实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractKindVo`包 | -| ContractBidVendorService | ✅ | ✅ | 已正确处理contract、company、quotationSheet等关联实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractBidVendorVo`包 | -| ContractPayPlanService | ✅ | ✅ | 将ContractPayPlanVo的refId、payRatio、payCurrency、payDate、payTerm等属性映射到ContractPayPlan实体,并正确处理contract关联实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractPayPlanVo`包 | -| PurchaseBillVoucherService | ✅ | ✅ | 将PurchaseBillVoucherVo的id、refId、code、companyId、invoiceId、employeeId、makerId、makerDate、modifyDate、verifierId、verifierDate、description等属性映射到PurchaseBillVoucher实体,并正确处理company、invoice、employee、maker、verifier等关联实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.PurchaseBillVoucherVo`包 | -| PurchaseOrderItemService | ✅ | ✅ | 将PurchaseOrderItemVo的id、code、name、quantity、price等属性映射到PurchaseOrderItem实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.PurchaseOrderItemVo`包 | -| SalesOrderItemService | ✅ | ✅ | 将SalesOrderItemVo的id、code、name、quantity、price等属性映射到SalesOrderItem实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.SalesOrderItemVo`包 | -| CompanyBlackReasonService | ✅ | ✅ | 将CompanyBlackReasonVo的companyId、reason、startDate等属性映射到CompanyBlackReason实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.CompanyBlackReasonVo`包 | -| CompanyCustomerEntityService | ✅ | ✅ | 将CompanyCustomerEntityVo的name、abbName、code等基本属性映射到CompanyCustomerEntity实体,并正确处理customer、catalog、creator、modifier等关联实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.CompanyCustomerEntityVo`包 | -| CompanyFileTypeService | ✅ | ✅ | 将CompanyFileTypeVo的name、code、description等属性映射到CompanyFileType实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.CompanyFileTypeVo`包 | -| CompanyOldNameService | ✅ | ✅ | 将CompanyOldNameVo的companyId、name、beginDate、endDate等属性映射到CompanyOldName实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.CompanyOldNameVo`包 | -| PurchaseBillVoucherItemService | ✅ | ✅ | 将PurchaseBillVoucherItemVo的id、refId、quantity、price等属性映射到PurchaseBillVoucherItem实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.PurchaseBillVoucherItemVo`包 | -| ContractFileService | ✅ | ✅ | 将ContractFileVo的id、contractId、type、fileName、applyDate、description等属性映射到ContractFile实体,并正确处理contract关联实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractFileVo`包 | -| ContractCatalogService | ✅ | ✅ | 将ContractCatalogVo的id、code、name、path、parent、useYear等属性映射到ContractCatalog实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractCatalogVo`包 | -| ContractGroupService | ✅ | ✅ | 将ContractGroupVo的id、name、code、title等属性映射到ContractGroup实体 | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractGroupVo`包 | +| ContractService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractVo`包 | +| CompanyService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.CompanyVo`包 | +| CompanyCustomerService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.CompanyCustomerVo`包 | +| ProjectService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ProjectVo`包 | +| VendorService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.VendorVo`包 | +| BankService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.BankVo`包 | +| DepartmentService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.DepartmentVo`包 | +| EmployeeService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.EmployeeVo`包 | +| FunctionService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.FunctionVo`包 | +| ProjectCostItemService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ProjectCostItemVo`包 | +| EmployeeRoleService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.EmployeeRoleVo`包 | +| PermissionService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.PermissionVo`包 | +| ProductTypeService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ProductTypeVo`包 | +| ProjectFundPlanService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ProjectFundPlanVo`包 | +| ProjectIndustryService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ProjectIndustryVo`包 | +| ProjectSaleTypeService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ProjectSaleTypeVo`包 | +| ProjectTypeService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ProjectTypeVo`包 | +| ProductUsageService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ProductUsageVo`包 | +| CustomerSatisfactionSurveyService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.CustomerSatisfactionSurveyVo`包 | +| InventoryService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.InventoryVo`包 | +| InventoryHistoryPriceService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.InventoryHistoryPriceVo`包 | +| SalesBillVoucherService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.SalesBillVoucherVo`包 | +| ExtendVendorInfoService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ExtendVendorInfoVo`包 | +| ContractItemService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractItemVo`包 | +| ContractTypeService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractTypeVo`包 | +| ContractFileTypeService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractFileTypeLocalVo`包 | +| SaleOrdersService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.SalesOrderVo`包 | +| ContractKindService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractKindVo`包 | +| ContractBidVendorService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractBidVendorVo`包 | +| ContractPayPlanService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractPayPlanVo`包 | +| PurchaseBillVoucherService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.PurchaseBillVoucherVo`包 | +| PurchaseOrderItemService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.PurchaseOrderItemVo`包 | +| SalesOrderItemService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.SalesOrderItemVo`包 | +| CompanyBlackReasonService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.CompanyBlackReasonVo`包 | +| CompanyCustomerEntityService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.CompanyCustomerEntityVo`包 | +| CompanyFileTypeService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.CompanyFileTypeVo`包 | +| CompanyOldNameService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.CompanyOldNameVo`包 | +| PurchaseBillVoucherItemService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.PurchaseBillVoucherItemVo`包 | +| ContractFileService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractFileVo`包 | +| ContractCatalogService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractCatalogVo`包 | +| ContractGroupService | ✅ | ✅ | ✅ | 已正确导入`com.ecep.contract.service.VoableService`和`com.ecep.contract.vo.ContractGroupVo`包 | ## 已完成的全部实现 diff --git a/server/src/main/java/com/ecep/contract/ds/company/service/CompanyFileService.java b/server/src/main/java/com/ecep/contract/ds/company/service/CompanyFileService.java index 8e7b376..f4aba8e 100644 --- a/server/src/main/java/com/ecep/contract/ds/company/service/CompanyFileService.java +++ b/server/src/main/java/com/ecep/contract/ds/company/service/CompanyFileService.java @@ -27,6 +27,7 @@ import org.springframework.util.StringUtils; import com.ecep.contract.CompanyFileType; import com.ecep.contract.IEntityService; +import com.ecep.contract.MessageHolder; import com.ecep.contract.MyDateTimeUtils; import com.ecep.contract.QueryService; import com.ecep.contract.SpringApp; @@ -148,10 +149,11 @@ public class CompanyFileService * @see CompanyFile * @see CompanyFileType */ - public void verify(Company company, LocalDate verifyDate, Consumer status) { + public boolean verify(Company company, LocalDate verifyDate, MessageHolder holder) { if (verifyDate.isBefore(LocalDate.of(2023, 1, 1))) { // 不检查2023-01-01之前的资信评估报告 - return; + holder.warn(company.getName() + " 2023-01-01 前不检查资信评估报告"); + return true; } // 查询公司的资信评估报告 @@ -160,30 +162,33 @@ public class CompanyFileService .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(CompanyFile::getApplyDate)) - .map(CompanyFile::getApplyDate) - .ifPresent(dates::add); - - files.stream() - .filter(v -> v.getExpiringDate() != null && !verifyDate.isAfter(v.getExpiringDate())) - .min(Comparator.comparing(CompanyFile::getApplyDate)) - .map(CompanyFile::getApplyDate) - .ifPresent(dates::add); - - if (dates.isEmpty()) { - status.accept("未匹配到资信评估报告"); - } else if (dates.size() == 1) { - status.accept("未匹配到资信评估报告, 最接近日期:" + dates.getFirst()); - } else { - LocalDate localDate = dates.stream().max(LocalDate::compareTo).orElse(null); - status.accept("未匹配到资信评估报告, 最接近日期:" + localDate); - } + if (companyFile != null) { + holder.info(" 在 " + verifyDate + " 找到资信评估报告 " + companyFile.getFilePath()); + return true; } + + List dates = new ArrayList<>(); + files.stream() + .filter(v -> v.getApplyDate() != null && !verifyDate.isBefore(v.getApplyDate())) + .max(Comparator.comparing(CompanyFile::getApplyDate)) + .map(CompanyFile::getApplyDate) + .ifPresent(dates::add); + + files.stream() + .filter(v -> v.getExpiringDate() != null && !verifyDate.isAfter(v.getExpiringDate())) + .min(Comparator.comparing(CompanyFile::getApplyDate)) + .map(CompanyFile::getApplyDate) + .ifPresent(dates::add); + + if (dates.isEmpty()) { + holder.error(" 在 " + verifyDate + " 未找到资信评估报告"); + } else if (dates.size() == 1) { + holder.error("未匹配到资信评估报告, 最接近日期:" + dates.getFirst()); + } else { + LocalDate localDate = dates.stream().max(LocalDate::compareTo).orElse(null); + holder.error("未匹配到资信评估报告, 最接近日期:" + localDate); + } + return false; } /** diff --git a/server/src/main/java/com/ecep/contract/ds/company/service/CompanyService.java b/server/src/main/java/com/ecep/contract/ds/company/service/CompanyService.java index b56529c..cae2193 100644 --- a/server/src/main/java/com/ecep/contract/ds/company/service/CompanyService.java +++ b/server/src/main/java/com/ecep/contract/ds/company/service/CompanyService.java @@ -1,9 +1,6 @@ package com.ecep.contract.ds.company.service; -import com.ecep.contract.EntityService; -import com.ecep.contract.IEntityService; -import com.ecep.contract.MyDateTimeUtils; -import com.ecep.contract.QueryService; +import com.ecep.contract.*; import com.ecep.contract.cloud.rk.CloudRkService; import com.ecep.contract.cloud.tyc.CloudTycService; import com.ecep.contract.cloud.u8.YongYouU8Service; @@ -420,25 +417,26 @@ public class CompanyService extends EntityService * @param verifyDate 验证日期 * @param status 状态输出 */ - public void verifyEnterpriseStatus(Company company, LocalDate verifyDate, Consumer status) { + public boolean verifyEnterpriseStatus(Company company, LocalDate verifyDate, MessageHolder holder) { // 检查营业状态 String entStatus = company.getEntStatus(); - if (StringUtils.hasText(entStatus)) { - if (entStatus.contains("注销")) { - LocalDate end = company.getOperationPeriodEnd(); - LocalDate begin = company.getOperationPeriodBegin(); - if (begin == null || end == null) { - // 注销时间未知,无法判断是否在 verifyDate 之后注销 - status.accept("营业状态异常:" + entStatus); - } else { - if (!MyDateTimeUtils.dateValidFilter(verifyDate, begin, end, 0)) { - status.accept("营业状态异常:" + entStatus); - } + if (!StringUtils.hasText(entStatus)) { + holder.warn("营业状态异常:未设置"); + return false; + } + if (entStatus.contains("注销")) { + LocalDate end = company.getOperationPeriodEnd(); + LocalDate begin = company.getOperationPeriodBegin(); + if (begin == null || end == null) { + // 注销时间未知,无法判断是否在 verifyDate 之后注销 + holder.error("营业状态异常:" + entStatus); + } else { + if (!MyDateTimeUtils.dateValidFilter(verifyDate, begin, end, 0)) { + holder.error("营业状态异常:" + entStatus); } } - } else { - status.accept("营业状态异常:未设置"); } + return true; } @Override @@ -495,7 +493,7 @@ public class CompanyService extends EntityService } public Predicate buildSearchPredicate(String searchText, Path root, CriteriaQuery query, - CriteriaBuilder builder) { + CriteriaBuilder builder) { return builder.or( builder.like(root.get("name"), "%" + searchText + "%"), builder.like(root.get("shortName"), "%" + searchText + "%"), diff --git a/server/src/main/java/com/ecep/contract/ds/company/tasker/CompanyCompositeUpdateTasker.java b/server/src/main/java/com/ecep/contract/ds/company/tasker/CompanyCompositeUpdateTasker.java index 868661e..db4b537 100644 --- a/server/src/main/java/com/ecep/contract/ds/company/tasker/CompanyCompositeUpdateTasker.java +++ b/server/src/main/java/com/ecep/contract/ds/company/tasker/CompanyCompositeUpdateTasker.java @@ -21,14 +21,16 @@ import com.ecep.contract.constant.CloudServiceConstant; import com.ecep.contract.model.CloudRk; import com.ecep.contract.model.CloudYu; import com.ecep.contract.model.Company; +import com.ecep.contract.service.WebSocketServerTasker; import com.ecep.contract.ui.Tasker; +import com.fasterxml.jackson.databind.JsonNode; import lombok.Setter; /** * 合并更新 */ -public class CompanyCompositeUpdateTasker extends Tasker { +public class CompanyCompositeUpdateTasker extends Tasker implements WebSocketServerTasker { private static final Logger logger = LoggerFactory.getLogger(CompanyCompositeUpdateTasker.class); CloudRkCtx cloudRkCtx = new CloudRkCtx(); @@ -43,17 +45,25 @@ public class CompanyCompositeUpdateTasker extends Tasker { private Company company; @Override - protected Object execute(MessageHolder holder) throws Exception { - - updateProgress(0.1, 1); - syncFromCloudRk(holder); - updateProgress(0.3, 1); - syncFromYongYouU8(holder); - updateProgress(0.6, 1); - syncFromCloudTyc(holder); - return null; + public void init(JsonNode argsNode) { + int companyId = argsNode.get(0).asInt(); + company = getCachedBean(com.ecep.contract.ds.company.service.CompanyService.class).findById(companyId); } + @Override + protected Object execute(MessageHolder holder) throws Exception { + + holder.debug("1. 从 " + CloudServiceConstant.RK_NAME + " 更新..."); + updateProgress(0.1, 1); + syncFromCloudRk(holder); + holder.debug("2. 从 " + CloudServiceConstant.U8_NAME + " 更新..."); + updateProgress(0.3, 1); + syncFromYongYouU8(holder); + holder.debug("3. 从 " + CloudServiceConstant.TYC_NAME + " 更新..."); + syncFromCloudTyc(holder); + updateProgress(0.9, 1); + return null; + } private void syncFromCloudRk(MessageHolder holder) { holder.debug("1. 从 " + CloudServiceConstant.RK_NAME + " 更新..."); diff --git a/server/src/main/java/com/ecep/contract/ds/company/tasker/CompanyVerifyTasker.java b/server/src/main/java/com/ecep/contract/ds/company/tasker/CompanyVerifyTasker.java index 80bf0f9..b5311c1 100644 --- a/server/src/main/java/com/ecep/contract/ds/company/tasker/CompanyVerifyTasker.java +++ b/server/src/main/java/com/ecep/contract/ds/company/tasker/CompanyVerifyTasker.java @@ -8,61 +8,33 @@ import java.util.logging.Level; import com.ecep.contract.MessageHolder; import com.ecep.contract.ds.company.service.CompanyService; +import com.ecep.contract.ds.contract.service.ContractService; import com.ecep.contract.ds.contract.tasker.ContractVerifyComm; import com.ecep.contract.model.Company; import com.ecep.contract.model.Contract; -import com.ecep.contract.ui.MessageHolderImpl; +import com.ecep.contract.service.WebSocketServerTasker; import com.ecep.contract.ui.Tasker; +import com.fasterxml.jackson.databind.JsonNode; import lombok.Getter; import lombok.Setter; -public class CompanyVerifyTasker extends Tasker { - @Setter - private CompanyService companyService; +public class CompanyVerifyTasker extends Tasker implements WebSocketServerTasker { @Getter @Setter private Company company; - + @Getter + @Setter + boolean passed = false; ContractVerifyComm comm = new ContractVerifyComm(); - AtomicBoolean verified = new AtomicBoolean(true); public CompanyService getCompanyService() { - if (companyService == null) { - companyService = getBean(CompanyService.class); - } - return companyService; + return getCachedBean(CompanyService.class); } - @Override - public Object call() throws Exception { - comm.setVerifyCompanyPath(false); - comm.setVerifyCompanyStatus(false); - comm.setVerifyCompanyCredit(false); - return execute(new MessageHolderImpl(this) { - @Override - public void addMessage(Level level, String message) { - super.addMessage(level, message); - if (level.intValue() > Level.INFO.intValue()) { - verified.set(false); - } - } - }); - } - - @Override - protected Object execute(MessageHolder holder) throws Exception { - updateTitle("验证企业是否符合合规要求"); - - verify(company, holder); - - if (verified.get()) { - updateMessage(Level.CONFIG, "合规验证通过"); - } else { - updateMessage(Level.SEVERE, "合规验证不通过"); - } - return null; + public ContractService getContractService() { + return getCachedBean(ContractService.class); } /** @@ -71,22 +43,52 @@ public class CompanyVerifyTasker extends Tasker { * @param company 公司 * @param holder 输出 */ + @Override + public void init(JsonNode argsNode) { + int companyId = argsNode.get(0).asInt(); + company = getCompanyService().findById(companyId); + comm.setVerifyCompanyPath(false); + comm.setVerifyCompanyStatus(false); + comm.setVerifyCompanyCredit(false); + } + + @Override + protected Object execute(MessageHolder holder) throws Exception { + updateTitle("验证企业是否符合合规要求"); + + verify(company, holder); + + if (passed) { + holder.info("合规验证通过"); + } else { + holder.error("合规验证不通过"); + } + + updateProperty("passed", passed); + return null; + } + private void verify(Company company, MessageHolder holder) { LocalDate now = LocalDate.now(); - getCompanyService().verifyEnterpriseStatus(company, now, holder::info); + if (getCompanyService().verifyEnterpriseStatus(company, now, holder)) { + passed = false; + } // 验证所有的合同 - List list = comm.getContractService().findAllByCompany(company); + List list = getContractService().findAllByCompany(company); if (list.isEmpty()) { holder.debug("!没有相关合同!"); return; } holder.debug("检索到相关合同 " + list.size() + " 个"); + AtomicInteger counter = new AtomicInteger(0); long total = list.size(); for (Contract contract : list) { holder.debug("核验合同:" + contract.getCode() + ", " + contract.getName()); - comm.verify(company, contract, holder.sub("-- ")); + if (!comm.verify(company, contract, holder.sub("-- "))) { + passed = false; + } updateProgress(counter.incrementAndGet(), total); } updateProgress(1, 1); diff --git a/server/src/main/java/com/ecep/contract/ds/contract/service/ContractService.java b/server/src/main/java/com/ecep/contract/ds/contract/service/ContractService.java index 5f87070..24ee1d1 100644 --- a/server/src/main/java/com/ecep/contract/ds/contract/service/ContractService.java +++ b/server/src/main/java/com/ecep/contract/ds/contract/service/ContractService.java @@ -189,8 +189,9 @@ public class ContractService extends EntityService Matcher matcher = pattern.matcher(contractCode); if (matcher.find()) { catalogCode = matcher.group(1); - System.out.println("字母部分: " + matcher.group(1)); - System.out.println("数字部分: " + matcher.group(2)); + if (logger.isDebugEnabled()) { + logger.debug("{} -> 字母:{}, 数字:{}", contractCode, matcher.group(1), matcher.group(2)); + } } if (catalogCode == null) { if (logger.isInfoEnabled()) { @@ -376,7 +377,7 @@ public class ContractService extends EntityService if (contract == null || vo == null) { return; } - + contract.setCode(vo.getCode()); contract.setName(vo.getName()); contract.setGuid(vo.getGuid()); @@ -393,7 +394,7 @@ public class ContractService extends EntityService contract.setExecAmount(vo.getExecAmount()); contract.setExecUnTaxAmount(vo.getExecUnTaxAmount()); contract.setPayWay(vo.getPayWay()); - + if (vo.getCompanyId() == null) { contract.setCompany(null); } else { diff --git a/server/src/main/java/com/ecep/contract/ds/contract/tasker/ContractVerifyComm.java b/server/src/main/java/com/ecep/contract/ds/contract/tasker/ContractVerifyComm.java index d6eba0a..741982a 100644 --- a/server/src/main/java/com/ecep/contract/ds/contract/tasker/ContractVerifyComm.java +++ b/server/src/main/java/com/ecep/contract/ds/contract/tasker/ContractVerifyComm.java @@ -18,35 +18,24 @@ import org.hibernate.Hibernate; import org.springframework.security.core.userdetails.User; import org.springframework.util.StringUtils; -import com.ecep.contract.CustomerFileType; import com.ecep.contract.ContractFileType; import com.ecep.contract.ContractPayWay; +import com.ecep.contract.CustomerFileType; import com.ecep.contract.MessageHolder; import com.ecep.contract.MyDateTimeUtils; import com.ecep.contract.SpringApp; import com.ecep.contract.ds.company.CompanyFileUtils; import com.ecep.contract.ds.company.service.CompanyExtendInfoService; -import com.ecep.contract.ds.company.service.CompanyFileService; -import com.ecep.contract.ds.company.service.CompanyService; -import com.ecep.contract.ds.contract.service.ContractBidVendorService; -import com.ecep.contract.ds.contract.service.ContractFileService; -import com.ecep.contract.ds.contract.service.ContractFileTypeService; -import com.ecep.contract.ds.contract.service.ContractService; import com.ecep.contract.ds.contract.service.ExtendVendorInfoService; import com.ecep.contract.ds.converter.NumberStringConverter; -import com.ecep.contract.ds.customer.service.CompanyCustomerFileService; -import com.ecep.contract.ds.customer.service.CompanyCustomerService; import com.ecep.contract.ds.other.service.EmployeeService; import com.ecep.contract.ds.project.ProjectCostImportItemsFromContractsTasker; import com.ecep.contract.ds.project.service.ProjectBidService; import com.ecep.contract.ds.project.service.ProjectCostService; import com.ecep.contract.ds.project.service.ProjectQuotationService; import com.ecep.contract.ds.project.service.ProjectSaleTypeRequireFileTypeService; -import com.ecep.contract.ds.project.service.ProjectService; import com.ecep.contract.ds.project.service.ProjectSaleTypeService; -import com.ecep.contract.ds.vendor.service.VendorService; import com.ecep.contract.ds.vendor.service.VendorGroupRequireFileTypeService; -import com.ecep.contract.ds.vendor.service.VendorGroupService; import com.ecep.contract.model.Company; import com.ecep.contract.model.CompanyCustomer; import com.ecep.contract.model.CompanyCustomerFile; @@ -66,184 +55,48 @@ import com.ecep.contract.model.ProjectSaleTypeRequireFileType; import com.ecep.contract.model.VendorGroup; import com.ecep.contract.model.VendorGroupRequireFileType; import com.ecep.contract.util.SecurityUtils; +import com.ecep.contract.util.VerifyContext; import lombok.Data; @Data -public class ContractVerifyComm { - // Project - private ProjectService projectService; - private ProjectSaleTypeRequireFileTypeService saleTypeRequireFileTypeService; - private ProjectSaleTypeService projectSaleTypeService; - 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; - } - +public class ContractVerifyComm extends VerifyContext { private ProjectSaleTypeService getProjectSaleTypeService() { - if (projectSaleTypeService == null) { - projectSaleTypeService = SpringApp.getBean(ProjectSaleTypeService.class); - } - return projectSaleTypeService; + return getBean(ProjectSaleTypeService.class); } ProjectCostService getProjectCostService() { - if (projectCostService == null) { - projectCostService = SpringApp.getBean(ProjectCostService.class); - } - return projectCostService; + return getBean(ProjectCostService.class); } ProjectQuotationService getProjectQuotationService() { - if (projectQuotationService == null) { - projectQuotationService = SpringApp.getBean(ProjectQuotationService.class); - } - return projectQuotationService; + return getBean(ProjectQuotationService.class); } ProjectBidService getProjectBidService() { - if (projectBidService == null) { - projectBidService = SpringApp.getBean(ProjectBidService.class); - } - return projectBidService; + return getBean(ProjectBidService.class); } 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; + return getBean(ProjectSaleTypeRequireFileTypeService.class); } private VendorGroupRequireFileTypeService getVendorGroupRequireFileTypeService() { - if (vendorGroupRequireFileTypeService == null) { - vendorGroupRequireFileTypeService = SpringApp.getBean(VendorGroupRequireFileTypeService.class); - } - return vendorGroupRequireFileTypeService; + return getBean(VendorGroupRequireFileTypeService.class); } 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; + return getBean(ExtendVendorInfoService.class); } 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; + return getBean(CompanyExtendInfoService.class); } /** * */ private Map fileTypeLocalMap = null; - private Locale locale = Locale.getDefault(); private Contract contract; /** @@ -285,69 +138,95 @@ public class ContractVerifyComm { * @param contract 要验证的合同对象 * @param holder 输出 */ - public void verify(Contract contract, MessageHolder holder) { + public boolean verify(Contract contract, MessageHolder holder) { + boolean passed = true; LocalDate setupDate = contract.getSetupDate(); if (setupDate == null) { holder.error("未设置合同提交日期"); - return; + passed = false; } Company company = contract.getCompany(); if (company == null) { holder.error("未关联企业"); - return; + return false; } if (!Hibernate.isInitialized(company)) { company = getCompanyService().findById(company.getId()); } - verify(company, contract, holder); + if (!verify(company, contract, holder)) { + passed = false; + } + return passed; } - public void verify(Company company, Contract contract, MessageHolder holder) { + public boolean verify(Company company, LocalDate verifyDate, MessageHolder holder) { + CompanyExtendInfo companyExtendInfo = getCompanyExtendInfoService().findByCompany(company); + if (companyExtendInfo.isDisableVerify()) { + holder.debug("公司设定不做校验"); + return true; + } + + boolean passed = true; + MessageHolder subHolder = holder.sub(company.getName() + " -> "); + if (verifyCompanyPath) { + if (!CompanyFileUtils.exists(company.getPath())) { + subHolder.error("公司目录未设置"); + passed = false; + } else { + File basePath = getCompanyService().getBasePath(); + if (!company.getPath().startsWith(basePath.getAbsolutePath())) { + subHolder.warn("公司目录未在规定目录下"); + } + } + } + + if (verifyCompanyStatus) { + if (!getCompanyService().verifyEnterpriseStatus(company, verifyDate, subHolder)) { + passed = false; + } + } + + if (verifyCompanyCredit) { + if (!getCompanyFileService().verify(company, verifyDate, subHolder)) { + passed = false; + } + } + return passed; + } + + /** + * 验证合同是否合规 + * + * @param company + * @param contract + * @param holder + * @return + */ + public boolean verify(Company company, Contract contract, MessageHolder holder) { + boolean passed = true; LocalDate setupDate = contract.getSetupDate(); Employee employee = contract.getEmployee(); if (employee == null) { holder.error("未关联业务员"); + passed = false; } if (contract.getAmount() == null || contract.getAmount() <= 0) { holder.error("合同金额小于等于0"); + passed = false; } - CompanyExtendInfo companyExtendInfo = getCompanyExtendInfoService().findByCompany(company); - - if (companyExtendInfo.isDisableVerify()) { - holder.debug("公司设定不做校验"); - } else { - if (verifyCompanyPath) { - if (!CompanyFileUtils.exists(company.getPath())) { - holder.error("公司目录未设置"); - } else { - File basePath = getCompanyService().getBasePath(); - if (!company.getPath().startsWith(basePath.getAbsolutePath())) { - holder.error("公司目录未在规定目录下"); - } - } - } - - if (verifyCompanyStatus) { - getCompanyService().verifyEnterpriseStatus(company, setupDate, msg -> { - holder.error(company.getName() + ":" + msg); - }); - } - - if (verifyCompanyCredit) { - getCompanyFileService().verify(company, contract.getSetupDate(), msg -> { - holder.error(company.getName() + ":" + msg); - }); - } + if (!verify(company, setupDate, holder)) { + passed = false; } // 合同类型 switch (contract.getPayWay()) { case RECEIVE -> { // 销售合同 + CompanyExtendInfo companyExtendInfo = getCompanyExtendInfoService().findByCompany(company); verifyAsCustomer(company, companyExtendInfo, contract, holder); // 销售合同下的采购合同 @@ -356,20 +235,24 @@ public class ContractVerifyComm { for (Contract v : list) { MessageHolder subHolder = holder.sub(v.getCode() + " -> "); subHolder.info("采购合同 : " + v.getName()); - verify(v, subHolder); + if (!verify(v, subHolder)) { + passed = false; + } if (CompanyFileUtils.exists(v.getPath())) { if (!v.getPath().startsWith(contract.getPath())) { holder.error("合同目录未在规定目录下"); + passed = false; } } else { holder.error("合同目录未设置"); + passed = false; } } DoubleSummaryStatistics statistics = list.stream().mapToDouble(c -> { return Objects.requireNonNullElse(c.getAmount(), 0.0); }).summaryStatistics(); - NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale); + NumberFormat numberFormat = NumberFormat.getCurrencyInstance(getLocale()); holder.debug("采购合同金额合计:" + numberFormat.format(statistics.getSum())); holder.debug("采购合同金额平均值:" + numberFormat.format(statistics.getAverage())); @@ -394,6 +277,7 @@ public class ContractVerifyComm { holder.error("合同付款类型:未设置"); } } + return passed; } private void verifyAsVendor(Company company, Contract contract, MessageHolder holder) { @@ -535,9 +419,9 @@ public class ContractVerifyComm { return false; } - private void verifyAsCustomer(Company company, CompanyExtendInfo companyExtendInfo, Contract contract, + private boolean verifyAsCustomer(Company company, CompanyExtendInfo companyExtendInfo, Contract contract, MessageHolder holder) { - boolean valiad = true; + boolean passed = true; Project project = contract.getProject(); if (project == null) { // 收款的合同时,检查是否关联了项目,如果没有则创建 @@ -586,16 +470,17 @@ public class ContractVerifyComm { if (!companyExtendInfo.isDisableVerify()) { if (!verifyCustomerContract(contract, holder)) { - valiad = false; + passed = false; } if (verifyCustomerFiles) { holder.debug("核验文件..."); if (!verifyContractFileAsCustomer(project, contract, holder)) { - valiad = false; + passed = false; } } } + return passed; } /** diff --git a/server/src/main/java/com/ecep/contract/ds/contract/tasker/ContractVerifyTasker.java b/server/src/main/java/com/ecep/contract/ds/contract/tasker/ContractVerifyTasker.java index 00bffe1..d44ca6a 100644 --- a/server/src/main/java/com/ecep/contract/ds/contract/tasker/ContractVerifyTasker.java +++ b/server/src/main/java/com/ecep/contract/ds/contract/tasker/ContractVerifyTasker.java @@ -1,17 +1,14 @@ package com.ecep.contract.ds.contract.tasker; import java.util.Locale; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.logging.Level; import com.ecep.contract.MessageHolder; import com.ecep.contract.ds.contract.service.ContractService; import com.ecep.contract.model.Contract; import com.ecep.contract.service.WebSocketServerTasker; -import com.ecep.contract.ui.MessageHolderImpl; import com.ecep.contract.ui.Tasker; - import com.fasterxml.jackson.databind.JsonNode; + import lombok.Getter; import lombok.Setter; @@ -20,39 +17,25 @@ public class ContractVerifyTasker extends Tasker implements WebSocketSer @Setter private Contract contract; ContractVerifyComm comm = new ContractVerifyComm(); - - AtomicBoolean verified = new AtomicBoolean(true); - - @Override - public Object call() throws Exception { - updateTitle("验证合同 " + contract.getCode() + " 及其子合同是否符合合规要求"); - return execute(new MessageHolderImpl(this) { - @Override - public void addMessage(Level level, String message) { - super.addMessage(level, message); - if (level.intValue() > Level.INFO.intValue()) { - verified.set(false); - } - } - }); - } + @Getter + @Setter + boolean passed = true; @Override protected Object execute(MessageHolder holder) { - comm.verify(contract, holder); - if (verified.get()) { - updateMessage(Level.CONFIG, "合规验证通过"); + updateTitle("验证合同 " + contract.getCode() + " 及其子合同是否符合合规要求"); + if (!comm.verify(contract, holder)) { + passed = false; + } + + if (passed) { + holder.info("合规验证通过"); } else { - updateMessage(Level.SEVERE, "合规验证不通过"); + holder.error("合规验证不通过"); } return null; } - - public void setContractService(ContractService contractService) { - comm.setContractService(contractService); - } - public Locale getLocale() { return comm.getLocale(); } @@ -67,5 +50,4 @@ public class ContractVerifyTasker extends Tasker implements WebSocketSer contract = getCachedBean(ContractService.class).findById(contractId); } - } diff --git a/server/src/main/java/com/ecep/contract/util/VerifyContext.java b/server/src/main/java/com/ecep/contract/util/VerifyContext.java new file mode 100644 index 0000000..c596fcc --- /dev/null +++ b/server/src/main/java/com/ecep/contract/util/VerifyContext.java @@ -0,0 +1,123 @@ +package com.ecep.contract.util; + +import java.util.HashMap; +import java.util.Locale; + +import com.ecep.contract.SpringApp; +import com.ecep.contract.ds.company.service.CompanyFileService; +import com.ecep.contract.ds.company.service.CompanyFileTypeService; +import com.ecep.contract.ds.company.service.CompanyService; +import com.ecep.contract.ds.contract.service.ContractBidVendorService; +import com.ecep.contract.ds.contract.service.ContractFileService; +import com.ecep.contract.ds.contract.service.ContractFileTypeService; +import com.ecep.contract.ds.contract.service.ContractService; +import com.ecep.contract.ds.customer.service.CompanyCustomerFileService; +import com.ecep.contract.ds.customer.service.CompanyCustomerFileTypeService; +import com.ecep.contract.ds.customer.service.CompanyCustomerService; +import com.ecep.contract.ds.other.service.EmployeeService; +import com.ecep.contract.ds.project.service.ProjectFileService; +import com.ecep.contract.ds.project.service.ProjectFileTypeService; +import com.ecep.contract.ds.project.service.ProjectService; +import com.ecep.contract.ds.vendor.service.VendorFileService; +import com.ecep.contract.ds.vendor.service.VendorFileTypeService; +import com.ecep.contract.ds.vendor.service.VendorGroupService; +import com.ecep.contract.ds.vendor.service.VendorService; + +import lombok.Getter; +import lombok.Setter; + +public class VerifyContext { + @Getter + @Setter + private Locale locale = Locale.getDefault(); + private HashMap, Object> cachedMap = new HashMap<>(); + + public K getBean(Class requiredType) { + @SuppressWarnings("unchecked") + K bean = (K) cachedMap.get(requiredType); + if (bean == null) { + bean = SpringApp.getBean(requiredType); + cachedMap.put(requiredType, bean); + } + return bean; + } + + // Employee + protected EmployeeService getEmployeeService() { + return getBean(EmployeeService.class); + } + + // Project + protected ProjectService getProjectService() { + return getBean(ProjectService.class); + } + + protected ProjectFileService getProjectFileService() { + return getBean(ProjectFileService.class); + } + + protected ProjectFileTypeService getProjectFileTypeService() { + return getBean(ProjectFileTypeService.class); + } + + // Contract + protected ContractService getContractService() { + return getBean(ContractService.class); + } + + protected ContractFileTypeService getContractFileTypeService() { + return getBean(ContractFileTypeService.class); + } + + protected ContractFileService getContractFileService() { + return getBean(ContractFileService.class); + } + + protected ContractBidVendorService getContractBidVendorService() { + return getBean(ContractBidVendorService.class); + } + + // Company + protected CompanyService getCompanyService() { + return getBean(CompanyService.class); + } + + protected CompanyFileTypeService getCompanyFileTypeService() { + return getBean(CompanyFileTypeService.class); + } + + protected CompanyFileService getCompanyFileService() { + return getBean(CompanyFileService.class); + } + + // Vendor + protected VendorService getVendorService() { + return getBean(VendorService.class); + } + + protected VendorGroupService getVendorGroupService() { + return getBean(VendorGroupService.class); + } + + protected VendorFileTypeService getVendorFileTypeService() { + return getBean(VendorFileTypeService.class); + } + + protected VendorFileService getVendorFileService() { + return getBean(VendorFileService.class); + } + + // Customer + + protected CompanyCustomerService getCompanyCustomerService() { + return getBean(CompanyCustomerService.class); + } + + protected CompanyCustomerFileTypeService getCompanyCustomerFileTypeService() { + return getBean(CompanyCustomerFileTypeService.class); + } + + protected CompanyCustomerFileService getCompanyCustomerFileService() { + return getBean(CompanyCustomerFileService.class); + } +} diff --git a/server/src/main/resources/tasker_mapper.json b/server/src/main/resources/tasker_mapper.json index 2afd319..9c2095d 100644 --- a/server/src/main/resources/tasker_mapper.json +++ b/server/src/main/resources/tasker_mapper.json @@ -7,7 +7,9 @@ "CompanyCustomerEvaluationFormUpdateTask": "com.ecep.contract.ds.customer.tasker.CompanyCustomerEvaluationFormUpdateTask", "CompanyCustomerNextSignDateTask": "com.ecep.contract.ds.customer.tasker.CompanyCustomerNextSignDateTask", "CompanyCustomerRebuildFilesTasker": "com.ecep.contract.ds.customer.tasker.CompanyCustomerRebuildFilesTasker", - "CustomerFileMoveTasker": "com.ecep.contract.ds.customer.tasker.CustomerFileMoveTasker" + "CustomerFileMoveTasker": "com.ecep.contract.ds.customer.tasker.CustomerFileMoveTasker", + "CompanyCompositeUpdateTasker": "com.ecep.contract.ds.company.tasker.CompanyCompositeUpdateTasker", + "CompanyVerifyTasker": "com.ecep.contract.ds.company.tasker.CompanyVerifyTasker" }, "descriptions": "任务注册信息" } \ No newline at end of file diff --git a/上海社会科学院—天眼查-2023-09-21_17-30.pdf b/上海社会科学院—天眼查-2023-09-21_17-30.pdf deleted file mode 100644 index 076e3e1..0000000 Binary files a/上海社会科学院—天眼查-2023-09-21_17-30.pdf and /dev/null differ