Files
OnboardXAdmin/SimpleAdmin.Application/Services/Onboarding/Audit/OnboardingAuditService.cs
T
2026-08-24 15:32:50 +08:00

141 lines
5.5 KiB
C#

namespace SimpleAdmin.Application;
/// <summary>
/// 实现入职审核业务能力。
/// </summary>
public class OnboardingAuditService : IOnboardingAuditService
{
private readonly SqlSugarScope _db;
private readonly IConfigService _config;
private readonly IOnboardingContractSnapshotService _snapshotService;
public OnboardingAuditService(
IConfigService config,
IOnboardingContractSnapshotService snapshotService)
{
_db = DbContext.DB;
_config = config;
_snapshotService = snapshotService;
}
/// <summary>
/// 审核通过入职任务,并在同一事务中创建正式员工档案。
/// </summary>
public async Task Approve(OnboardingAuditActionInput input)
{
var task = await GetAuditableTask(input.TaskId);
var employeeInfo = await _db.Queryable<ObTaskEmployeeInfo>()
.FirstAsync(item => item.TaskId == task.Id)
?? throw Oops.Bah("候选人资料不存在");
var hasMaterialNeedSupplement = await _db.Queryable<ObTaskMaterial>()
.AnyAsync(item => item.TaskId == task.Id
&& item.ReviewStatus == TaskMaterialReviewStatus.NeedSupplement);
if (hasMaterialNeedSupplement)
{
throw Oops.Bah("仍有资料需要补充,不能审核通过");
}
// 审核通过是创建正式员工的唯一入口,因此必须在入库前拦截身份证号或手机号重复。
var hasExistingEmployee = await _db.Queryable<ObEmployee>()
.AnyAsync(item => item.IdCardNumber == employeeInfo.IdCardNumber || item.Phone == employeeInfo.Phone);
if (hasExistingEmployee)
{
throw Oops.Bah("该身份证号或手机号已存在正式员工");
}
var extraValues = await _db.Queryable<ObTaskFormValue>()
.Where(item => item.TaskId == task.Id)
.ToListAsync();
var employee = employeeInfo.Adapt<ObEmployee>();
employee.Id = global::SimpleAdmin.Core.Utils.CommonUtils.GetSingleId();
employee.CompanyId = task.CompanyId;
employee.PositionId = task.PositionId;
employee.ExtraInfoJson = global::System.Text.Json.JsonSerializer.Serialize(extraValues);
// 员工档案、任务状态和审核记录必须同时成功,避免出现“已通过但没有员工档案”的中间状态。
await _db.Ado.BeginTranAsync();
try
{
await _snapshotService.Build(task.Id, employeeInfo);
await _db.Insertable(employee).ExecuteCommandAsync();
task.EmployeeId = employee.Id;
task.TaskStatus = OnboardingTaskStatus.Approved;
task.AuditedAt = DateTime.Now;
await _db.Updateable(task).ExecuteCommandAsync();
await WriteAudit(task, OnboardingAuditAction.Approve, input.AuditOpinion);
await _db.Ado.CommitTranAsync();
}
catch
{
await _db.Ado.RollbackTranAsync();
throw;
}
}
/// <summary>
/// 退回入职任务,保存审核意见并允许候选人补充资料。
/// </summary>
public async Task Reject(OnboardingAuditActionInput input)
{
if (string.IsNullOrWhiteSpace(input.AuditOpinion))
{
throw Oops.Bah("请填写退回原因");
}
var task = await GetAuditableTask(input.TaskId);
task.TaskStatus = OnboardingTaskStatus.Rejected;
task.RejectReason = input.AuditOpinion;
await _db.Updateable(task).ExecuteCommandAsync();
await WriteAudit(task, OnboardingAuditAction.Reject, input.AuditOpinion);
}
private async Task<ObOnboardingTask> GetAuditableTask(long taskId)
{
var task = await _db.Queryable<ObOnboardingTask>().InSingleAsync(taskId)
?? throw Oops.Bah("入职任务不存在");
if (task.TaskStatus != OnboardingTaskStatus.Reviewing)
{
throw Oops.Bah("当前任务不在审核中");
}
var config = await _config.GetByConfigKey(CateGoryConst.CONFIG_BIZ_DEFINE, "onboard.reviewer.userIds")
?? throw Oops.Bah("请配置入职审核人");
using var configJson = global::System.Text.Json.JsonDocument.Parse(config.ConfigValue);
// 审核人由全局配置与公司专属配置合并得出,不依赖独立业务表。
var reviewerIds = new List<long>();
if (configJson.RootElement.TryGetProperty("all", out var allReviewers))
{
reviewerIds.AddRange(allReviewers.EnumerateArray().Select(item => item.GetInt64()));
}
if (configJson.RootElement.TryGetProperty("company", out var companyReviewers)
&& companyReviewers.TryGetProperty(task.CompanyId.ToString(), out var reviewers))
{
reviewerIds.AddRange(reviewers.EnumerateArray().Select(item => item.GetInt64()));
}
if (!reviewerIds.Contains(UserManager.UserId))
{
throw Oops.Bah("您不是该入职任务的审核人");
}
return task;
}
private Task WriteAudit(ObOnboardingTask task, string action, string opinion)
{
return _db.Insertable(new ObTaskAudit
{
Id = global::SimpleAdmin.Core.Utils.CommonUtils.GetSingleId(),
TaskId = task.Id,
AuditRound = task.SubmitCount,
AuditAction = action,
AuditorUserId = UserManager.UserId,
AuditOpinion = opinion,
AuditedAt = DateTime.Now
}).ExecuteCommandAsync();
}
}