diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OASyncServiceImpl.java b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OASyncServiceImpl.java
index 6f3143a4..e133b6c5 100644
--- a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OASyncServiceImpl.java
+++ b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OASyncServiceImpl.java
@@ -263,7 +263,7 @@ public class OASyncServiceImpl implements IOASyncService {
}
/**
- * 从 OA 人员列表同步组织与人员
+ * 从 OA 人员列表同步人员并绑定已有组织(不维护组织树,须先同步组织架构)
*
* @param startTime 增量查询开始时间,为空则全量
* @return 处理的人员数量
@@ -284,7 +284,7 @@ public class OASyncServiceImpl implements IOASyncService {
}
/**
- * 按页从 OA 人员列表同步组织与人员
+ * 按页从 OA 人员列表同步人员并绑定已有组织(不维护组织树,须先同步组织架构)
*
* @param current 当前页
* @param size 每页条数
diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OaUserListSyncHelper.java b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OaUserListSyncHelper.java
index 77ba09d0..87e3cd50 100644
--- a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OaUserListSyncHelper.java
+++ b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OaUserListSyncHelper.java
@@ -30,7 +30,6 @@ import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
-import org.springblade.common.constant.DataStatusEnum;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.utils.DigestUtil;
@@ -53,7 +52,6 @@ import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -66,10 +64,9 @@ import java.util.stream.Collectors;
import static org.springblade.common.constant.CommonConstant.DEFAULT_PARAM_PASSWORD;
import static org.springblade.common.constant.CommonConstant.DEFAULT_PARAM_ROLE;
import static org.springblade.common.constant.CommonConstant.DEFAULT_ROLE;
-import static org.springblade.common.constant.CommonConstant.YES;
/**
- * 从 OA 人员列表提取组织并同步人员
+ * OA 人员同步:绑定已有组织机构,不维护组织树
*
* @author Chill
*/
@@ -86,104 +83,312 @@ public class OaUserListSyncHelper {
private final IRoleService roleService;
/**
- * 从人员数据提取二级公司、三级部门,并挂到集团顶级(id=1/GWWL) 下
+ * 加载已有组织索引,并将人员旁路产生的 OAC/OAD 存量归并到正式组织。
+ *
人员同步不再新建/更新组织树,须先执行组织架构同步。
*
* @param oaPersons OA人员
- * @return 组织索引
+ * @return 组织索引(仅含已有组织)
*/
public OaOrgIndex syncOrgsFromPersons(List oaPersons) {
OaOrgIndex orgIndex = new OaOrgIndex();
if (CollectionUtil.isEmpty(oaPersons)) {
return orgIndex;
}
- Date orgSyncStart = new Date();
- Dept rootCompany = this.getOrCreateRootCompany();
- String tenantId = resolveTenantId();
- Map companyPersonMap = new LinkedHashMap<>();
- Map departmentPersonMap = new LinkedHashMap<>();
- for (OAPersonResponse oaPerson : oaPersons) {
- String companyKey = resolveCompanyKey(oaPerson);
- if (StringUtils.isNotBlank(companyKey) && StringUtils.isNotBlank(oaPerson.getSubcompanyname())) {
- companyPersonMap.putIfAbsent(companyKey, oaPerson);
- }
- String departmentKey = resolveDepartmentKey(oaPerson);
- if (StringUtils.isNotBlank(departmentKey) && StringUtils.isNotBlank(oaPerson.getDepartmentname())
- && StringUtils.isNotBlank(oaPerson.getSubcompanyname())) {
- departmentPersonMap.putIfAbsent(departmentKey, oaPerson);
- }
- }
-
- Map existingCompanyByCode = new HashMap<>();
- Map existingCompanyByName = new HashMap<>();
- deptService.list(Wrappers.lambdaQuery()
- .eq(Dept::getParentId, rootCompany.getId())
- .eq(Dept::getDeptCategory, DeptCategory.COMPANY.getCode())
- ).forEach(dept -> {
- if (StringUtils.isNotBlank(dept.getDeptCode())) {
- existingCompanyByCode.put(dept.getDeptCode(), dept);
- }
- if (StringUtils.isNotBlank(dept.getDeptName())) {
- existingCompanyByName.put(dept.getDeptName(), dept);
- }
- });
- List addCompanies = new ArrayList<>();
- List updateCompanies = new ArrayList<>();
- companyPersonMap.forEach((companyKey, oaPerson) -> {
- String oaCode = buildCompanyCode(oaPerson, companyKey);
- Dept existing = existingCompanyByCode.get(oaCode);
- if (existing == null) {
- existing = existingCompanyByName.get(oaPerson.getSubcompanyname());
- }
- Dept company = this.upsertOrg(oaPerson.getSubcompanyname(), oaCode, existing, rootCompany, tenantId,
- DeptCategory.COMPANY, addCompanies, updateCompanies);
- orgIndex.companyByOaId.put(companyKey, company);
- });
- this.saveOrgs(addCompanies, updateCompanies, DeptCategory.COMPANY);
-
- Map existingDeptByCode = new HashMap<>();
- Map existingDeptByParentAndName = new HashMap<>();
- List companyIds = orgIndex.companyByOaId.values().stream()
- .map(Dept::getId)
- .filter(Objects::nonNull)
- .distinct()
- .toList();
- if (CollectionUtil.isNotEmpty(companyIds)) {
- deptService.list(Wrappers.lambdaQuery()
- .in(Dept::getParentId, companyIds)
- .eq(Dept::getDeptCategory, DeptCategory.DEPT.getCode())
- ).forEach(dept -> {
- if (StringUtils.isNotBlank(dept.getDeptCode())) {
- existingDeptByCode.put(dept.getDeptCode(), dept);
- }
- if (dept.getParentId() != null && StringUtils.isNotBlank(dept.getDeptName())) {
- existingDeptByParentAndName.put(dept.getParentId() + "#" + dept.getDeptName(), dept);
- }
- });
- }
- List addDepartments = new ArrayList<>();
- List updateDepartments = new ArrayList<>();
- departmentPersonMap.forEach((departmentKey, oaPerson) -> {
- Dept parentCompany = orgIndex.findCompany(oaPerson);
- if (parentCompany == null || parentCompany.getId() == null) {
- return;
- }
- String oaCode = buildDepartmentCode(oaPerson, departmentKey);
- Dept existing = existingDeptByCode.get(oaCode);
- if (existing == null) {
- existing = existingDeptByParentAndName.get(parentCompany.getId() + "#" + oaPerson.getDepartmentname());
- }
- Dept department = this.upsertOrg(oaPerson.getDepartmentname(), oaCode, existing, parentCompany, tenantId,
- DeptCategory.DEPT, addDepartments, updateDepartments);
- orgIndex.deptByOaId.put(departmentKey, department);
- orgIndex.deptByCompanyAndName.put(resolveCompanyKey(oaPerson) + "#" + oaPerson.getDepartmentname(), department);
- });
- this.saveOrgs(addDepartments, updateDepartments, DeptCategory.DEPT);
- deptService.updateAncestors(orgSyncStart);
- ComposeLogUtil.getLastLog().info("同步人员提取组织完成,二级公司{}个,三级部门{}个",
+ this.repairPersonBypassOrgs();
+ this.loadExistingOrgIndex(orgIndex);
+ ComposeLogUtil.getLastLog().info("人员同步绑定已有组织,二级公司{}个,三级部门{}个",
orgIndex.companyByOaId.size(), orgIndex.deptByOaId.size());
return orgIndex;
}
+ /**
+ * 将 OAC/OAD 旁路节点上的人员关系迁移到同 oa_id 的正式组织,并逻辑删除旁路节点
+ */
+ private void repairPersonBypassOrgs() {
+ List companyList = deptService.list(Wrappers.lambdaQuery()
+ .eq(Dept::getDeptCategory, DeptCategory.COMPANY.getCode()));
+ List departmentList = deptService.list(Wrappers.lambdaQuery()
+ .eq(Dept::getDeptCategory, DeptCategory.DEPT.getCode()));
+ Map officialCompanyByOaId = new HashMap<>();
+ Map officialDeptByOaId = new HashMap<>();
+ Map companyById = new HashMap<>();
+ for (Dept company : companyList) {
+ if (company.getId() != null) {
+ companyById.put(company.getId(), company);
+ }
+ if (!isPersonBypassCode(company.getDeptCode(), DeptCategory.COMPANY)) {
+ this.putPreferredByOaId(officialCompanyByOaId, company, DeptCategory.COMPANY);
+ }
+ }
+ for (Dept department : departmentList) {
+ if (!isPersonBypassCode(department.getDeptCode(), DeptCategory.DEPT)) {
+ this.putPreferredByOaId(officialDeptByOaId, department, DeptCategory.DEPT);
+ }
+ }
+
+ Set softDeleteIds = new HashSet<>();
+ Set affectedUserIds = new HashSet<>();
+ int migratedDeptBindingCount = 0;
+ int migratedCompanyBindingCount = 0;
+
+ for (Dept bypass : departmentList) {
+ if (!isPersonBypassCode(bypass.getDeptCode(), DeptCategory.DEPT) || bypass.getId() == null) {
+ continue;
+ }
+ String oaId = StringUtils.trimToNull(bypass.getOaId());
+ if (oaId == null) {
+ oaId = extractOaIdFromBypassCode(bypass.getDeptCode(), DeptCategory.DEPT);
+ }
+ if (oaId == null) {
+ continue;
+ }
+ Dept official = officialDeptByOaId.get(oaId);
+ if (official == null || official.getId() == null || Objects.equals(official.getId(), bypass.getId())
+ || isPersonBypassCode(official.getDeptCode(), DeptCategory.DEPT)) {
+ continue;
+ }
+ Dept officialCompany = resolveBelongCompany(official, companyById);
+ migratedDeptBindingCount += this.migrateUserDeptBindings(bypass, official, officialCompany, affectedUserIds);
+ softDeleteIds.add(bypass.getId());
+ }
+
+ for (Dept bypass : companyList) {
+ if (!isPersonBypassCode(bypass.getDeptCode(), DeptCategory.COMPANY) || bypass.getId() == null) {
+ continue;
+ }
+ String oaId = StringUtils.trimToNull(bypass.getOaId());
+ if (oaId == null) {
+ oaId = extractOaIdFromBypassCode(bypass.getDeptCode(), DeptCategory.COMPANY);
+ }
+ if (oaId == null) {
+ continue;
+ }
+ Dept official = officialCompanyByOaId.get(oaId);
+ if (official == null || official.getId() == null || Objects.equals(official.getId(), bypass.getId())
+ || isPersonBypassCode(official.getDeptCode(), DeptCategory.COMPANY)) {
+ continue;
+ }
+ migratedCompanyBindingCount += this.migrateUserCompanyBindings(bypass, official, affectedUserIds);
+ long childCount = deptService.count(Wrappers.lambdaQuery().eq(Dept::getParentId, bypass.getId()));
+ if (childCount == 0) {
+ softDeleteIds.add(bypass.getId());
+ } else {
+ ComposeLogUtil.getLastLog().warn("旁路公司仍有子节点,暂不删除 companyId={} deptCode={} childCount={}",
+ bypass.getId(), bypass.getDeptCode(), childCount);
+ }
+ }
+
+ if (CollectionUtil.isNotEmpty(softDeleteIds)) {
+ deptService.removeByIds(softDeleteIds);
+ ComposeLogUtil.getLastLog().info("人员同步归并旁路组织完成,迁移部门关系{}条,迁移公司关系{}条,逻辑删除旁路节点{}个",
+ migratedDeptBindingCount, migratedCompanyBindingCount, softDeleteIds.size());
+ } else if (migratedDeptBindingCount > 0 || migratedCompanyBindingCount > 0) {
+ ComposeLogUtil.getLastLog().info("人员同步归并旁路组织完成,迁移部门关系{}条,迁移公司关系{}条",
+ migratedDeptBindingCount, migratedCompanyBindingCount);
+ }
+ this.refreshUserDeptFields(affectedUserIds);
+ }
+
+ /**
+ * 仅加载已有组织,按 oa_id / 名称建立索引供人员绑定
+ */
+ private void loadExistingOrgIndex(OaOrgIndex orgIndex) {
+ Map companyByOaId = new HashMap<>();
+ Map companyByName = new HashMap<>();
+ Map companyById = new HashMap<>();
+ deptService.list(Wrappers.lambdaQuery()
+ .eq(Dept::getDeptCategory, DeptCategory.COMPANY.getCode())
+ ).forEach(dept -> {
+ if (dept.getId() != null) {
+ companyById.put(dept.getId(), dept);
+ }
+ this.putPreferredByOaKey(companyByOaId, resolveOrgOaKey(dept, DeptCategory.COMPANY), dept, DeptCategory.COMPANY);
+ if (StringUtils.isNotBlank(dept.getDeptName())) {
+ Dept previous = companyByName.get(dept.getDeptName());
+ if (previous == null
+ || (isPersonBypassCode(previous.getDeptCode(), DeptCategory.COMPANY)
+ && !isPersonBypassCode(dept.getDeptCode(), DeptCategory.COMPANY))) {
+ companyByName.put(dept.getDeptName(), dept);
+ }
+ }
+ });
+ companyByOaId.forEach((oaId, dept) -> orgIndex.companyByOaId.put(oaId, dept));
+ companyByName.forEach((name, dept) -> orgIndex.companyByOaId.putIfAbsent("NAME:" + name, dept));
+
+ Map deptByOaId = new HashMap<>();
+ deptService.list(Wrappers.lambdaQuery()
+ .eq(Dept::getDeptCategory, DeptCategory.DEPT.getCode())
+ ).forEach(dept -> {
+ this.putPreferredByOaKey(deptByOaId, resolveOrgOaKey(dept, DeptCategory.DEPT), dept, DeptCategory.DEPT);
+ Dept parentCompany = resolveBelongCompany(dept, companyById);
+ if (parentCompany == null || StringUtils.isBlank(dept.getDeptName())) {
+ return;
+ }
+ String companyKey = resolveOrgOaKey(parentCompany, DeptCategory.COMPANY);
+ if (companyKey == null && StringUtils.isNotBlank(parentCompany.getDeptName())) {
+ companyKey = "NAME:" + parentCompany.getDeptName();
+ }
+ if (companyKey == null) {
+ return;
+ }
+ String nameKey = companyKey + "#" + dept.getDeptName();
+ Dept previous = orgIndex.deptByCompanyAndName.get(nameKey);
+ if (previous == null
+ || (isPersonBypassCode(previous.getDeptCode(), DeptCategory.DEPT)
+ && !isPersonBypassCode(dept.getDeptCode(), DeptCategory.DEPT))) {
+ orgIndex.deptByCompanyAndName.put(nameKey, dept);
+ }
+ });
+ orgIndex.deptByOaId.putAll(deptByOaId);
+ }
+
+ /** 优先取 oa_id;旁路空 oa_id 时从 OAC/OAD 编码后缀解析 */
+ private String resolveOrgOaKey(Dept dept, DeptCategory deptCategory) {
+ if (dept == null) {
+ return null;
+ }
+ String oaId = StringUtils.trimToNull(dept.getOaId());
+ if (oaId != null) {
+ return oaId;
+ }
+ return extractOaIdFromBypassCode(dept.getDeptCode(), deptCategory);
+ }
+
+ private int migrateUserDeptBindings(Dept bypass, Dept official, Dept officialCompany, Set affectedUserIds) {
+ List bindingList = userDeptService.list(Wrappers.lambdaQuery()
+ .and(wrapper -> wrapper.eq(UserDept::getDeptId, bypass.getId())
+ .or().eq(UserDept::getDeptCode, bypass.getDeptCode())));
+ if (CollectionUtil.isEmpty(bindingList)) {
+ return 0;
+ }
+ Set userIds = bindingList.stream()
+ .map(UserDept::getUserId)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toSet());
+ Map existingByKey = userDeptService.list(Wrappers.lambdaQuery()
+ .in(UserDept::getUserId, userIds)
+ ).stream()
+ .collect(Collectors.toMap(this::getUserDeptKey, userDept -> userDept, (first, second) -> first));
+ List updateList = new ArrayList<>();
+ List removeIds = new ArrayList<>();
+ for (UserDept binding : bindingList) {
+ if (binding.getUserId() == null) {
+ continue;
+ }
+ affectedUserIds.add(binding.getUserId());
+ String companyCode = officialCompany != null ? officialCompany.getDeptCode() : binding.getCompanyCode();
+ String companyName = officialCompany != null ? officialCompany.getDeptName() : binding.getCompanyName();
+ String newKey = binding.getUserId() + StringUtils.defaultString(companyCode)
+ + StringUtils.defaultString(official.getDeptCode());
+ UserDept alreadyOfficial = existingByKey.get(newKey);
+ if (alreadyOfficial != null && !Objects.equals(alreadyOfficial.getId(), binding.getId())) {
+ removeIds.add(binding.getId());
+ continue;
+ }
+ binding.setDeptId(official.getId());
+ binding.setDeptCode(official.getDeptCode());
+ binding.setDeptName(official.getDeptName());
+ if (officialCompany != null) {
+ binding.setCompanyCode(companyCode);
+ binding.setCompanyName(companyName);
+ }
+ updateList.add(binding);
+ existingByKey.put(newKey, binding);
+ }
+ if (CollectionUtil.isNotEmpty(updateList)) {
+ userDeptService.updateBatchById(updateList);
+ }
+ if (CollectionUtil.isNotEmpty(removeIds)) {
+ userDeptService.removeByIds(removeIds);
+ }
+ return updateList.size() + removeIds.size();
+ }
+
+ private int migrateUserCompanyBindings(Dept bypass, Dept official, Set affectedUserIds) {
+ if (StringUtils.isBlank(bypass.getDeptCode())) {
+ return 0;
+ }
+ List bindingList = userDeptService.list(Wrappers.lambdaQuery()
+ .eq(UserDept::getCompanyCode, bypass.getDeptCode()));
+ if (CollectionUtil.isEmpty(bindingList)) {
+ return 0;
+ }
+ List updateList = new ArrayList<>();
+ for (UserDept binding : bindingList) {
+ if (binding.getUserId() != null) {
+ affectedUserIds.add(binding.getUserId());
+ }
+ binding.setCompanyCode(official.getDeptCode());
+ binding.setCompanyName(official.getDeptName());
+ updateList.add(binding);
+ }
+ userDeptService.updateBatchById(updateList);
+ return updateList.size();
+ }
+
+ private void refreshUserDeptFields(Set userIds) {
+ if (CollectionUtil.isEmpty(userIds)) {
+ return;
+ }
+ List userDeptIdsList = userDeptService.queryUserDeptIds(userIds);
+ List updateUserParams = userDeptIdsList.stream()
+ .filter(userDeptIds -> StringUtils.isNotBlank(userDeptIds.getDeptIds()))
+ .filter(userDeptIds -> {
+ int deptIdLength = userDeptIds.getDeptIds().length();
+ int deptCodesLength = StringUtils.length(userDeptIds.getDeptCodes());
+ return deptIdLength <= MAX_DEPT_ID_LENGTH && deptCodesLength <= MAX_DEPT_ID_LENGTH;
+ })
+ .map(userDeptIds -> {
+ User user = new User();
+ user.setId(userDeptIds.getUserId());
+ user.setDeptId(userDeptIds.getDeptIds());
+ user.setDeptCodes(userDeptIds.getDeptCodes());
+ return user;
+ }).toList();
+ if (CollectionUtil.isNotEmpty(updateUserParams)) {
+ userService.updateBatchById(updateUserParams);
+ }
+ }
+
+ private Dept resolveBelongCompany(Dept department, Map companyById) {
+ if (department == null) {
+ return null;
+ }
+ if (department.getParentId() != null) {
+ Dept parent = companyById.get(department.getParentId());
+ if (parent != null) {
+ return parent;
+ }
+ }
+ if (StringUtils.isNotBlank(department.getBelongCompanyCode())) {
+ return companyById.values().stream()
+ .filter(company -> department.getBelongCompanyCode().equals(company.getDeptCode()))
+ .findFirst()
+ .orElse(null);
+ }
+ return null;
+ }
+
+ /**
+ * 从 OAC37 / OAD37 旁路编码解析 OA 主键;哈希旁路(OACNxxx)返回 null
+ */
+ private String extractOaIdFromBypassCode(String deptCode, DeptCategory deptCategory) {
+ if (StringUtils.isBlank(deptCode) || !isPersonBypassCode(deptCode, deptCategory)) {
+ return null;
+ }
+ String prefix = DeptCategory.COMPANY.equals(deptCategory)
+ ? OAConvertConstant.COMPANY_OA_PREFIX
+ : OAConvertConstant.DEPARTMENT_OA_PREFIX;
+ if (deptCode.length() <= prefix.length()) {
+ return null;
+ }
+ String suffix = deptCode.substring(prefix.length());
+ if (suffix.isEmpty() || suffix.startsWith("N")) {
+ return null;
+ }
+ return suffix;
+ }
+
/**
* 同步人员并绑定到三级部门
*
@@ -395,73 +600,47 @@ public class OaUserListSyncHelper {
return localModified.equals(remoteModified);
}
- private Dept getOrCreateRootCompany() {
- return deptService.ensureOaSyncRootDept();
+ private boolean isPersonBypassCode(String deptCode, DeptCategory deptCategory) {
+ if (StringUtils.isBlank(deptCode)) {
+ return true;
+ }
+ if (DeptCategory.COMPANY.equals(deptCategory)) {
+ return deptCode.startsWith(OAConvertConstant.COMPANY_OA_PREFIX);
+ }
+ return deptCode.startsWith(OAConvertConstant.DEPARTMENT_OA_PREFIX);
}
- private Dept upsertOrg(String name, String oaCode, Dept existing, Dept parent, String tenantId,
- DeptCategory deptCategory, List addList, List updateList) {
- if (existing != null) {
- Dept updateParam = new Dept();
- updateParam.setId(existing.getId());
- updateParam.setDeptName(name);
- updateParam.setFullName(name);
- updateParam.setShortName(name);
- updateParam.setParentId(parent.getId());
- updateParam.setParentCode(parent.getDeptCode());
- updateParam.setAncestors(buildAncestors(parent));
- updateParam.setIsOa(YES);
- updateParam.setSyncTime(new Date());
- updateList.add(updateParam);
- existing.setDeptName(name);
- existing.setFullName(name);
- existing.setShortName(name);
- existing.setParentId(parent.getId());
- existing.setParentCode(parent.getDeptCode());
- existing.setAncestors(updateParam.getAncestors());
- return existing;
+ /** 同一 oa_id 多条时优先正式编码,避免人员挂到 OAC/OAD 旁路重复节点。 */
+ private void putPreferredByOaId(Map byOaId, Dept dept, DeptCategory deptCategory) {
+ if (dept == null || StringUtils.isBlank(dept.getOaId())) {
+ return;
}
- Dept dept = this.buildOrgDept(name, oaCode, parent, tenantId, deptCategory);
- dept.setId(DefaultIdentifierGenerator.getInstance().nextId(null));
- addList.add(dept);
- return dept;
+ this.putPreferredByOaKey(byOaId, dept.getOaId().trim(), dept, deptCategory);
}
- private void saveOrgs(List addList, List updateList, DeptCategory deptCategory) {
- if (CollectionUtil.isNotEmpty(addList)) {
- ComposeLogUtil.getLastLog().info("批量新增{}:{}", deptCategory.getName(), addList.size());
- deptService.saveBatch(addList);
+ private void putPreferredByOaKey(Map byOaId, String oaKey, Dept dept, DeptCategory deptCategory) {
+ if (dept == null || StringUtils.isBlank(oaKey)) {
+ return;
}
- if (CollectionUtil.isNotEmpty(updateList)) {
- ComposeLogUtil.getLastLog().info("批量修改{}:{}", deptCategory.getName(), updateList.size());
- deptService.updateBatchById(updateList);
+ Dept previous = byOaId.get(oaKey);
+ if (previous == null) {
+ byOaId.put(oaKey, dept);
+ return;
+ }
+ boolean previousBypass = isPersonBypassCode(previous.getDeptCode(), deptCategory);
+ boolean currentBypass = isPersonBypassCode(dept.getDeptCode(), deptCategory);
+ if (previousBypass && !currentBypass) {
+ byOaId.put(oaKey, dept);
}
- }
-
- private Dept buildOrgDept(String name, String deptCode, Dept parent, String tenantId, DeptCategory deptCategory) {
- Dept dept = new Dept();
- dept.setTenantId(tenantId);
- dept.setParentId(parent.getId());
- dept.setParentCode(parent.getDeptCode());
- dept.setAncestors(this.buildAncestors(parent));
- dept.setDeptName(name);
- dept.setFullName(name);
- dept.setShortName(name);
- dept.setDeptCode(deptCode);
- dept.setBelongCompanyCode(DeptCategory.COMPANY.equals(deptCategory) ? deptCode : parent.getBelongCompanyCode());
- dept.setDeptCategory(deptCategory.getCode());
- dept.setSort(0);
- dept.setStatus(DataStatusEnum.ENABLE.getCode());
- dept.setIsDeleted(BladeConstant.DB_NOT_DELETED);
- dept.setIsOa(YES);
- dept.setIsPlatformCompany(0);
- dept.setSyncTime(new Date());
- return dept;
}
private UserDept buildUserDept(OAPersonResponse oaPerson, Map userMap, OaOrgIndex orgIndex) {
Dept department = orgIndex.findDept(oaPerson);
if (department == null || department.getId() == null) {
+ ComposeLogUtil.getLastLog().warn(
+ "人员未匹配到已有部门,请先同步组织架构 account={} departmentid={} departmentname={} subcompanyid1={}",
+ userConvert.resolveAccount(oaPerson), oaPerson.getDepartmentid(), oaPerson.getDepartmentname(),
+ oaPerson.getSubcompanyid1());
return null;
}
UserDept userDept = userConvert.person2userDept(oaPerson, userMap);
@@ -493,55 +672,6 @@ public class OaUserListSyncHelper {
return roleList.get(0).getId().toString();
}
- private String resolveCompanyKey(OAPersonResponse oaPerson) {
- if (oaPerson == null) {
- return null;
- }
- if (StringUtils.isNotBlank(oaPerson.getSubcompanyid1())) {
- return oaPerson.getSubcompanyid1().trim();
- }
- if (StringUtils.isNotBlank(oaPerson.getSubcompanyname())) {
- return "NAME:" + oaPerson.getSubcompanyname().trim();
- }
- return null;
- }
-
- private String resolveDepartmentKey(OAPersonResponse oaPerson) {
- if (oaPerson == null) {
- return null;
- }
- if (StringUtils.isNotBlank(oaPerson.getDepartmentid())) {
- return oaPerson.getDepartmentid().trim();
- }
- String companyKey = resolveCompanyKey(oaPerson);
- if (StringUtils.isNotBlank(companyKey) && StringUtils.isNotBlank(oaPerson.getDepartmentname())) {
- return companyKey + ":" + oaPerson.getDepartmentname().trim();
- }
- return null;
- }
-
- private String buildCompanyCode(OAPersonResponse oaPerson, String companyKey) {
- if (StringUtils.isNotBlank(oaPerson.getSubcompanyid1())) {
- return OAConvertConstant.COMPANY_OA_PREFIX + oaPerson.getSubcompanyid1().trim();
- }
- return OAConvertConstant.COMPANY_OA_PREFIX + "N" + Math.abs(companyKey.hashCode());
- }
-
- private String buildDepartmentCode(OAPersonResponse oaPerson, String departmentKey) {
- if (StringUtils.isNotBlank(oaPerson.getDepartmentid())) {
- return OAConvertConstant.DEPARTMENT_OA_PREFIX + oaPerson.getDepartmentid().trim();
- }
- return OAConvertConstant.DEPARTMENT_OA_PREFIX + "N" + Math.abs(departmentKey.hashCode());
- }
-
- private String buildAncestors(Dept parent) {
- String ancestors = parent.getAncestors();
- if (StringUtils.isBlank(ancestors)) {
- ancestors = String.valueOf(BladeConstant.TOP_PARENT_ID);
- }
- return ancestors + "," + parent.getId();
- }
-
private String resolveTenantId() {
String tenantId = AuthUtil.getTenantId();
if (StringUtils.isBlank(tenantId)) {
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/BillPaymentMapper.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/BillPaymentMapper.java
index 2b2db978..ca20187c 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/BillPaymentMapper.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/BillPaymentMapper.java
@@ -27,9 +27,20 @@ package org.springblade.transport.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
import org.springblade.transport.pojo.entity.BillPayment;
/** 汇票付款 Mapper。 @author Chill */
@Mapper
public interface BillPaymentMapper extends BaseMapper {
+
+ /**
+ * 查询指定租户、指定日期前缀下已使用的最大汇票付款流水号。
+ * 不过滤逻辑删除数据,避免唯一索引仍占用历史编号时重复生成。
+ */
+ @Select("SELECT COALESCE(MAX(CAST(SUBSTRING(payment_no, CHAR_LENGTH(#{prefix}) + 1) AS UNSIGNED)), 0) "
+ + "FROM blade_bill_payment WHERE tenant_id = #{tenantId} "
+ + "AND payment_no LIKE CONCAT(#{prefix}, '%')")
+ Long selectMaxDailySequence(@Param("tenantId") String tenantId, @Param("prefix") String prefix);
}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/FormalSettlementMapper.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/FormalSettlementMapper.java
index 36f22485..2c01c226 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/FormalSettlementMapper.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/FormalSettlementMapper.java
@@ -29,4 +29,13 @@ public interface FormalSettlementMapper extends BaseMapper {
/** 恢复逻辑删除的正式结算单主记录。 */
@Update("UPDATE blade_formal_settlement SET is_deleted = 0 WHERE tenant_id = #{tenantId} AND id = #{id} AND is_deleted = 1")
int restoreByIdIncludingDeleted(@Param("tenantId") String tenantId, @Param("id") Long id);
+
+ /**
+ * 查询指定租户、指定日期前缀下已使用的最大正式结算单流水号。
+ * 不过滤逻辑删除数据,避免唯一索引仍占用历史编号时重复生成。
+ */
+ @Select("SELECT COALESCE(MAX(CAST(SUBSTRING(formal_settlement_no, CHAR_LENGTH(#{prefix}) + 1) AS UNSIGNED)), 0) "
+ + "FROM blade_formal_settlement WHERE tenant_id = #{tenantId} "
+ + "AND formal_settlement_no LIKE CONCAT(#{prefix}, '%')")
+ Long selectMaxDailySequence(@Param("tenantId") String tenantId, @Param("prefix") String prefix);
}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/FormalSettlementPaymentMapper.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/FormalSettlementPaymentMapper.java
index fe41e31b..2e0e61a1 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/FormalSettlementPaymentMapper.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/FormalSettlementPaymentMapper.java
@@ -10,9 +10,20 @@ package org.springblade.transport.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
import org.springblade.transport.pojo.entity.FormalSettlementPayment;
/** 正式结算付款申请 Mapper。 @author Chill */
@Mapper
public interface FormalSettlementPaymentMapper extends BaseMapper {
+
+ /**
+ * 查询指定租户、指定日期前缀下已使用的最大付款申请流水号。
+ * 不过滤逻辑删除数据,避免唯一索引仍占用历史编号时重复生成。
+ */
+ @Select("SELECT COALESCE(MAX(CAST(SUBSTRING(payment_no, CHAR_LENGTH(#{prefix}) + 1) AS UNSIGNED)), 0) "
+ + "FROM blade_formal_settlement_payment WHERE tenant_id = #{tenantId} "
+ + "AND payment_no LIKE CONCAT(#{prefix}, '%')")
+ Long selectMaxDailySequence(@Param("tenantId") String tenantId, @Param("prefix") String prefix);
}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/InvoiceApplicationMapper.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/InvoiceApplicationMapper.java
index 9e9db78c..4bcca990 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/InvoiceApplicationMapper.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/InvoiceApplicationMapper.java
@@ -27,6 +27,8 @@ package org.springblade.transport.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
import org.springblade.transport.pojo.entity.InvoiceApplication;
/**
@@ -36,4 +38,13 @@ import org.springblade.transport.pojo.entity.InvoiceApplication;
*/
@Mapper
public interface InvoiceApplicationMapper extends BaseMapper {
+
+ /**
+ * 查询指定租户、指定日期前缀下已使用的最大开票申请流水号。
+ * 不过滤逻辑删除数据,避免唯一索引仍占用历史编号时重复生成。
+ */
+ @Select("SELECT COALESCE(MAX(CAST(SUBSTRING(application_no, CHAR_LENGTH(#{prefix}) + 1) AS UNSIGNED)), 0) "
+ + "FROM blade_invoice_application WHERE tenant_id = #{tenantId} "
+ + "AND application_no LIKE CONCAT(#{prefix}, '%')")
+ Long selectMaxDailySequence(@Param("tenantId") String tenantId, @Param("prefix") String prefix);
}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/PaymentApplicationMapper.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/PaymentApplicationMapper.java
index 770dc202..f1507f68 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/PaymentApplicationMapper.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/PaymentApplicationMapper.java
@@ -21,9 +21,20 @@ package org.springblade.transport.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
import org.springblade.transport.pojo.entity.PaymentApplication;
/** 付款申请 Mapper。 @author Chill */
@Mapper
public interface PaymentApplicationMapper extends BaseMapper {
+
+ /**
+ * 查询指定租户、指定日期前缀下已使用的最大付款申请流水号。
+ * 不过滤逻辑删除数据,避免唯一索引仍占用历史编号时重复生成。
+ */
+ @Select("SELECT COALESCE(MAX(CAST(SUBSTRING(payment_no, CHAR_LENGTH(#{prefix}) + 1) AS UNSIGNED)), 0) "
+ + "FROM blade_payment_application WHERE tenant_id = #{tenantId} "
+ + "AND payment_no LIKE CONCAT(#{prefix}, '%')")
+ Long selectMaxDailySequence(@Param("tenantId") String tenantId, @Param("prefix") String prefix);
}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/PreSettlementAdvanceMapper.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/PreSettlementAdvanceMapper.java
index c8bb1558..734364da 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/PreSettlementAdvanceMapper.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/PreSettlementAdvanceMapper.java
@@ -10,6 +10,8 @@ package org.springblade.transport.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
import org.springblade.transport.pojo.entity.PreSettlementAdvance;
/**
@@ -19,4 +21,12 @@ import org.springblade.transport.pojo.entity.PreSettlementAdvance;
*/
@Mapper
public interface PreSettlementAdvanceMapper extends BaseMapper {
+
+ /**
+ * 查询预付单号最大流水(含逻辑删除)。
+ */
+ @Select("SELECT COALESCE(MAX(CAST(SUBSTRING(advance_no, CHAR_LENGTH(#{prefix}) + 1) AS UNSIGNED)), 0) "
+ + "FROM blade_pre_settlement_advance WHERE tenant_id = #{tenantId} "
+ + "AND advance_no LIKE CONCAT(#{prefix}, '%')")
+ Long selectMaxDailySequence(@Param("tenantId") String tenantId, @Param("prefix") String prefix);
}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/PreSettlementMapper.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/PreSettlementMapper.java
index c2b86484..2fbe0db4 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/PreSettlementMapper.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/PreSettlementMapper.java
@@ -10,6 +10,8 @@ package org.springblade.transport.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
import org.springblade.transport.pojo.entity.PreSettlement;
/**
@@ -19,4 +21,20 @@ import org.springblade.transport.pojo.entity.PreSettlement;
*/
@Mapper
public interface PreSettlementMapper extends BaseMapper {
+
+ /**
+ * 查询预结算单号最大流水(含逻辑删除)。
+ */
+ @Select("SELECT COALESCE(MAX(CAST(SUBSTRING(pre_settlement_no, CHAR_LENGTH(#{prefix}) + 1) AS UNSIGNED)), 0) "
+ + "FROM blade_pre_settlement WHERE tenant_id = #{tenantId} "
+ + "AND pre_settlement_no LIKE CONCAT(#{prefix}, '%')")
+ Long selectMaxPreSettlementDailySequence(@Param("tenantId") String tenantId, @Param("prefix") String prefix);
+
+ /**
+ * 查询预结算转正式结算单号最大流水(含逻辑删除)。
+ */
+ @Select("SELECT COALESCE(MAX(CAST(SUBSTRING(formal_settlement_no, CHAR_LENGTH(#{prefix}) + 1) AS UNSIGNED)), 0) "
+ + "FROM blade_pre_settlement WHERE tenant_id = #{tenantId} "
+ + "AND formal_settlement_no LIKE CONCAT(#{prefix}, '%')")
+ Long selectMaxFormalSettlementDailySequence(@Param("tenantId") String tenantId, @Param("prefix") String prefix);
}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/SettlementAdjustmentMapper.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/SettlementAdjustmentMapper.java
index 1a2b5629..9a7b7e64 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/SettlementAdjustmentMapper.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/SettlementAdjustmentMapper.java
@@ -2,7 +2,19 @@ package org.springblade.transport.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
import org.springblade.transport.pojo.entity.SettlementAdjustment;
@Mapper
-public interface SettlementAdjustmentMapper extends BaseMapper {}
+public interface SettlementAdjustmentMapper extends BaseMapper {
+
+ /**
+ * 查询指定租户、指定日期前缀下已使用的最大结算调整单流水号。
+ * 不过滤逻辑删除数据,避免唯一索引仍占用历史编号时重复生成。
+ */
+ @Select("SELECT COALESCE(MAX(CAST(SUBSTRING(adjustment_no, CHAR_LENGTH(#{prefix}) + 1) AS UNSIGNED)), 0) "
+ + "FROM blade_settlement_adjustment WHERE tenant_id = #{tenantId} "
+ + "AND adjustment_no LIKE CONCAT(#{prefix}, '%')")
+ Long selectMaxDailySequence(@Param("tenantId") String tenantId, @Param("prefix") String prefix);
+}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/TransportReconciliationMapper.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/TransportReconciliationMapper.java
index e808e682..db46b800 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/TransportReconciliationMapper.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/TransportReconciliationMapper.java
@@ -22,4 +22,13 @@ public interface TransportReconciliationMapper extends BaseMapperlambdaQuery()
- .likeRight(BillPayment::getPaymentNo, prefix)) + 1);
+ Long maxSequence = baseMapper.selectMaxDailySequence(AuthUtil.getTenantId(), prefix);
+ return prefix + String.format("%05d", (maxSequence == null ? 0L : maxSequence) + 1);
}
private BigDecimal positive(BigDecimal value, String name) {
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/FormalSettlementServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/FormalSettlementServiceImpl.java
index cbfdb8e0..83462702 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/FormalSettlementServiceImpl.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/FormalSettlementServiceImpl.java
@@ -286,21 +286,8 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl throw new ServiceException("结算类型不正确");
};
String prefix = code + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
- List numbers = list(Wrappers.lambdaQuery()
- .select(FormalSettlement::getFormalSettlementNo)
- .likeRight(FormalSettlement::getFormalSettlementNo, prefix))
- .stream().map(FormalSettlement::getFormalSettlementNo).toList();
- int sequence = 1;
- if (!numbers.isEmpty()) {
- String latest = numbers.stream().max(String::compareTo).orElse(prefix);
- try {
- sequence = Integer.parseInt(latest.substring(prefix.length())) + 1;
- } catch (RuntimeException ignored) {
- sequence = Math.toIntExact(count(Wrappers.lambdaQuery()
- .likeRight(FormalSettlement::getFormalSettlementNo, prefix))) + 1;
- }
- }
- return prefix + String.format("%05d", sequence);
+ Long maxSequence = baseMapper.selectMaxDailySequence(AuthUtil.getTenantId(), prefix);
+ return prefix + String.format("%05d", (maxSequence == null ? 0L : maxSequence) + 1);
}
@Override
@@ -2190,11 +2177,11 @@ public class FormalSettlementServiceImpl extends BaseServiceImpllambdaQuery()
- .likeRight(FormalSettlementPayment::getPaymentNo, prefix));
- return prefix + String.format("%04d", count + 1);
+ Long maxSequence = paymentMapper.selectMaxDailySequence(AuthUtil.getTenantId(), prefix);
+ return prefix + String.format("%04d", (maxSequence == null ? 0L : maxSequence) + 1);
}
private BigDecimal money(BigDecimal value) { return (value == null ? BigDecimal.ZERO : value).setScale(2, RoundingMode.HALF_UP); }
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceApplicationServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceApplicationServiceImpl.java
index 10b197a8..6ca7eaef 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceApplicationServiceImpl.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceApplicationServiceImpl.java
@@ -1679,10 +1679,11 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpllambdaQuery()
- .likeRight(InvoiceApplication::getApplicationNo, prefix)) + 1);
+ Long maxSequence = baseMapper.selectMaxDailySequence(AuthUtil.getTenantId(), prefix);
+ return prefix + String.format("%05d", (maxSequence == null ? 0L : maxSequence) + 1);
}
private String normalizeDepartmentEmails(String value, List invoiceInfos) {
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PaymentApplicationServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PaymentApplicationServiceImpl.java
index 6b827dd5..9a3af520 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PaymentApplicationServiceImpl.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PaymentApplicationServiceImpl.java
@@ -2455,7 +2455,14 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpllambdaQuery().likeRight(PaymentApplication::getPaymentNo, prefix)) + 1); }
+ /**
+ * 生成当日付款申请单号;按最大流水号 +1,且计入逻辑删除数据,避免撞 uk_payment_application_no
+ */
+ private synchronized String nextNo() {
+ String prefix = "FKD" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
+ Long maxSequence = baseMapper.selectMaxDailySequence(AuthUtil.getTenantId(), prefix);
+ return prefix + String.format("%05d", (maxSequence == null ? 0L : maxSequence) + 1);
+ }
private BigDecimal nonNegative(BigDecimal value, String name) { if (value == null || value.compareTo(BigDecimal.ZERO) < 0) throw new ServiceException(name + "不能小于0"); return value; }
private BigDecimal money(BigDecimal value) { return value == null ? BigDecimal.ZERO : value; }
private String limit(String value, int length) { if (value != null && value.length() > length) throw new ServiceException("备注不能超过" + length + "个字符"); return value; }
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PreSettlementServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PreSettlementServiceImpl.java
index 354ec65f..ff913107 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PreSettlementServiceImpl.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PreSettlementServiceImpl.java
@@ -85,7 +85,6 @@ import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
@@ -1780,44 +1779,25 @@ public class PreSettlementServiceImpl extends BaseServiceImpllambdaQuery()
- .likeRight(PreSettlementAdvance::getAdvanceNo, prefix)
- .orderByDesc(PreSettlementAdvance::getAdvanceNo)
- .last("limit 1"));
- return prefix + String.format("%05d", nextSequence(latest == null ? null : latest.getAdvanceNo(), prefix));
- }
-
- private String nextDailyCode(String code, Function getter) {
- String prefix = code + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
- PreSettlement latest = list(Wrappers.lambdaQuery()
- .and(query -> query.likeRight(PreSettlement::getPreSettlementNo, prefix)
- .or().likeRight(PreSettlement::getFormalSettlementNo, prefix))
- .orderByDesc(PreSettlement::getCreateTime)
- .last("limit 1")).stream().max(Comparator.comparing(item -> {
- String value = getter.apply(item);
- return value == null ? "" : value;
- })).orElse(null);
- String latestCode = latest == null ? null : getter.apply(latest);
- return prefix + String.format("%05d", nextSequence(latestCode, prefix));
- }
-
- private int nextSequence(String latestCode, String prefix) {
- if (latestCode == null || !latestCode.startsWith(prefix)) return 1;
- try {
- return Integer.parseInt(latestCode.substring(prefix.length())) + 1;
- } catch (NumberFormatException exception) {
- return 1;
- }
+ Long maxSequence = advanceMapper.selectMaxDailySequence(AuthUtil.getTenantId(), prefix);
+ return prefix + String.format("%05d", (maxSequence == null ? 0L : maxSequence) + 1);
}
}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/SettlementAdjustmentServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/SettlementAdjustmentServiceImpl.java
index 8dda1c1c..d6dd4a95 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/SettlementAdjustmentServiceImpl.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/SettlementAdjustmentServiceImpl.java
@@ -392,7 +392,12 @@ public class SettlementAdjustmentServiceImpl extends BaseServiceImpllambdaQuery().likeRight(SettlementAdjustment::getAdjustmentNo, prefix)); return prefix + String.format("%04d", count + 1); }
+ /** 生成当日结算调整单号;按最大流水号 +1,且计入逻辑删除数据 */
+ private synchronized String nextNo() {
+ String prefix = "TZ" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
+ Long maxSequence = baseMapper.selectMaxDailySequence(AuthUtil.getTenantId(), prefix);
+ return prefix + String.format("%04d", (maxSequence == null ? 0L : maxSequence) + 1);
+ }
private BigDecimal money(BigDecimal value) { return value == null ? BigDecimal.ZERO : value; }
private String requiredText(String value, String field, int max) { if (Func.isEmpty(value)) throw new ServiceException(field + "不能为空"); return limit(value.trim(), max); }
private String limit(String value, int max) { if (value != null && value.length() > max) throw new ServiceException("内容不能超过" + max + "个字"); return value; }
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TransportReconciliationServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TransportReconciliationServiceImpl.java
index dff1f39b..065ec3b9 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TransportReconciliationServiceImpl.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TransportReconciliationServiceImpl.java
@@ -1512,20 +1512,14 @@ public class TransportReconciliationServiceImpl
private BigDecimal sumExternalQuantity(List rows) { return rows.stream().map(TransportReconciliationExternal::getTransportQuantity).map(this::money).reduce(BigDecimal.ZERO, BigDecimal::add); }
private BigDecimal sumInternalAmount(List rows) { return rows.stream().map(TransportReconciliationInternal::getSettlementAmount).map(this::money).reduce(BigDecimal.ZERO, BigDecimal::add); }
private BigDecimal sumExternalAmount(List rows) { return rows.stream().map(TransportReconciliationExternal::getSettlementAmount).map(this::money).reduce(BigDecimal.ZERO, BigDecimal::add); }
+ /** 生成当日运输对账单号;按最大流水号 +1,且计入逻辑删除数据 */
private synchronized String nextNo() {
String prefix = "DZD" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
- int sequence = list(Wrappers.lambdaQuery()
- .select(TransportReconciliation::getReconciliationNo)
- .likeRight(TransportReconciliation::getReconciliationNo, prefix))
- .stream()
- .map(TransportReconciliation::getReconciliationNo)
- .filter(number -> number != null && number.length() == prefix.length() + 5)
- .map(number -> number.substring(prefix.length()))
- .filter(suffix -> suffix.chars().allMatch(Character::isDigit))
- .mapToInt(Integer::parseInt)
- .max()
- .orElse(0) + 1;
- if (sequence > 99999) throw new ServiceException("当日运输对账单号流水已用完");
+ Long maxSequence = baseMapper.selectMaxDailySequence(AuthUtil.getTenantId(), prefix);
+ long sequence = (maxSequence == null ? 0L : maxSequence) + 1;
+ if (sequence > 99999) {
+ throw new ServiceException("当日运输对账单号流水已用完");
+ }
return prefix + String.format("%05d", sequence);
}
}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillImportBatchServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillImportBatchServiceImpl.java
index 0f92b9b4..2d52773c 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillImportBatchServiceImpl.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillImportBatchServiceImpl.java
@@ -25,6 +25,7 @@ import org.springblade.system.cache.UserCache;
import org.springblade.system.feign.ISysClient;
import org.springblade.system.pojo.entity.DictBiz;
import org.springblade.system.pojo.entity.CargoType;
+import org.springblade.system.pojo.entity.MeasurementUnit;
import org.springblade.transport.excel.WaybillImportBatchExcel;
import org.springblade.transport.mapper.WaybillImportBatchMapper;
import org.springblade.transport.pojo.dto.WaybillImportBatchRequest;
@@ -919,13 +920,14 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl row, List quantityUnitOptions, List errors) {
- String quantityUnit = stringValue(row, "quantityUnit", "数量单位");
+ String quantityUnit = stringValue(row, "quantityUnit", "数量单位", "*数量单位");
if (Func.isEmpty(quantityUnit)) {
return;
}
-
- if (!quantityUnitOptions.contains(quantityUnit)) {
- errors.add("数量单位必须为系统枚举值之一");
+ String normalized = quantityUnit.trim();
+ boolean matched = quantityUnitOptions.stream().anyMatch(option -> option.equalsIgnoreCase(normalized));
+ if (!matched) {
+ errors.add("数量单位「" + normalized + "」未在计量单位主数据中匹配");
}
}
@@ -1186,9 +1188,28 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl loadQuantityUnitOptions() {
- // 常见数量单位
- return List.of("吨", "千克", "立方米", "件", "箱", "台", "个", "升", "米", "平方米");
+ R> response = sysClient.getMeasurementUnits();
+ if (response == null || !response.isSuccess() || response.getData() == null) {
+ throw new ServiceException("计量单位基础数据读取失败,请稍后重试");
+ }
+ Set options = new HashSet<>();
+ for (MeasurementUnit unit : response.getData()) {
+ if (unit == null || (unit.getStatus() != null && !Objects.equals(unit.getStatus(), 1))) {
+ continue;
+ }
+ if (Func.isNotEmpty(unit.getUnitName())) {
+ options.add(unit.getUnitName().trim());
+ }
+ if (Func.isNotEmpty(unit.getUnitCode())) {
+ options.add(unit.getUnitCode().trim());
+ }
+ }
+ if (options.isEmpty()) {
+ throw new ServiceException("计量单位主数据为空,请先在基础数据中配置计量单位");
+ }
+ return new ArrayList<>(options);
}
/**