11
This commit is contained in:
@@ -4,6 +4,7 @@ import com.nbport.zgwl.common.PageResult;
|
|||||||
import com.nbport.zgwl.common.R;
|
import com.nbport.zgwl.common.R;
|
||||||
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchApproveDto;
|
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchApproveDto;
|
||||||
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchArchiveDto;
|
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchArchiveDto;
|
||||||
|
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchCollectSaveDto;
|
||||||
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchDto;
|
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchDto;
|
||||||
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackDto;
|
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackDto;
|
||||||
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackRequestDto;
|
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackRequestDto;
|
||||||
@@ -299,6 +300,32 @@ public class ContractLaunchController {
|
|||||||
return R.success(contractLaunchService.mockCollect(id));
|
return R.success(contractLaunchService.mockCollect(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存采集信息(用印信息 + 签订信息)。
|
||||||
|
*
|
||||||
|
* 签署完成后,在「合同采集」阶段(pending_collect),
|
||||||
|
* 用户通过采集弹窗补充/修改用印信息和签订信息后保存到合同记录。
|
||||||
|
* 与 mock-collect 分开,允许用户在触发采集前先保存草稿。
|
||||||
|
*
|
||||||
|
* 请求体 ContractLaunchCollectSaveDto 字段:
|
||||||
|
* sealIsSeal - 是否用印
|
||||||
|
* sealApproveSame - 用印和审批文本是否一致
|
||||||
|
* sealQuantity - 用印数量
|
||||||
|
* sealDate - 用印时间
|
||||||
|
* signDate - 签订日期
|
||||||
|
* activeDate - 合同生效日期
|
||||||
|
* executorAccount - 合同履行执行人
|
||||||
|
* signedFileName - 签署文件名
|
||||||
|
* signedFilePath - 签署文件路径
|
||||||
|
* signedFileType - 签署文件类型
|
||||||
|
* signedFileSize - 签署文件大小
|
||||||
|
*/
|
||||||
|
@PostMapping("/{id}/collect/save")
|
||||||
|
public R<ContractLaunchDto> saveCollectInfo(@PathVariable("id") Long id,
|
||||||
|
@RequestBody ContractLaunchCollectSaveDto collectDto) {
|
||||||
|
return R.success(contractLaunchService.saveCollectInfo(id, collectDto));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 合同归档。
|
* 合同归档。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合同采集信息保存参数。
|
||||||
|
*
|
||||||
|
* 签署完成后,在「合同采集」阶段(pending_collect → pending_archive),
|
||||||
|
* 用户通过采集弹窗补充用印信息、签订信息后保存到合同记录,
|
||||||
|
* 再调用 dataCollectionPushService.collectContract 推送到法务系统。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ContractLaunchCollectSaveDto implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** 是否用印(1-是,0-否) */
|
||||||
|
private String sealIsSeal;
|
||||||
|
|
||||||
|
/** 用印和审批文本是否一致(1-是,0-否) */
|
||||||
|
private String sealApproveSame;
|
||||||
|
|
||||||
|
/** 用印数量 */
|
||||||
|
private Integer sealQuantity;
|
||||||
|
|
||||||
|
/** 用印时间 */
|
||||||
|
@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 signDate;
|
||||||
|
|
||||||
|
/** 合同生效日期 */
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
|
private LocalDateTime activeDate;
|
||||||
|
|
||||||
|
/** 合同履行执行人(账号) */
|
||||||
|
private String executorAccount;
|
||||||
|
|
||||||
|
/** 签署文件名 */
|
||||||
|
private String signedFileName;
|
||||||
|
|
||||||
|
/** 签署文件路径 */
|
||||||
|
private String signedFilePath;
|
||||||
|
|
||||||
|
/** 签署文件类型 */
|
||||||
|
private String signedFileType;
|
||||||
|
|
||||||
|
/** 签署文件大小 */
|
||||||
|
private Long signedFileSize;
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package com.nbport.zgwl.contractlaunch.service;
|
|||||||
import com.nbport.zgwl.common.PageResult;
|
import com.nbport.zgwl.common.PageResult;
|
||||||
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchApproveDto;
|
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchApproveDto;
|
||||||
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchArchiveDto;
|
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchArchiveDto;
|
||||||
|
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchCollectSaveDto;
|
||||||
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchDto;
|
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchDto;
|
||||||
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackDto;
|
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackDto;
|
||||||
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackSampleDto;
|
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackSampleDto;
|
||||||
@@ -50,6 +51,9 @@ public interface ContractLaunchService {
|
|||||||
/** 签署完成回调(回写签署文件路径,状态变更为待采集) */
|
/** 签署完成回调(回写签署文件路径,状态变更为待采集) */
|
||||||
ContractLaunchDto markSealCompleted(Long id, ContractLaunchSealDto sealDto);
|
ContractLaunchDto markSealCompleted(Long id, ContractLaunchSealDto sealDto);
|
||||||
|
|
||||||
|
/** 保存采集信息(用印+签订信息),用于采集弹窗保存草稿 */
|
||||||
|
ContractLaunchDto saveCollectInfo(Long id, ContractLaunchCollectSaveDto collectDto);
|
||||||
|
|
||||||
/** 模拟合同采集(调用数据采集 collectContract 接口,TODO:替换为真实调用) */
|
/** 模拟合同采集(调用数据采集 collectContract 接口,TODO:替换为真实调用) */
|
||||||
ContractLaunchDto mockCollect(Long id);
|
ContractLaunchDto mockCollect(Long id);
|
||||||
|
|
||||||
|
|||||||
+109
-22
@@ -11,6 +11,7 @@ import com.nbport.zgwl.contractlaunch.dto.ContractLaunchApproveDto;
|
|||||||
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchArchiveDto;
|
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchArchiveDto;
|
||||||
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchArchiveEleDto;
|
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchArchiveEleDto;
|
||||||
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchArchivePaperDto;
|
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchArchivePaperDto;
|
||||||
|
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchCollectSaveDto;
|
||||||
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchDto;
|
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchDto;
|
||||||
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchFileDto;
|
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchFileDto;
|
||||||
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackDto;
|
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackDto;
|
||||||
@@ -125,15 +126,11 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
|||||||
if (securityManager.isSuperAdmin()) {
|
if (securityManager.isSuperAdmin()) {
|
||||||
return "admin";
|
return "admin";
|
||||||
}
|
}
|
||||||
String permissionScope = resolveScopeByDataPermission(currentUser.getDataPermission());
|
|
||||||
if (permissionScope != null) {
|
|
||||||
return permissionScope;
|
|
||||||
}
|
|
||||||
if (authManager.isUserCanAccessSys(currentUser.getId(), SysEnum.MANAGE)) {
|
if (authManager.isUserCanAccessSys(currentUser.getId(), SysEnum.MANAGE)) {
|
||||||
return isAdminUser(currentUser) ? "company" : "personal";
|
return "company";
|
||||||
}
|
}
|
||||||
if (authManager.isUserCanAccessSys(currentUser.getId(), SysEnum.BUSINESS)) {
|
if (authManager.isUserCanAccessSys(currentUser.getId(), SysEnum.BUSINESS)) {
|
||||||
return isAdminUser(currentUser) ? "company" : "personal";
|
return "company";
|
||||||
}
|
}
|
||||||
return "personal";
|
return "personal";
|
||||||
}
|
}
|
||||||
@@ -278,6 +275,10 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
|||||||
}
|
}
|
||||||
SysUserEntity currentUser = adminSecurityManage.getUser();
|
SysUserEntity currentUser = adminSecurityManage.getUser();
|
||||||
boolean singleAgreement = isSingleAgreement(contract);
|
boolean singleAgreement = isSingleAgreement(contract);
|
||||||
|
// 非单方协议:提交法务前做严格校验
|
||||||
|
if (!singleAgreement) {
|
||||||
|
validateSubmitForLaw(contract);
|
||||||
|
}
|
||||||
contract.setStatus(ContractLaunchConstants.STATUS_REVIEWING);
|
contract.setStatus(ContractLaunchConstants.STATUS_REVIEWING);
|
||||||
contract.setApproveStatus(ContractLaunchConstants.APPROVE_STATUS_PENDING);
|
contract.setApproveStatus(ContractLaunchConstants.APPROVE_STATUS_PENDING);
|
||||||
contract.setApproveMessage(singleAgreement ? "已提交内部审批,等待审批" : "已提交法务,等待审批");
|
contract.setApproveMessage(singleAgreement ? "已提交内部审批,等待审批" : "已提交法务,等待审批");
|
||||||
@@ -551,6 +552,54 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
|||||||
* requestDTO.setPayload(payload);
|
* requestDTO.setPayload(payload);
|
||||||
* dataCollectionPushService.collectContract(requestDTO);
|
* dataCollectionPushService.collectContract(requestDTO);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存采集信息(用印+签订信息)。
|
||||||
|
*
|
||||||
|
* 在 pending_collect 状态时,用户通过采集弹窗补充/修改
|
||||||
|
* 用印信息和签订信息后保存到合同记录。
|
||||||
|
* 不触发状态变更,可多次保存;后续再通过 mockCollect(或真实联调的 collect)推送法务。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public ContractLaunchDto saveCollectInfo(Long id, ContractLaunchCollectSaveDto collectDto) {
|
||||||
|
ContractLaunchDto contract = getDetail(id);
|
||||||
|
if (isSingleAgreement(contract)) {
|
||||||
|
throw new ServiceException("单方协议无需执行法务采集");
|
||||||
|
}
|
||||||
|
if (!ContractLaunchConstants.STATUS_PENDING_COLLECT.equals(contract.getStatus())) {
|
||||||
|
throw new ServiceException("仅待采集状态允许保存采集信息");
|
||||||
|
}
|
||||||
|
SysUserEntity currentUser = adminSecurityManage.getUser();
|
||||||
|
|
||||||
|
// 用印信息
|
||||||
|
contract.setSealIsSeal(collectDto.getSealIsSeal());
|
||||||
|
contract.setSealApproveSame(collectDto.getSealApproveSame());
|
||||||
|
contract.setSealQuantity(collectDto.getSealQuantity());
|
||||||
|
contract.setSealDate(collectDto.getSealDate());
|
||||||
|
// 签订信息
|
||||||
|
contract.setSignDate(collectDto.getSignDate());
|
||||||
|
contract.setActiveDate(collectDto.getActiveDate());
|
||||||
|
contract.setExecutorAccount(collectDto.getExecutorAccount());
|
||||||
|
// 签署文件
|
||||||
|
if (collectDto.getSignedFilePath() != null && !collectDto.getSignedFilePath().isBlank()) {
|
||||||
|
contract.setSignedFileName(collectDto.getSignedFileName());
|
||||||
|
contract.setSignedFilePath(collectDto.getSignedFilePath());
|
||||||
|
contract.setSignedFileType(collectDto.getSignedFileType());
|
||||||
|
contract.setSignedFileSize(collectDto.getSignedFileSize());
|
||||||
|
}
|
||||||
|
contract.setUpdateBy(currentUser.getUsername());
|
||||||
|
contract.setUpdateTime(LocalDateTime.now());
|
||||||
|
contractLaunchMapper.updateContract(contract);
|
||||||
|
|
||||||
|
insertLog(id, ContractLaunchConstants.ACTION_COLLECT, "保存采集信息",
|
||||||
|
ContractLaunchConstants.ACTION_STATUS_SUCCESS, "用户通过采集弹窗保存用印/签订信息", null, currentUser);
|
||||||
|
return getDetail(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【测试按钮】模拟合同采集。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public ContractLaunchDto mockCollect(Long id) {
|
public ContractLaunchDto mockCollect(Long id) {
|
||||||
@@ -1159,7 +1208,11 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
|||||||
} else if (isOppositeParty(item)) {
|
} else if (isOppositeParty(item)) {
|
||||||
item.setRoleName("相对方");
|
item.setRoleName("相对方");
|
||||||
}
|
}
|
||||||
|
if (isOppositeParty(item)) {
|
||||||
|
item.setSubjectCode(null);
|
||||||
|
} else {
|
||||||
item.setSubjectCode(trim(item.getSubjectCode()));
|
item.setSubjectCode(trim(item.getSubjectCode()));
|
||||||
|
}
|
||||||
item.setCompanyName(trim(item.getCompanyName()));
|
item.setCompanyName(trim(item.getCompanyName()));
|
||||||
item.setCreditCode(trim(item.getCreditCode()));
|
item.setCreditCode(trim(item.getCreditCode()));
|
||||||
item.setOppositeId(trim(item.getOppositeId()));
|
item.setOppositeId(trim(item.getOppositeId()));
|
||||||
@@ -1284,21 +1337,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
|||||||
if (contract.getContractType() == null || contract.getContractType().isBlank()) {
|
if (contract.getContractType() == null || contract.getContractType().isBlank()) {
|
||||||
contract.setContractType(contract.getContractTypeCode());
|
contract.setContractType(contract.getContractTypeCode());
|
||||||
}
|
}
|
||||||
if (contract.getValuationMode() == null || contract.getValuationMode().isBlank()) {
|
// 以下字段在提交法务时才强制必填(validateSubmitForLaw),草稿保存时放宽
|
||||||
throw new ServiceException("计价方式不能为空");
|
|
||||||
}
|
|
||||||
if (contract.getCurrencyName() == null || contract.getCurrencyName().isBlank()) {
|
|
||||||
throw new ServiceException("币种不能为空");
|
|
||||||
}
|
|
||||||
if (contract.getPaymentMethod() == null || contract.getPaymentMethod().isBlank()) {
|
|
||||||
throw new ServiceException("付款方式不能为空");
|
|
||||||
}
|
|
||||||
if (contract.getSealType() == null || contract.getSealType().isBlank()) {
|
|
||||||
throw new ServiceException("签订方式不能为空");
|
|
||||||
}
|
|
||||||
if (contract.getSealQuantity() != null && contract.getSealQuantity() < 1) {
|
|
||||||
throw new ServiceException("用印数量必须大于等于1");
|
|
||||||
}
|
|
||||||
if (contract.getContractPeriodType() == null || contract.getContractPeriodType().isBlank()) {
|
if (contract.getContractPeriodType() == null || contract.getContractPeriodType().isBlank()) {
|
||||||
throw new ServiceException("合同期限类型不能为空");
|
throw new ServiceException("合同期限类型不能为空");
|
||||||
}
|
}
|
||||||
@@ -1313,7 +1352,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
|||||||
// if (contract.getActiveDate() == null) {
|
// if (contract.getActiveDate() == null) {
|
||||||
// throw new ServiceException("合同生效日期不能为空");
|
// throw new ServiceException("合同生效日期不能为空");
|
||||||
// }
|
// }
|
||||||
validateActiveDateWithinTerm(contract);
|
// activeDate 已移至采集阶段,草稿保存时不校验
|
||||||
if (contract.getPartyList() == null || contract.getPartyList().isEmpty()) {
|
if (contract.getPartyList() == null || contract.getPartyList().isEmpty()) {
|
||||||
throw new ServiceException("至少需要维护一个合同方");
|
throw new ServiceException("至少需要维护一个合同方");
|
||||||
}
|
}
|
||||||
@@ -1364,6 +1403,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
|||||||
&& !item.getFilePath().isBlank()))) {
|
&& !item.getFilePath().isBlank()))) {
|
||||||
throw new ServiceException("当前签订方式必须上传授权委托书附件");
|
throw new ServiceException("当前签订方式必须上传授权委托书附件");
|
||||||
}
|
}
|
||||||
|
// 履行计划在草稿和提交法务时均必填
|
||||||
validatePerformancePlans(contract, false);
|
validatePerformancePlans(contract, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1833,6 +1873,53 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
|||||||
validatePerformancePlans(contract, true);
|
validatePerformancePlans(contract, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交法务前的严格校验:草稿校验 + pushContract 必填项补全 + 履行计划校验
|
||||||
|
*/
|
||||||
|
private void validateSubmitForLaw(ContractLaunchDto contract) {
|
||||||
|
// 先跑草稿基本校验(不含已移除的采集字段)
|
||||||
|
validateDraft(contract);
|
||||||
|
// 补全 pushContract 必填项
|
||||||
|
if (contract.getValuationMode() == null || contract.getValuationMode().isBlank()) {
|
||||||
|
throw new ServiceException("计价方式不能为空");
|
||||||
|
}
|
||||||
|
if (contract.getCurrencyName() == null || contract.getCurrencyName().isBlank()) {
|
||||||
|
throw new ServiceException("币种不能为空");
|
||||||
|
}
|
||||||
|
if (contract.getSealType() == null || contract.getSealType().isBlank()) {
|
||||||
|
throw new ServiceException("签订方式不能为空");
|
||||||
|
}
|
||||||
|
if (contract.getIsElectron() == null || contract.getIsElectron().isBlank()) {
|
||||||
|
throw new ServiceException("签署方式不能为空");
|
||||||
|
}
|
||||||
|
if (contract.getPaymentDirection() == null || contract.getPaymentDirection().isBlank()) {
|
||||||
|
throw new ServiceException("收支方向不能为空");
|
||||||
|
}
|
||||||
|
if (contract.getTextSource() == null || contract.getTextSource().isBlank()) {
|
||||||
|
throw new ServiceException("文本来源不能为空");
|
||||||
|
}
|
||||||
|
if (contract.getContractSource() == null || contract.getContractSource().isBlank()) {
|
||||||
|
throw new ServiceException("合同来源不能为空");
|
||||||
|
}
|
||||||
|
if (contract.getExecutorAccount() == null || contract.getExecutorAccount().isBlank()) {
|
||||||
|
throw new ServiceException("合同执行人不能为空");
|
||||||
|
}
|
||||||
|
if (contract.getIsMajorContract() == null) {
|
||||||
|
throw new ServiceException("是否重大合同不能为空");
|
||||||
|
}
|
||||||
|
if (contract.getIsOpenBidding() == null) {
|
||||||
|
throw new ServiceException("是否公开招标不能为空");
|
||||||
|
}
|
||||||
|
if (contract.getIsSgat() == null || contract.getIsSgat().isBlank()) {
|
||||||
|
throw new ServiceException("是否涉及港澳台不能为空");
|
||||||
|
}
|
||||||
|
if (contract.getNeedAmendments() == null || contract.getNeedAmendments().isBlank()) {
|
||||||
|
throw new ServiceException("是否需修订条款不能为空");
|
||||||
|
}
|
||||||
|
// 履行计划校验(提交法务时必填)
|
||||||
|
validatePerformancePlans(contract, false);
|
||||||
|
}
|
||||||
|
|
||||||
private void validatePerformancePlans(ContractLaunchDto contract, boolean requirePlanId) {
|
private void validatePerformancePlans(ContractLaunchDto contract, boolean requirePlanId) {
|
||||||
if (contract.getPerformancePlans() == null || contract.getPerformancePlans().isEmpty()) {
|
if (contract.getPerformancePlans() == null || contract.getPerformancePlans().isEmpty()) {
|
||||||
throw new ServiceException("履行计划不能为空");
|
throw new ServiceException("履行计划不能为空");
|
||||||
|
|||||||
Reference in New Issue
Block a user