From 69f904b23cc99328adf3f9d68ee9ce2d32e1a861 Mon Sep 17 00:00:00 2001 From: zhouxiaofeng <2946471396@qq.com> Date: Mon, 1 Jun 2026 14:56:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=88=E5=90=8C=E5=A4=8D=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ContractLaunchController.java | 15 ++ .../service/ContractLaunchService.java | 3 + .../service/ContractLaunchServiceImpl.java | 235 ++++++++++++++++-- .../utils/ContractLaunchConstants.java | 1 + 4 files changed, 229 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/nbport/zgwl/contractlaunch/controller/ContractLaunchController.java b/src/main/java/com/nbport/zgwl/contractlaunch/controller/ContractLaunchController.java index 48ce37c..bd001ac 100644 --- a/src/main/java/com/nbport/zgwl/contractlaunch/controller/ContractLaunchController.java +++ b/src/main/java/com/nbport/zgwl/contractlaunch/controller/ContractLaunchController.java @@ -118,6 +118,21 @@ public class ContractLaunchController { return R.success(contractLaunchService.updateDraft(contract)); } + /** + * 复制合同并生成新草稿。 + * + * 业务设计: + * 1. 允许从任意未删除合同复制出一份新的草稿,方便高频复用历史合同 + * 2. 保留主信息、合同方、正文附件、履行计划等业务内容 + * 3. 重置系统编号、合同编号、审批/签署/归档状态与相关痕迹,避免串流程数据 + * + * 对应前端功能:列表页 → 复制合同 + */ + @PostMapping("/{id}/copy") + public R copyDraft(@PathVariable("id") Long id) { + return R.success(contractLaunchService.copyDraft(id)); + } + /** * 提交法务审批。 * diff --git a/src/main/java/com/nbport/zgwl/contractlaunch/service/ContractLaunchService.java b/src/main/java/com/nbport/zgwl/contractlaunch/service/ContractLaunchService.java index 3dd31ec..ce30df1 100644 --- a/src/main/java/com/nbport/zgwl/contractlaunch/service/ContractLaunchService.java +++ b/src/main/java/com/nbport/zgwl/contractlaunch/service/ContractLaunchService.java @@ -23,6 +23,9 @@ public interface ContractLaunchService { /** 编辑合同草稿 */ ContractLaunchDto updateDraft(ContractLaunchDto contract); + /** 复制合同并生成新的草稿 */ + ContractLaunchDto copyDraft(Long id); + /** 提交法务审批(调用结算平台 pushContract 接口) */ ContractLaunchDto submitToLaw(Long id); diff --git a/src/main/java/com/nbport/zgwl/contractlaunch/service/ContractLaunchServiceImpl.java b/src/main/java/com/nbport/zgwl/contractlaunch/service/ContractLaunchServiceImpl.java index 7ce6fa3..1951e7d 100644 --- a/src/main/java/com/nbport/zgwl/contractlaunch/service/ContractLaunchServiceImpl.java +++ b/src/main/java/com/nbport/zgwl/contractlaunch/service/ContractLaunchServiceImpl.java @@ -92,31 +92,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { SysUserEntity currentUser = adminSecurityManage.getUser(); normalizeContract(contract); validateDraft(contract); - - LocalDateTime now = LocalDateTime.now(); - contract.setId(contractLaunchMapper.selectMainSeqNextVal()); - contract.setContractSysId(ContractLaunchCodeUtils.buildContractSysId()); - if (contract.getContractCode() == null || contract.getContractCode().isBlank()) { - contract.setContractCode(ContractLaunchCodeUtils.buildContractCode(contract.getContractTypeCode())); - } - contract.setContractSource(contract.getContractSource() == null || contract.getContractSource().isBlank() ? "ECP" : contract.getContractSource()); - contract.setStatus(ContractLaunchConstants.STATUS_DRAFT); - contract.setApproveStatus(ContractLaunchConstants.APPROVE_STATUS_PENDING); - contract.setInitiator(currentUser.getUsername()); - contract.setInitiatorDept(currentUser.getSysOrgEntity() == null ? "" : currentUser.getSysOrgEntity().getOrgName()); - contract.setCompanyName(currentUser.getSysOrgEntity() == null ? "" : currentUser.getSysOrgEntity().getOrgName()); - contract.setOrgId(currentUser.getSysOrgEntity() == null ? "" : currentUser.getSysOrgEntity().getId()); - contract.setCreatorPhone(currentUser.getMobilePhone()); - contract.setCreateBy(currentUser.getUsername()); - contract.setCreateTime(now); - contract.setUpdateBy(currentUser.getUsername()); - contract.setUpdateTime(now); - contract.setIsDeleted(ContractLaunchConstants.IS_DELETED_NO); - contract.setQueryScope("personal"); - contractLaunchMapper.insertContract(contract); - saveChildren(contract, currentUser.getUsername()); - insertLog(contract.getId(), ContractLaunchConstants.ACTION_SAVE, "保存草稿", ContractLaunchConstants.ACTION_STATUS_SUCCESS, "合同草稿创建成功", null, currentUser); - return getDetail(contract.getId()); + return persistDraft(contract, currentUser, false, ContractLaunchConstants.ACTION_SAVE, "保存草稿", "合同草稿创建成功"); } /** @@ -163,6 +139,25 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { return getDetail(contract.getId()); } + /** + * 复制合同并生成新草稿。 + * + * 复制策略: + * 1. 复制主信息、合同方、正文/签订依据/其他附件、履行计划 + * 2. 重置系统主键、合同系统号、合同编号、流程状态、审批信息、签署信息、归档信息 + * 3. 不复制日志,也不复制 signed/archive 分类文件 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public ContractLaunchDto copyDraft(Long id) { + ContractLaunchDto source = getDetail(id); + SysUserEntity currentUser = adminSecurityManage.getUser(); + ContractLaunchDto copiedContract = buildCopiedDraft(source); + normalizeContract(copiedContract); + validateDraft(copiedContract); + return persistDraft(copiedContract, currentUser, true, ContractLaunchConstants.ACTION_COPY, "复制合同", "合同复制成功,已生成新草稿"); + } + /** * 提交法务审批。 * @@ -505,6 +500,196 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { insertLog(id, ContractLaunchConstants.ACTION_DELETE, "删除合同", ContractLaunchConstants.ACTION_STATUS_SUCCESS, "合同已逻辑删除", null, currentUser); } + private ContractLaunchDto persistDraft(ContractLaunchDto contract, + SysUserEntity currentUser, + boolean forceGenerateContractCode, + String actionType, + String actionName, + String actionContent) { + LocalDateTime now = LocalDateTime.now(); + contract.setId(contractLaunchMapper.selectMainSeqNextVal()); + contract.setContractSysId(ContractLaunchCodeUtils.buildContractSysId()); + if (forceGenerateContractCode || contract.getContractCode() == null || contract.getContractCode().isBlank()) { + contract.setContractCode(ContractLaunchCodeUtils.buildContractCode(contract.getContractTypeCode())); + } + contract.setContractSource(contract.getContractSource() == null || contract.getContractSource().isBlank() ? "ECP" : contract.getContractSource()); + contract.setStatus(ContractLaunchConstants.STATUS_DRAFT); + contract.setApproveStatus(ContractLaunchConstants.APPROVE_STATUS_PENDING); + contract.setApproveMessage(null); + contract.setInitiator(currentUser.getUsername()); + contract.setInitiatorDept(currentUser.getSysOrgEntity() == null ? "" : currentUser.getSysOrgEntity().getOrgName()); + contract.setCompanyName(currentUser.getSysOrgEntity() == null ? "" : currentUser.getSysOrgEntity().getOrgName()); + contract.setOrgId(currentUser.getSysOrgEntity() == null ? "" : currentUser.getSysOrgEntity().getId()); + contract.setCreatorPhone(currentUser.getMobilePhone()); + contract.setCreateBy(currentUser.getUsername()); + contract.setCreateTime(now); + contract.setUpdateBy(currentUser.getUsername()); + contract.setUpdateTime(now); + contract.setIsDeleted(ContractLaunchConstants.IS_DELETED_NO); + contract.setQueryScope("personal"); + contractLaunchMapper.insertContract(contract); + saveChildren(contract, currentUser.getUsername()); + insertLog(contract.getId(), actionType, actionName, ContractLaunchConstants.ACTION_STATUS_SUCCESS, actionContent, null, currentUser); + return getDetail(contract.getId()); + } + + private ContractLaunchDto buildCopiedDraft(ContractLaunchDto source) { + ContractLaunchDto target = new ContractLaunchDto(); + target.setContractName(buildCopiedContractName(source.getContractName())); + target.setContractType(source.getContractType()); + target.setContractTypeCode(source.getContractTypeCode()); + target.setContractSource(source.getContractSource()); + target.setCreationMode(source.getCreationMode()); + target.setTemplateId(source.getTemplateId()); + target.setTemplateCode(source.getTemplateCode()); + target.setTemplateName(source.getTemplateName()); + target.setContractAmount(source.getContractAmount()); + target.setCurrencyName(source.getCurrencyName()); + target.setContractPeriodType(source.getContractPeriodType()); + target.setPeriodExplain(source.getPeriodExplain()); + target.setEffectiveStart(source.getEffectiveStart()); + target.setEffectiveEnd(source.getEffectiveEnd()); + target.setPaymentMethod(source.getPaymentMethod()); + target.setPrimaryContent(source.getPrimaryContent()); + target.setAmountExplain(source.getAmountExplain()); + target.setValuationMode(source.getValuationMode()); + target.setSealType(source.getSealType()); + target.setTextSource(source.getTextSource()); + target.setMandateType(source.getMandateType()); + target.setCargoType(source.getCargoType()); + target.setAssistDepartmentName(source.getAssistDepartmentName()); + target.setExecutorAccount(source.getExecutorAccount()); + target.setSelfCode(source.getSelfCode()); + target.setMainContractCode(source.getMainContractCode()); + target.setSigningSubjectCode(source.getSigningSubjectCode()); + target.setDateType(source.getDateType()); + target.setIsAddit(source.getIsAddit()); + target.setIsElectron(source.getIsElectron()); + target.setPaymentDirection(source.getPaymentDirection()); + target.setPushUrl(source.getPushUrl()); + target.setIsMajorContract(source.getIsMajorContract()); + target.setIsOpenBidding(source.getIsOpenBidding()); + target.setIsYearBudget(source.getIsYearBudget()); + target.setIsShare(source.getIsShare()); + target.setContractNature(source.getContractNature()); + target.setIsSgat(source.getIsSgat()); + target.setIsNormal(source.getIsNormal()); + target.setIsTerminated(null); + target.setIsSingleAgreement(source.getIsSingleAgreement()); + target.setBiddingNo(source.getBiddingNo()); + target.setOpenBiddingRemark(source.getOpenBiddingRemark()); + target.setContractGistRemark(source.getContractGistRemark()); + target.setEwAmountType(source.getEwAmountType()); + target.setDjAmount(source.getDjAmount()); + target.setYjAmount(source.getYjAmount()); + target.setYfkAmount(source.getYfkAmount()); + target.setBzjAmount(source.getBzjAmount()); + target.setBodySummary(source.getBodySummary()); + target.setTemplateFieldValuesJson(source.getTemplateFieldValuesJson()); + target.setContractTextFileName(source.getContractTextFileName()); + target.setContractTextFilePath(source.getContractTextFilePath()); + target.setContractTextFileType(source.getContractTextFileType()); + target.setContractTextFileSize(source.getContractTextFileSize()); + target.setSignDate(source.getSignDate()); + target.setActiveDate(source.getActiveDate()); + target.setInvoiceDate(source.getInvoiceDate()); + target.setReceiveDate(source.getReceiveDate()); + target.setRemindDays(source.getRemindDays()); + target.setRemark(source.getRemark()); + target.setPartyList(copyPartyList(source.getPartyList())); + target.setFileList(copyFileList(source.getFileList())); + target.setPerformancePlans(copyPlanList(source.getPerformancePlans())); + return target; + } + + private String buildCopiedContractName(String sourceName) { + String baseName = trim(sourceName); + if (baseName == null || baseName.isBlank()) { + return "复制合同"; + } + if (baseName.endsWith("-副本")) { + return baseName; + } + return baseName + "-副本"; + } + + private List copyPartyList(List sourceList) { + if (sourceList == null || sourceList.isEmpty()) { + return new ArrayList<>(); + } + List targetList = new ArrayList<>(); + for (ContractLaunchPartyDto source : sourceList) { + ContractLaunchPartyDto target = new ContractLaunchPartyDto(); + target.setRoleCode(source.getRoleCode()); + target.setRoleName(source.getRoleName()); + target.setPartnerId(source.getPartnerId()); + target.setOppositeId(source.getOppositeId()); + target.setCompanyName(source.getCompanyName()); + target.setCompanyType(source.getCompanyType()); + target.setOppositeCharacter(source.getOppositeCharacter()); + target.setContactName(source.getContactName()); + target.setContactPhone(source.getContactPhone()); + target.setContactEmail(source.getContactEmail()); + target.setContactAddress(source.getContactAddress()); + target.setRegisteredAddress(source.getRegisteredAddress()); + target.setLegalRepresentative(source.getLegalRepresentative()); + target.setCreditCode(source.getCreditCode()); + target.setBankName(source.getBankName()); + target.setBankAccount(source.getBankAccount()); + target.setNaturalPersonIdType(source.getNaturalPersonIdType()); + target.setNaturalPersonIdNumber(source.getNaturalPersonIdNumber()); + target.setIsGroupInternal(source.getIsGroupInternal()); + target.setIsHongKongMacaoTaiwan(source.getIsHongKongMacaoTaiwan()); + target.setRemark(source.getRemark()); + targetList.add(target); + } + return targetList; + } + + private List copyFileList(List sourceList) { + if (sourceList == null || sourceList.isEmpty()) { + return new ArrayList<>(); + } + List targetList = new ArrayList<>(); + for (ContractLaunchFileDto source : sourceList) { + if (ContractLaunchConstants.FILE_CATEGORY_SIGNED.equals(source.getFileCategory()) + || ContractLaunchConstants.FILE_CATEGORY_ARCHIVE.equals(source.getFileCategory())) { + continue; + } + ContractLaunchFileDto target = new ContractLaunchFileDto(); + target.setFileCategory(source.getFileCategory()); + target.setFileName(source.getFileName()); + target.setFilePath(source.getFilePath()); + target.setFileType(source.getFileType()); + target.setFileSize(source.getFileSize()); + target.setRemark(source.getRemark()); + targetList.add(target); + } + return targetList; + } + + private List copyPlanList(List sourceList) { + if (sourceList == null || sourceList.isEmpty()) { + return new ArrayList<>(); + } + List targetList = new ArrayList<>(); + for (ContractLaunchPlanDto source : sourceList) { + ContractLaunchPlanDto target = new ContractLaunchPlanDto(); + target.setPlanMatter(source.getPlanMatter()); + target.setPlanWhere(source.getPlanWhere()); + target.setPlanTime(source.getPlanTime()); + target.setPlanDay(source.getPlanDay()); + target.setPlanMoney(source.getPlanMoney()); + target.setPlanSubjectCode(source.getPlanSubjectCode()); + target.setPlanSubjectName(source.getPlanSubjectName()); + target.setPlanDetail(source.getPlanDetail()); + target.setPlanStatus("0"); + target.setRemark(source.getRemark()); + targetList.add(target); + } + return targetList; + } + /** * 批量填充子表数据(合同方/文件/履行计划/日志)。 * diff --git a/src/main/java/com/nbport/zgwl/contractlaunch/utils/ContractLaunchConstants.java b/src/main/java/com/nbport/zgwl/contractlaunch/utils/ContractLaunchConstants.java index fd60d2c..cecfd59 100644 --- a/src/main/java/com/nbport/zgwl/contractlaunch/utils/ContractLaunchConstants.java +++ b/src/main/java/com/nbport/zgwl/contractlaunch/utils/ContractLaunchConstants.java @@ -41,6 +41,7 @@ public final class ContractLaunchConstants { public static final String ACTION_COLLECT = "collect"; public static final String ACTION_ARCHIVE = "archive"; public static final String ACTION_DELETE = "delete"; + public static final String ACTION_COPY = "copy"; public static final String ACTION_STATUS_SUCCESS = "success"; public static final String ACTION_STATUS_FAILED = "failed";