diff --git a/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchDto.java b/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchDto.java index bbf5f38..1a67ab2 100644 --- a/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchDto.java +++ b/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchDto.java @@ -287,6 +287,10 @@ public class ContractLaunchDto implements Serializable { @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private LocalDateTime signDate; + /** 用印时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime sealDate; + /** 用印数量,默认为1 */ private Integer sealQuantity; diff --git a/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchSealDto.java b/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchSealDto.java index 874c799..454f792 100644 --- a/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchSealDto.java +++ b/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchSealDto.java @@ -1,9 +1,11 @@ package com.nbport.zgwl.contractlaunch.dto; +import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import java.io.Serial; import java.io.Serializable; +import java.time.LocalDateTime; /** * 签章回写参数 @@ -40,4 +42,16 @@ public class ContractLaunchSealDto implements Serializable { private String signedFileUrl; private String signedOfflineReason; + + /** 签订日期 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime signDate; + + /** 用印时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime sealDate; + + /** 合同生效日期 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime activeDate; } 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 a1bbc39..85227cc 100644 --- a/src/main/java/com/nbport/zgwl/contractlaunch/service/ContractLaunchServiceImpl.java +++ b/src/main/java/com/nbport/zgwl/contractlaunch/service/ContractLaunchServiceImpl.java @@ -396,6 +396,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { public ContractLaunchDto markSealCompleted(Long id, ContractLaunchSealDto sealDto) { ContractLaunchDto contract = getDetail(id); SysUserEntity currentUser = adminSecurityManage.getUser(); + LocalDateTime completedTime = LocalDateTime.now(); contract.setSealContractId(sealDto.getSealContractId() == null || sealDto.getSealContractId().isBlank() ? contract.getSealContractId() : sealDto.getSealContractId()); contract.setSealContractStatus(sealDto.getSealContractStatus()); contract.setSignedFileName(sealDto.getSignedFileName()); @@ -406,9 +407,13 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { contract.setSignedFileType(sealDto.getSignedFileType()); contract.setSignedFileSize(sealDto.getSignedFileSize()); contract.setSignedOfflineReason(sealDto.getSignedOfflineReason()); + contract.setSignDate(firstNonNull(sealDto.getSignDate(), contract.getSignDate(), completedTime)); + contract.setSealDate(firstNonNull(sealDto.getSealDate(), contract.getSealDate(), contract.getSignDate())); + contract.setActiveDate(firstNonNull(sealDto.getActiveDate(), contract.getActiveDate())); + validateSignCompletion(contract); contract.setStatus(ContractLaunchConstants.STATUS_PENDING_COLLECT); contract.setUpdateBy(currentUser.getUsername()); - contract.setUpdateTime(LocalDateTime.now()); + contract.setUpdateTime(completedTime); contractLaunchMapper.updateContract(contract); saveSignedFile(id, sealDto, currentUser.getUsername()); insertLog(id, ContractLaunchConstants.ACTION_SEAL_FINISH, "签署完成", ContractLaunchConstants.ACTION_STATUS_SUCCESS, "合同签署已完成,待采集", sealDto, currentUser); @@ -441,6 +446,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { if (!ContractLaunchConstants.STATUS_PENDING_COLLECT.equals(contract.getStatus())) { throw new ServiceException("当前状态不允许执行采集"); } + validateCollectionReady(contract); SysUserEntity currentUser = adminSecurityManage.getUser(); Map payload = buildDataCollectionContractPayload(contract); insertLog(id, ContractLaunchConstants.ACTION_COLLECT, "模拟合同采集", ContractLaunchConstants.ACTION_STATUS_PENDING, "合同采集接口当前先注释,使用测试按钮流转", payload, currentUser); @@ -654,6 +660,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { target.setContractTextFileType(source.getContractTextFileType()); target.setContractTextFileSize(source.getContractTextFileSize()); target.setSignDate(source.getSignDate()); + target.setSealDate(source.getSealDate()); target.setActiveDate(source.getActiveDate()); target.setInvoiceDate(source.getInvoiceDate()); target.setReceiveDate(source.getReceiveDate()); @@ -975,6 +982,10 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { && (contract.getPeriodExplain() == null || contract.getPeriodExplain().isBlank())) { throw new ServiceException("无固定期限合同必须填写期限说明"); } + if (contract.getActiveDate() == null) { + throw new ServiceException("合同生效日期不能为空"); + } + validateActiveDateWithinTerm(contract); if (contract.getPartyList() == null || contract.getPartyList().isEmpty()) { throw new ServiceException("至少需要维护一个合同方"); } @@ -1000,6 +1011,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { && !item.getFilePath().isBlank()))) { throw new ServiceException("当前签订方式必须上传授权委托书附件"); } + validatePerformancePlans(contract, false); } private boolean canEdit(String status) { @@ -1208,14 +1220,14 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { // payload.put("c_zw", buildCollectionFilePayloadList(contract, ContractLaunchConstants.FILE_CATEGORY_BODY)); // payload.put("c_attachs", buildCollectionFilePayloadList(contract, ContractLaunchConstants.FILE_CATEGORY_OTHER)); // payload.put("c_signAttachs", buildCollectionFilePayloadList(contract, ContractLaunchConstants.FILE_CATEGORY_GIST)); - payload.put("c_lxPlan", contract.getPerformancePlans()); + payload.put("c_lxPlan", buildCollectionPlanPayloadList(contract)); // 用印信息 Map seal = new LinkedHashMap<>(); seal.put("seal_isSeal", "1"); seal.put("seal_approveSame", "1"); seal.put("seal_type", contract.getSealType()); seal.put("seal_quantity", contract.getSealQuantity() == null ? "1" : String.valueOf(contract.getSealQuantity())); - seal.put("seal_date", contract.getSignDate()); + seal.put("seal_date", contract.getSealDate()); payload.put("c_seal", seal); // 签订信息 Map sign = new LinkedHashMap<>(); @@ -1230,6 +1242,23 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { return payload; } + private List> buildCollectionPlanPayloadList(ContractLaunchDto contract) { + boolean amountRequired = isPlanAmountRequired(contract.getValuationMode()); + return contract.getPerformancePlans().stream().map(plan -> { + Map map = new LinkedHashMap<>(); + map.put("lx_id", plan.getId() == null ? null : String.valueOf(plan.getId())); + map.put("lx_item", plan.getPlanMatter()); + map.put("lx_condition", plan.getPlanWhere()); + map.put("lx_nodeDate", plan.getPlanTime()); + map.put("lx_remindDays", plan.getPlanDay() == null ? null : String.valueOf(plan.getPlanDay())); + if (amountRequired && plan.getPlanMoney() != null) { + map.put("lx_amount", plan.getPlanMoney()); + } + map.put("lx_remarks", plan.getPlanDetail()); + return map; + }).collect(Collectors.toList()); + } + private boolean requiresAuthAttachment(String sealType) { return "GZBSQRQZ".equals(sealType) || "HTZYZBSQRQZ".equals(sealType); } @@ -1339,6 +1368,80 @@ public class ContractLaunchServiceImpl implements ContractLaunchService { return path != null && (path.startsWith("http://") || path.startsWith("https://")); } + private void validateSignCompletion(ContractLaunchDto contract) { + if (contract.getSignDate() == null) { + throw new ServiceException("签订日期不能为空"); + } + if (contract.getSealDate() == null) { + throw new ServiceException("用印时间不能为空"); + } + if (contract.getActiveDate() == null) { + throw new ServiceException("合同生效日期不能为空"); + } + validateActiveDateWithinTerm(contract); + } + + private void validateCollectionReady(ContractLaunchDto contract) { + validateSignCompletion(contract); + validatePerformancePlans(contract, true); + } + + private void validatePerformancePlans(ContractLaunchDto contract, boolean requirePlanId) { + if (contract.getPerformancePlans() == null || contract.getPerformancePlans().isEmpty()) { + throw new ServiceException("履行计划不能为空"); + } + boolean amountRequired = isPlanAmountRequired(contract.getValuationMode()); + for (ContractLaunchPlanDto plan : contract.getPerformancePlans()) { + if (requirePlanId && plan.getId() == null) { + throw new ServiceException("履行计划ID不能为空"); + } + if (plan.getPlanMatter() == null || plan.getPlanMatter().isBlank()) { + throw new ServiceException("履行计划的履行事项不能为空"); + } + if (plan.getPlanWhere() == null || plan.getPlanWhere().isBlank()) { + throw new ServiceException("履行计划的履约条件不能为空"); + } + if (plan.getPlanTime() == null) { + throw new ServiceException("履行计划的节点日期不能为空"); + } + if (plan.getPlanDay() == null) { + throw new ServiceException("履行计划的提前提醒天数不能为空"); + } + if (amountRequired && plan.getPlanMoney() == null) { + throw new ServiceException("履行计划的款项金额不能为空"); + } + } + } + + private boolean isPlanAmountRequired(String valuationMode) { + return !"0".equals(valuationMode) && !"3".equals(valuationMode); + } + + private void validateActiveDateWithinTerm(ContractLaunchDto contract) { + if (contract.getActiveDate() == null || !"0".equals(contract.getContractPeriodType())) { + return; + } + if (contract.getEffectiveStart() != null && contract.getActiveDate().isBefore(contract.getEffectiveStart())) { + throw new ServiceException("合同生效日期不能早于合同开始日期"); + } + if (contract.getEffectiveEnd() != null && contract.getActiveDate().isAfter(contract.getEffectiveEnd())) { + throw new ServiceException("合同生效日期不能晚于合同结束日期"); + } + } + + @SafeVarargs + private final T firstNonNull(T... values) { + if (values == null) { + return null; + } + for (T value : values) { + if (value != null) { + return value; + } + } + return null; + } + private String trim(String value) { return value == null ? null : value.trim(); } diff --git a/src/main/resources/mapper/contractlaunch/ContractLaunchMapper.xml b/src/main/resources/mapper/contractlaunch/ContractLaunchMapper.xml index cfbd227..32699be 100644 --- a/src/main/resources/mapper/contractlaunch/ContractLaunchMapper.xml +++ b/src/main/resources/mapper/contractlaunch/ContractLaunchMapper.xml @@ -79,6 +79,7 @@ + @@ -184,7 +185,7 @@ EW_AMOUNT_TYPE, DJ_AMOUNT, YJ_AMOUNT, YFK_AMOUNT, BZJ_AMOUNT, BODY_SUMMARY, CONTRACT_TEXT_FILE_NAME, CONTRACT_TEXT_FILE_PATH, CONTRACT_TEXT_FILE_TYPE, CONTRACT_TEXT_FILE_SIZE, SIGNED_FILE_NAME, SIGNED_FILE_PATH, SIGNED_FILE_TYPE, SIGNED_FILE_SIZE, SIGNED_FILE_URL, SIGNED_OFFLINE_REASON, - SIGN_DATE, ACTIVE_DATE, ARCHIVE_DATE, ARCHIVE_KEEPER, ARCHIVE_KEEPER_UNIT, + SIGN_DATE, SEAL_DATE, ACTIVE_DATE, ARCHIVE_DATE, ARCHIVE_KEEPER, ARCHIVE_KEEPER_UNIT, ARCHIVE_KEEPER_UNIT_CODE, INVOICE_DATE, RECEIVE_DATE, REMIND_DAYS, INITIATOR, INITIATOR_DEPT, COMPANY_NAME, ORG_ID, QUERY_SCOPE, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, IS_DELETED, REMARK @@ -262,7 +263,7 @@ TEMPLATE_FIELD_VALUES_JSON, CONTRACT_TEXT_FILE_NAME, CONTRACT_TEXT_FILE_PATH, CONTRACT_TEXT_FILE_TYPE, CONTRACT_TEXT_FILE_SIZE, SIGNED_FILE_NAME, SIGNED_FILE_PATH, SIGNED_FILE_TYPE, SIGNED_FILE_SIZE, SIGNED_FILE_URL, SIGNED_OFFLINE_REASON, - SIGN_DATE, ACTIVE_DATE, ARCHIVE_DATE, ARCHIVE_KEEPER, ARCHIVE_KEEPER_UNIT, + SIGN_DATE, SEAL_DATE, ACTIVE_DATE, ARCHIVE_DATE, ARCHIVE_KEEPER, ARCHIVE_KEEPER_UNIT, ARCHIVE_KEEPER_UNIT_CODE, INVOICE_DATE, RECEIVE_DATE, REMIND_DAYS, INITIATOR, INITIATOR_DEPT, COMPANY_NAME, ORG_ID, QUERY_SCOPE, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, IS_DELETED, REMARK @@ -282,7 +283,7 @@ #{templateFieldValuesJson}, #{contractTextFileName}, #{contractTextFilePath}, #{contractTextFileType}, #{contractTextFileSize}, #{signedFileName}, #{signedFilePath}, #{signedFileType}, #{signedFileSize}, #{signedFileUrl}, #{signedOfflineReason}, - #{signDate}, #{activeDate}, #{archiveDate}, #{archiveKeeper}, #{archiveKeeperUnit}, + #{signDate}, #{sealDate}, #{activeDate}, #{archiveDate}, #{archiveKeeper}, #{archiveKeeperUnit}, #{archiveKeeperUnitCode}, #{invoiceDate}, #{receiveDate}, #{remindDays}, #{initiator}, #{initiatorDept}, #{companyName}, #{orgId}, #{queryScope}, #{createBy}, #{createTime}, #{updateBy}, #{updateTime}, #{isDeleted}, #{remark} @@ -365,6 +366,7 @@ SIGNED_FILE_URL = #{signedFileUrl}, SIGNED_OFFLINE_REASON = #{signedOfflineReason}, SIGN_DATE = #{signDate}, + SEAL_DATE = #{sealDate}, ACTIVE_DATE = #{activeDate}, ARCHIVE_DATE = #{archiveDate}, ARCHIVE_KEEPER = #{archiveKeeper}, diff --git a/zgwl_contract_launch_oracle.sql b/zgwl_contract_launch_oracle.sql index 35976d8..5ac60d1 100644 --- a/zgwl_contract_launch_oracle.sql +++ b/zgwl_contract_launch_oracle.sql @@ -161,6 +161,7 @@ CREATE TABLE SEAL_CONTRACT_LAUNCH_MAIN ( SIGNED_FILE_SIZE NUMBER(19), SIGNED_OFFLINE_REASON VARCHAR2(1000 CHAR), SIGN_DATE DATE, + SEAL_DATE DATE, ACTIVE_DATE DATE, ARCHIVE_DATE DATE, ARCHIVE_KEEPER VARCHAR2(64 CHAR), @@ -348,6 +349,7 @@ COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SIGNED_FILE_TYPE IS '已签署文件 COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SIGNED_FILE_SIZE IS '已签署文件大小'; COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SIGNED_OFFLINE_REASON IS '线下签署原因'; COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SIGN_DATE IS '签署日期'; +COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SEAL_DATE IS '用印时间'; COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.ACTIVE_DATE IS '合同生效日期'; COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.ARCHIVE_DATE IS '归档时间'; COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.ARCHIVE_KEEPER IS '档案保管人'; diff --git a/zgwl_contract_launch_sign_fields_patch_oracle.sql b/zgwl_contract_launch_sign_fields_patch_oracle.sql new file mode 100644 index 0000000..31d3628 --- /dev/null +++ b/zgwl_contract_launch_sign_fields_patch_oracle.sql @@ -0,0 +1,14 @@ +DECLARE + v_count NUMBER; +BEGIN + SELECT COUNT(1) + INTO v_count + FROM USER_TAB_COLUMNS + WHERE TABLE_NAME = 'SEAL_CONTRACT_LAUNCH_MAIN' + AND COLUMN_NAME = 'SEAL_DATE'; + IF v_count = 0 THEN + EXECUTE IMMEDIATE 'ALTER TABLE SEAL_CONTRACT_LAUNCH_MAIN ADD SEAL_DATE DATE'; + EXECUTE IMMEDIATE 'COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SEAL_DATE IS ''用印时间'''; + END IF; +END; +/