修复相关bug

This commit is contained in:
fuenmao
2026-09-17 16:04:14 +08:00
parent aaec170c4f
commit bd20ceac4e
4 changed files with 157 additions and 7 deletions
@@ -147,7 +147,7 @@ public class OnboardingContractTemplateService : DbRepository<ObContractTemplate
"合同模板");
NormalizeInput(input);
await ValidateBusinessScope(input.CompanyId, input.DepartmentId, input.PositionIds);
await ValidateReferencedOnboardingTemplates(input);
await ValidateReferencedOnboardingTemplates(input, template.Status);
await EnsureCodeUnique(input.TemplateCode, input.Id);
var entity = BuildEntity(input.Id, input);
@@ -370,6 +370,18 @@ public class OnboardingContractTemplateService : DbRepository<ObContractTemplate
?? throw Oops.Bah("模板版本不存在");
await EnsureTemplateCanManage(version.TemplateId);
if (version.VersionStatus == ContractTemplateVersionStatus.Enabled
&& input.VersionStatus == ContractTemplateVersionStatus.Disabled)
{
var referencedNames = await GetEnabledOnboardingTemplateNames(
version.TemplateId,
version.Id);
if (referencedNames.Count > 0)
{
throw Oops.Bah(
$"该签署材料版本正在被启用中的入职模板{FormatTemplateNames(referencedNames)}引用,不能停用,请先调整或停用这些入职模板");
}
}
if (input.VersionStatus == ContractTemplateVersionStatus.Enabled)
{
ContractTemplateVersionValidity.ValidateRange(version.EffectiveDate, version.ExpiryDate);
@@ -550,7 +562,8 @@ public class OnboardingContractTemplateService : DbRepository<ObContractTemplate
/// 防止修改合同模板归属后破坏已经保存的入职模板配置。
/// </summary>
private async Task ValidateReferencedOnboardingTemplates(
OnboardingContractTemplateEditInput input)
OnboardingContractTemplateEditInput input,
string currentStatus)
{
var relations = await Context.Queryable<ObOnboardingTemplateContract>()
.Where(item => item.ContractTemplateId == input.Id)
@@ -565,6 +578,21 @@ public class OnboardingContractTemplateService : DbRepository<ObContractTemplate
var onboardingTemplates = await Context.Queryable<ObOnboardingTemplate>()
.Where(item => onboardingTemplateIds.Contains(item.Id))
.ToListAsync();
if (string.Equals(currentStatus, "enable", StringComparison.OrdinalIgnoreCase)
&& !string.Equals(input.Status, "enable", StringComparison.OrdinalIgnoreCase))
{
var enabledTemplateNames = onboardingTemplates
.Where(item => !item.IsDelete && item.Status == "enable")
.Select(item => item.TemplateName)
.Distinct()
.OrderBy(item => item)
.ToList();
if (enabledTemplateNames.Count > 0)
{
throw Oops.Bah(
$"该签署材料模板正在被启用中的入职模板{FormatTemplateNames(enabledTemplateNames)}引用,不能停用,请先调整或停用这些入职模板");
}
}
var positionRelations = await Context.Queryable<ObOnboardingTemplatePosition>()
.Where(item => onboardingTemplateIds.Contains(item.OnboardingTemplateId))
.ToListAsync();
@@ -589,6 +617,39 @@ public class OnboardingContractTemplateService : DbRepository<ObContractTemplate
}
}
private async Task<List<string>> GetEnabledOnboardingTemplateNames(
long contractTemplateId,
long? contractTemplateVersionId = null)
{
var relations = await Context.Queryable<ObOnboardingTemplateContract>()
.Where(item => item.ContractTemplateId == contractTemplateId)
.WhereIF(contractTemplateVersionId.HasValue,
item => item.ContractTemplateVersionId == contractTemplateVersionId.Value)
.ToListAsync();
if (relations.Count == 0)
return new List<string>();
var onboardingTemplateIds = relations
.Select(item => item.OnboardingTemplateId)
.Distinct()
.ToList();
var names = await Context.Queryable<ObOnboardingTemplate>()
.Where(item => onboardingTemplateIds.Contains(item.Id)
&& !item.IsDelete
&& item.Status == "enable")
.Select(item => item.TemplateName)
.ToListAsync();
return names
.Where(item => !string.IsNullOrWhiteSpace(item))
.Distinct()
.OrderBy(item => item)
.ToList();
}
private static string FormatTemplateNames(IEnumerable<string> templateNames)
{
return string.Join("、", templateNames.Select(item => $"“{item}”"));
}
/// <summary>
/// 构建合同模板主档案实体。
/// </summary>
@@ -31,6 +31,14 @@ public class OnboardingIdentityValidationService : IOnboardingIdentityValidation
throw Oops.Bah("该姓名和身份证号已完成正式员工建档,请勿重复提交入职资料");
}
// 身份证号码代表唯一自然人。即使姓名填写不同,也不能绕过正式员工重复校验。
var formalEmployeeIdCardExists = await _db.Queryable<ObEmployee>()
.AnyAsync(item => item.IdCardNumber == idCardNumber);
if (formalEmployeeIdCardExists)
{
throw Oops.Bah("该身份证号码已完成正式员工建档,请核对姓名和身份证号码;如需更正,请联系 HR");
}
// 待填写任务不占用身份,以实际先提交的任务为准;撤销或过期任务允许重新发起。
var duplicateTaskExists = await _db.Queryable<ObTaskEmployeeInfo>()
.InnerJoin<ObOnboardingTask>((info, task) => info.TaskId == task.Id)
@@ -42,9 +50,24 @@ public class OnboardingIdentityValidationService : IOnboardingIdentityValidation
|| task.TaskStatus == OnboardingTaskStatus.Approved
|| task.TaskStatus == OnboardingTaskStatus.Archived))
.AnyAsync();
if (!duplicateTaskExists)
return;
if (duplicateTaskExists)
{
throw Oops.Bah("该姓名和身份证号已存在正在办理的入职任务,请勿重复提交;如需补充材料,请联系 HR 继续使用原任务链接");
}
throw Oops.Bah("该姓名和身份证号已存在正在办理的入职任务,请勿重复提交;如需补充材料,请联系 HR 继续使用原任务链接");
// 再单独按身份证号码校验,防止不同姓名使用同一证件重复提交不同任务。
var duplicateIdCardTaskExists = await _db.Queryable<ObTaskEmployeeInfo>()
.InnerJoin<ObOnboardingTask>((info, task) => info.TaskId == task.Id)
.Where((info, task) => info.TaskId != currentTaskId
&& info.IdCardNumber == idCardNumber
&& (task.TaskStatus == OnboardingTaskStatus.Reviewing
|| task.TaskStatus == OnboardingTaskStatus.Rejected
|| task.TaskStatus == OnboardingTaskStatus.Approved
|| task.TaskStatus == OnboardingTaskStatus.Archived))
.AnyAsync();
if (duplicateIdCardTaskExists)
{
throw Oops.Bah("该身份证号码已存在正在办理的入职任务,请核对姓名和身份证号码;如需补充材料,请联系 HR 继续使用原任务链接");
}
}
}
@@ -229,7 +229,65 @@ public class OnboardingTemplateService : IOnboardingTemplateService
&& templateIds.Contains(item.Id))
.OrderBy(item => item.TemplateName)
.ToListAsync();
return await BuildOutputs(templates);
if (templates.Count == 0)
return await BuildOutputs(templates);
var onboardingTemplateIds = templates.Select(item => item.Id).ToList();
var contractConfigs = await _db.Queryable<ObOnboardingTemplateContract>()
.Where(item => onboardingTemplateIds.Contains(item.OnboardingTemplateId))
.ToListAsync();
if (contractConfigs.Count == 0)
return await BuildOutputs(new List<ObOnboardingTemplate>());
var contractTemplateIds = contractConfigs
.Select(item => item.ContractTemplateId)
.Distinct()
.ToList();
var contractVersionIds = contractConfigs
.Select(item => item.ContractTemplateVersionId)
.Distinct()
.ToList();
var contractTemplates = await _db.Queryable<ObContractTemplate>()
.Where(item => contractTemplateIds.Contains(item.Id))
.ToListAsync();
var contractVersions = await _db.Queryable<ObContractTemplateVersion>()
.Where(item => contractVersionIds.Contains(item.Id))
.ToListAsync();
var contractPositions = await _db.Queryable<ObContractTemplatePosition>()
.Where(item => contractTemplateIds.Contains(item.ContractTemplateId)
&& item.PositionId == positionId)
.ToListAsync();
var now = DateTime.Now;
var availableTemplates = templates.Where(template =>
{
var configs = contractConfigs
.Where(item => item.OnboardingTemplateId == template.Id)
.ToList();
if (configs.Count == 0)
return false;
return configs.All(config =>
{
var contractTemplate = contractTemplates
.FirstOrDefault(item => item.Id == config.ContractTemplateId);
var version = contractVersions
.FirstOrDefault(item => item.Id == config.ContractTemplateVersionId);
return contractTemplate != null
&& string.Equals(
contractTemplate.Status,
"enable",
StringComparison.OrdinalIgnoreCase)
&& contractTemplate.CompanyId == template.CompanyId
&& contractTemplate.DepartmentId == template.DepartmentId
&& contractPositions.Any(item =>
item.ContractTemplateId == config.ContractTemplateId)
&& version != null
&& version.TemplateId == config.ContractTemplateId
&& ContractTemplateVersionValidity.IsAvailable(version, now);
});
}).ToList();
return await BuildOutputs(availableTemplates);
}
private static void NormalizeAndValidateInput(OnboardingTemplateSaveInput input)
@@ -25,6 +25,10 @@ public class ConfigService : DbRepository<SysConfig>, IConfigService
/// <inheritdoc/>
public async Task<List<SysConfig>> GetConfigsByCategory(string category)
{
// 业务自定义配置需立即生效,始终以数据库中的最新数据为准。
if (category == CateGoryConst.CONFIG_BIZ_DEFINE)
return await GetListAsync(it => it.Category == category);
var key = SystemConst.CACHE_DEV_CONFIG + category;//系统配置key
//先从redis拿配置
var configList = _simpleCacheService.HashGetAll<SysConfig>(key).Values.ToList();
@@ -51,6 +55,10 @@ public class ConfigService : DbRepository<SysConfig>, IConfigService
/// <inheritdoc/>
public async Task<SysConfig> GetByConfigKey(string category, string configKey)
{
// 业务自定义配置不走缓存,避免修改后仍读取到本机旧值。
if (category == CateGoryConst.CONFIG_BIZ_DEFINE)
return await GetFirstAsync(it => it.Category == category && it.ConfigKey == configKey);
var key = SystemConst.CACHE_DEV_CONFIG + category;//系统配置key
//先从redis拿配置
var config = _simpleCacheService.HashGetOne<SysConfig>(key, configKey);