✨ 组织机构支持合同初始流水号

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-21 11:51:13 +08:00
parent 8dd0fa3260
commit 777102485c
6 changed files with 63 additions and 4 deletions
@@ -298,6 +298,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
validateBillingPlans(request.getBillingPlanJson());
validatePaymentRatios(request.getPaymentRatioJson());
Map<String, Object> beforeData = buildContractChangeSnapshot(source);
applyContractNo(source, request.getContractNo(), false);
source.setContractName(request.getContractName()); source.setPartyB(request.getPartyB());
source.setStartDate(request.getStartDate()); source.setEndDate(request.getEndDate()); source.setContractFormat(request.getContractFormat());
source.setSettlementMode(request.getSettlementMode()); source.setLegalSealFlag(request.getLegalSealFlag()); source.setCopyCount(request.getCopyCount());
@@ -507,8 +508,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
contractManage.setOrganizationId(TransportBusinessSupport.currentDeptId("合同管理"));
contractManage.setOrganizationName(TransportBusinessSupport.currentDept("合同管理").getDeptName());
}
// 新增始终按部门规则生成合同编号,避免前端预览号并发冲突
contractManage.setContractNo(nextContractNo(contractManage.getOrganizationId()));
applyContractNo(contractManage, contractManage.getContractNo(), true);
if (Func.isEmpty(contractManage.getHandlerUserId())) {
contractManage.setHandlerUserId(AuthUtil.getUserId());
contractManage.setHandlerUserName(AuthUtil.getUserName());
@@ -516,7 +516,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
contractManage.setArchiveStatus(ARCHIVE_STATUS_PENDING);
} else {
ContractManage oldRecord = loadExists(contractManage.getId());
contractManage.setContractNo(oldRecord.getContractNo());
applyContractNo(contractManage, contractManage.getContractNo(), false);
if (Func.isEmpty(contractManage.getOrganizationId())) {
contractManage.setOrganizationId(oldRecord.getOrganizationId());
contractManage.setOrganizationName(oldRecord.getOrganizationName());
@@ -535,6 +535,28 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
}
}
/**
* 保存合同编号。新增未填写时按部门规则生成,已填写或编辑时保留手工编号并校验唯一。
*/
private void applyContractNo(ContractManage contractManage, String contractNo, boolean generateWhenEmpty) {
String normalizedContractNo = TransportBusinessSupport.trimToNull(contractNo);
if (Func.isEmpty(normalizedContractNo)) {
if (!generateWhenEmpty) {
throw new ServiceException("请输入合同编号");
}
normalizedContractNo = nextContractNo(contractManage.getOrganizationId());
}
TransportBusinessSupport.validateLength(normalizedContractNo, 100, "合同编号不能超过100字");
Long duplicatedCount = count(Wrappers.<ContractManage>lambdaQuery()
.eq(ContractManage::getIsDeleted, 0)
.eq(ContractManage::getContractNo, normalizedContractNo)
.ne(Func.isNotEmpty(contractManage.getId()), ContractManage::getId, contractManage.getId()));
if (duplicatedCount != null && duplicatedCount > 0) {
throw new ServiceException("合同编号已存在");
}
contractManage.setContractNo(normalizedContractNo);
}
@Override
public synchronized String nextContractNo(Long organizationId) {
if (Func.isEmpty(organizationId)) {
@@ -558,7 +580,8 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
.orderByDesc(ContractManage::getContractNo)
.last("LIMIT 50"));
Pattern pattern = Pattern.compile("^" + Pattern.quote(prefix) + "(" + year + ")(\\d{3})号$");
int next = 1;
// 当年尚无匹配编号时,从组织配置的初始流水号起编;否则在已有最大流水号上加1
int next = resolveContractInitialSerial(dept);
for (ContractManage item : latestList) {
String contractNo = TransportBusinessSupport.trimToNull(item.getContractNo());
if (Func.isEmpty(contractNo)) {
@@ -577,6 +600,17 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
return head + String.format("%03d", next) + "号";
}
private int resolveContractInitialSerial(Dept dept) {
Integer serial = dept.getContractInitialSerial();
if (serial == null || serial < 1) {
return 1;
}
if (serial > 999) {
throw new ServiceException("组织机构中配置的合同初始流水号不能超过999");
}
return serial;
}
private void refreshArchiveStatusOnApprove(ContractManage contractManage) {
if (hasSealArchiveFile(contractManage.getContractFileJson())) {
contractManage.setArchiveStatus(ARCHIVE_STATUS_ARCHIVED);
@@ -1015,6 +1049,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
private Map<String, Object> buildContractChangeSnapshot(ContractManage contractManage) {
Map<String, Object> data = new LinkedHashMap<>();
data.put("contractNo", contractManage.getContractNo());
data.put("contractName", contractManage.getContractName());
data.put("partyB", contractManage.getPartyB());
data.put("startDate", contractManage.getStartDate());