197 lines
7.6 KiB
C#
197 lines
7.6 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 hasUnapprovedMaterial = await _db.Queryable<ObTaskMaterial>()
|
|
.AnyAsync(item => item.TaskId == task.Id
|
|
&& item.ReviewStatus != TaskMaterialReviewStatus.Passed);
|
|
if (hasUnapprovedMaterial)
|
|
{
|
|
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 employee = employeeInfo.Adapt<ObEmployee>();
|
|
employee.Id = global::SimpleAdmin.Core.Utils.CommonUtils.GetSingleId();
|
|
employee.CompanyId = task.CompanyId;
|
|
employee.DepartmentId = task.DepartmentId;
|
|
employee.PositionId = task.PositionId;
|
|
if (task.DepartmentId.HasValue)
|
|
{
|
|
var dept = await _db.Queryable<ObDepartment>().InSingleAsync(task.DepartmentId.Value);
|
|
employee.DepartmentName = dept?.DepartmentName ?? employeeInfo.OnboardingDepartment;
|
|
}
|
|
else
|
|
{
|
|
employee.DepartmentName = employeeInfo.OnboardingDepartment;
|
|
}
|
|
employee.College = employeeInfo.GraduatedSchool;
|
|
employee.BirthDate = ParseDate(employeeInfo.Birthday);
|
|
employee.ContactAddress = employeeInfo.CurrentAddress;
|
|
employee.EntryDate = ParseDate(employeeInfo.OnboardingDate);
|
|
employee.Remark = employeeInfo.OtherRemarks;
|
|
employee.ExtraInfoJson = global::System.Text.Json.JsonSerializer.Serialize(employeeInfo);
|
|
employee.Status = CommonStatusConst.ENABLE;
|
|
employee.CreateTime = DateTime.Now;
|
|
employee.CreateUserId = UserManager.UserId;
|
|
employee.CreateUser = UserManager.Name;
|
|
employee.UpdateTime = null;
|
|
employee.UpdateUserId = null;
|
|
employee.UpdateUser = null;
|
|
employee.IsDelete = false;
|
|
|
|
// 员工档案、任务状态和审核记录必须同时成功,避免出现“已通过但没有员工档案”的中间状态。
|
|
await _db.Ado.BeginTranAsync();
|
|
try
|
|
{
|
|
var updatedRows = await _db.Updateable<ObOnboardingTask>()
|
|
.SetColumns(item => new ObOnboardingTask
|
|
{
|
|
EmployeeId = employee.Id,
|
|
TaskStatus = OnboardingTaskStatus.Approved,
|
|
AuditedAt = DateTime.Now
|
|
})
|
|
.Where(item => item.Id == task.Id
|
|
&& item.TaskStatus == OnboardingTaskStatus.Reviewing
|
|
&& item.EmployeeId == null)
|
|
.ExecuteCommandAsync();
|
|
if (updatedRows != 1)
|
|
throw Oops.Bah("该入职任务已被其他审核人处理,请刷新后查看");
|
|
|
|
await _snapshotService.Build(task.Id, employeeInfo);
|
|
await _db.Insertable(employee).ExecuteCommandAsync();
|
|
|
|
task.EmployeeId = employee.Id;
|
|
task.TaskStatus = OnboardingTaskStatus.Approved;
|
|
task.AuditedAt = DateTime.Now;
|
|
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);
|
|
await _db.Ado.BeginTranAsync();
|
|
try
|
|
{
|
|
var auditedAt = DateTime.Now;
|
|
var updatedRows = await _db.Updateable<ObOnboardingTask>()
|
|
.SetColumns(item => new ObOnboardingTask
|
|
{
|
|
TaskStatus = OnboardingTaskStatus.Rejected,
|
|
AuditedAt = auditedAt,
|
|
RejectReason = input.AuditOpinion
|
|
})
|
|
.Where(item => item.Id == task.Id
|
|
&& item.TaskStatus == OnboardingTaskStatus.Reviewing)
|
|
.ExecuteCommandAsync();
|
|
if (updatedRows != 1)
|
|
throw Oops.Bah("该入职任务已被其他审核人处理,请刷新后查看");
|
|
|
|
task.TaskStatus = OnboardingTaskStatus.Rejected;
|
|
task.AuditedAt = auditedAt;
|
|
task.RejectReason = input.AuditOpinion;
|
|
await WriteAudit(task, OnboardingAuditAction.Reject, input.AuditOpinion);
|
|
await _db.Ado.CommitTranAsync();
|
|
}
|
|
catch
|
|
{
|
|
await _db.Ado.RollbackTranAsync();
|
|
throw;
|
|
}
|
|
}
|
|
|
|
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("请配置入职审核人");
|
|
// 审核人由全局配置与公司专属配置合并得出,不依赖独立业务表。
|
|
var reviewerIds = OnboardingReviewerConfigParser.Parse(config.ConfigValue, task.CompanyId);
|
|
|
|
if (!reviewerIds.Contains(UserManager.UserId))
|
|
{
|
|
throw Oops.Bah("您不是该入职任务的审核人");
|
|
}
|
|
|
|
return task;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 将登记表中的日期文本转换为正式员工档案日期。
|
|
/// </summary>
|
|
private static DateTime? ParseDate(string value)
|
|
{
|
|
return DateTime.TryParse(value, out var result)
|
|
? result.Date
|
|
: null;
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|