逻辑调整
This commit is contained in:
+147
-44
@@ -1,32 +1,53 @@
|
||||
namespace SimpleAdmin.Application;
|
||||
|
||||
/// <summary>冻结任务合同变量;DOCX 生成阶段只读取本快照,不再读取模板实时值。</summary>
|
||||
/// <summary>
|
||||
/// 实现任务合同变量快照业务能力。
|
||||
/// 构建任务合同变量快照,合同生成阶段只读取本快照。
|
||||
/// </summary>
|
||||
public class OnboardingContractSnapshotService : IOnboardingContractSnapshotService
|
||||
{
|
||||
private readonly SqlSugarScope _db;
|
||||
public OnboardingContractSnapshotService() => _db = DbContext.DB;
|
||||
|
||||
public OnboardingContractSnapshotService()
|
||||
{
|
||||
_db = DbContext.DB;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据任务、公司和候选人资料构建或刷新合同变量快照。
|
||||
/// 根据任务、公司、员工固定信息和动态补充字段构建合同变量快照。
|
||||
/// </summary>
|
||||
public async Task Build(long taskId, ObTaskEmployeeInfo employeeInfo = null)
|
||||
public async Task Build(
|
||||
long taskId,
|
||||
ObTaskEmployeeInfo employeeInfo = null,
|
||||
bool invalidateGeneratedPreview = false)
|
||||
{
|
||||
var task = await _db.Queryable<ObOnboardingTask>().InSingleAsync(taskId) ?? throw Oops.Bah("入职任务不存在");
|
||||
var company = await _db.Queryable<ObCompany>().InSingleAsync(task.CompanyId) ?? throw Oops.Bah("入职公司不存在");
|
||||
employeeInfo ??= await _db.Queryable<ObTaskEmployeeInfo>().FirstAsync(x => x.TaskId == taskId);
|
||||
var contracts = await _db.Queryable<ObTaskContract>().Where(x => x.TaskId == taskId).ToListAsync();
|
||||
var task = await _db.Queryable<ObOnboardingTask>().InSingleAsync(taskId)
|
||||
?? throw Oops.Bah("入职任务不存在");
|
||||
var company = await _db.Queryable<ObCompany>().InSingleAsync(task.CompanyId)
|
||||
?? throw Oops.Bah("入职公司不存在");
|
||||
employeeInfo ??= await _db.Queryable<ObTaskEmployeeInfo>()
|
||||
.FirstAsync(item => item.TaskId == taskId);
|
||||
var dynamicValues = await _db.Queryable<ObTaskFormValue>()
|
||||
.Where(item => item.TaskId == taskId)
|
||||
.ToListAsync();
|
||||
var dynamicValueMap = dynamicValues
|
||||
.GroupBy(item => item.FieldCode, StringComparer.OrdinalIgnoreCase)
|
||||
.ToDictionary(group => group.Key, group => group.Last().FieldValue, StringComparer.OrdinalIgnoreCase);
|
||||
var contracts = await _db.Queryable<ObTaskContract>()
|
||||
.Where(item => item.TaskId == taskId)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var contract in contracts)
|
||||
{
|
||||
if (contract.GeneratedDocxFileId.HasValue || contract.GeneratedPdfFileId.HasValue) throw Oops.Bah("合同已生成,不能重建变量快照");
|
||||
var definitions = await _db.Queryable<ObTemplateVariable>().Where(x => x.TemplateVersionId == contract.TemplateVersionId).OrderBy(x => x.SortCode).ToListAsync();
|
||||
var oldRows = await _db.Queryable<ObTaskContractVariable>().Where(x => x.TaskContractId == contract.Id).ToListAsync();
|
||||
var definitions = await _db.Queryable<ObTemplateVariable>()
|
||||
.Where(item => item.TemplateVersionId == contract.TemplateVersionId)
|
||||
.OrderBy(item => item.SortCode)
|
||||
.ToListAsync();
|
||||
var oldRows = await _db.Queryable<ObTaskContractVariable>()
|
||||
.Where(item => item.TaskContractId == contract.Id)
|
||||
.ToListAsync();
|
||||
var rows = definitions.Select(definition =>
|
||||
{
|
||||
var old = oldRows.FirstOrDefault(x => x.VariableCode == definition.VariableCode);
|
||||
// 人事手工填写的工资、补贴等合同参数优先级最高,刷新自动变量时不能覆盖。
|
||||
var old = oldRows.FirstOrDefault(item => item.VariableCode == definition.VariableCode);
|
||||
var preserveManual = old?.IsManualOverride == true;
|
||||
return new ObTaskContractVariable
|
||||
{
|
||||
@@ -36,54 +57,136 @@ public class OnboardingContractSnapshotService : IOnboardingContractSnapshotServ
|
||||
VariableName = definition.VariableName,
|
||||
VariableType = definition.VariableType,
|
||||
DataType = definition.DataType,
|
||||
VariableValue = preserveManual ? old.VariableValue : ResolveValue(definition, employeeInfo, company, task),
|
||||
SourceType = preserveManual ? ContractVariableSourceType.HrInput : GetSourceType(definition.VariableType),
|
||||
VariableValue = preserveManual
|
||||
? old.VariableValue
|
||||
: ResolveValue(definition, employeeInfo, dynamicValueMap, company, task),
|
||||
SourceType = preserveManual
|
||||
? ContractVariableSourceType.HrInput
|
||||
: GetSourceType(definition.VariableType),
|
||||
IsManualOverride = preserveManual
|
||||
};
|
||||
}).ToList();
|
||||
await _db.Deleteable<ObTaskContractVariable>().Where(x => x.TaskContractId == contract.Id).ExecuteCommandAsync();
|
||||
if (rows.Count > 0) await _db.Insertable(rows).ExecuteCommandAsync();
|
||||
|
||||
await _db.Deleteable<ObTaskContractVariable>()
|
||||
.Where(item => item.TaskContractId == contract.Id)
|
||||
.ExecuteCommandAsync();
|
||||
if (rows.Count > 0)
|
||||
await _db.Insertable(rows).ExecuteCommandAsync();
|
||||
|
||||
if (invalidateGeneratedPreview && task.TaskStatus is OnboardingTaskStatus.PendingFill or OnboardingTaskStatus.Rejected)
|
||||
{
|
||||
contract.GeneratedDocxFileId = null;
|
||||
contract.GeneratedPdfFileId = null;
|
||||
contract.GeneratedAt = null;
|
||||
contract.ReadAt = null;
|
||||
contract.ConfirmedAt = null;
|
||||
contract.ContractStatus = TaskContractStatus.PendingGenerate;
|
||||
await _db.Updateable(contract).ExecuteCommandAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetSourceType(string variableType) => variableType switch
|
||||
private static string GetSourceType(string variableType)
|
||||
{
|
||||
ContractVariableType.Employee => ContractVariableSourceType.Employee,
|
||||
ContractVariableType.Company => ContractVariableSourceType.Company,
|
||||
ContractVariableType.System => ContractVariableSourceType.System,
|
||||
_ => ContractVariableSourceType.HrInput
|
||||
};
|
||||
return variableType switch
|
||||
{
|
||||
ContractVariableType.Employee => ContractVariableSourceType.Employee,
|
||||
ContractVariableType.Company => ContractVariableSourceType.Company,
|
||||
ContractVariableType.System => ContractVariableSourceType.System,
|
||||
_ => ContractVariableSourceType.HrInput
|
||||
};
|
||||
}
|
||||
|
||||
private static string ResolveValue(ObTemplateVariable definition, ObTaskEmployeeInfo info, ObCompany company, ObOnboardingTask task)
|
||||
private static string ResolveValue(
|
||||
ObTemplateVariable definition,
|
||||
ObTaskEmployeeInfo employeeInfo,
|
||||
IReadOnlyDictionary<string, string> dynamicValues,
|
||||
ObCompany company,
|
||||
ObOnboardingTask task)
|
||||
{
|
||||
var sourceField = GetSourceField(definition);
|
||||
if (definition.VariableType == ContractVariableType.Employee)
|
||||
return GetPropertyValue(info, definition.EmployeeField) ?? definition.DefaultValue;
|
||||
{
|
||||
var fixedValue = GetPropertyValue(employeeInfo, ResolveEmployeeField(sourceField), definition.FormatRule);
|
||||
if (!string.IsNullOrWhiteSpace(fixedValue))
|
||||
return fixedValue;
|
||||
return dynamicValues.TryGetValue(sourceField, out var dynamicValue)
|
||||
? dynamicValue
|
||||
: definition.DefaultValue;
|
||||
}
|
||||
|
||||
if (definition.VariableType == ContractVariableType.Company)
|
||||
return GetPropertyValue(company, ResolveCompanyField(definition)) ?? definition.DefaultValue;
|
||||
if (definition.VariableType == ContractVariableType.System && string.Equals(definition.VariableCode, "TASK_NO", StringComparison.OrdinalIgnoreCase))
|
||||
return task.TaskNo;
|
||||
return GetPropertyValue(company, ResolveCompanyField(sourceField), definition.FormatRule) ?? definition.DefaultValue;
|
||||
|
||||
if (definition.VariableType == ContractVariableType.System)
|
||||
{
|
||||
return sourceField.ToUpperInvariant() switch
|
||||
{
|
||||
"TASKNO" or "TASK_NO" or "CONTRACTNO" or "CONTRACT_NO" => task.TaskNo,
|
||||
"CURRENTDATE" or "CURRENT_DATE" or "SIGNDATE" or "SIGN_DATE" => DateTime.Now.ToString("yyyy年MM月dd日"),
|
||||
_ => definition.DefaultValue
|
||||
};
|
||||
}
|
||||
|
||||
return definition.DefaultValue;
|
||||
}
|
||||
|
||||
private static string GetPropertyValue(object source, string propertyName)
|
||||
private static string GetSourceField(ObTemplateVariable definition)
|
||||
{
|
||||
if (source == null || string.IsNullOrWhiteSpace(propertyName)) return null;
|
||||
return source.GetType().GetProperty(propertyName, global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.Instance | global::System.Reflection.BindingFlags.IgnoreCase)?.GetValue(source)?.ToString();
|
||||
if (!string.IsNullOrWhiteSpace(definition.EmployeeField))
|
||||
return definition.EmployeeField;
|
||||
var separatorIndex = definition.VariableCode?.IndexOf('.') ?? -1;
|
||||
return separatorIndex >= 0
|
||||
? definition.VariableCode[(separatorIndex + 1)..]
|
||||
: definition.VariableCode;
|
||||
}
|
||||
|
||||
private static string ResolveCompanyField(ObTemplateVariable definition)
|
||||
private static string GetPropertyValue(object source, string propertyName, string formatRule = null)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(definition.EmployeeField)) return definition.EmployeeField;
|
||||
return definition.VariableCode.ToUpperInvariant() switch
|
||||
if (source == null || string.IsNullOrWhiteSpace(propertyName))
|
||||
return null;
|
||||
|
||||
var value = source.GetType()
|
||||
.GetProperty(
|
||||
propertyName,
|
||||
global::System.Reflection.BindingFlags.Public
|
||||
| global::System.Reflection.BindingFlags.Instance
|
||||
| global::System.Reflection.BindingFlags.IgnoreCase)
|
||||
?.GetValue(source);
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
if (value is DateTime dateTime)
|
||||
return dateTime.ToString(string.IsNullOrWhiteSpace(formatRule) ? "yyyy年MM月dd日" : formatRule);
|
||||
if (value is DateTimeOffset dateTimeOffset)
|
||||
return dateTimeOffset.ToString(string.IsNullOrWhiteSpace(formatRule) ? "yyyy年MM月dd日" : formatRule);
|
||||
if (!string.IsNullOrWhiteSpace(formatRule) && value is IFormattable formattable)
|
||||
return formattable.ToString(formatRule, null);
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
private static string ResolveEmployeeField(string sourceField)
|
||||
{
|
||||
return sourceField.ToUpperInvariant() switch
|
||||
{
|
||||
"COMPANY_CODE" => nameof(ObCompany.CompanyCode),
|
||||
"COMPANY_NAME" => nameof(ObCompany.CompanyName),
|
||||
"LEGAL_NAME" or "COMPANY_LEGAL_NAME" => nameof(ObCompany.LegalName),
|
||||
"UNIFIED_SOCIAL_CREDIT_CODE" => nameof(ObCompany.UnifiedSocialCreditCode),
|
||||
"LEGAL_REPRESENTATIVE" => nameof(ObCompany.LegalRepresentative),
|
||||
"REGISTERED_ADDRESS" => nameof(ObCompany.RegisteredAddress),
|
||||
"CONTACT_PHONE" => nameof(ObCompany.ContactPhone),
|
||||
_ => definition.VariableCode
|
||||
"FULLNAME" or "FULL_NAME" or "NAME" => nameof(ObTaskEmployeeInfo.EmployeeName),
|
||||
"MOBILE" or "MOBILEPHONE" or "MOBILE_PHONE" => nameof(ObTaskEmployeeInfo.Phone),
|
||||
"IDNUMBER" or "ID_NUMBER" or "IDENTITYNUMBER" => nameof(ObTaskEmployeeInfo.IdCardNumber),
|
||||
_ => sourceField
|
||||
};
|
||||
}
|
||||
}
|
||||
private static string ResolveCompanyField(string sourceField)
|
||||
{
|
||||
return sourceField.ToUpperInvariant() switch
|
||||
{
|
||||
"COMPANYCODE" or "COMPANY_CODE" => nameof(ObCompany.CompanyCode),
|
||||
"COMPANYNAME" or "COMPANY_NAME" => nameof(ObCompany.CompanyName),
|
||||
"LEGALNAME" or "LEGAL_NAME" or "COMPANYLEGALNAME" => nameof(ObCompany.LegalName),
|
||||
"UNIFIEDSOCIALCREDITCODE" or "UNIFIED_SOCIAL_CREDIT_CODE" => nameof(ObCompany.UnifiedSocialCreditCode),
|
||||
"LEGALREPRESENTATIVE" or "LEGAL_REPRESENTATIVE" => nameof(ObCompany.LegalRepresentative),
|
||||
"REGISTEREDADDRESS" or "REGISTERED_ADDRESS" => nameof(ObCompany.RegisteredAddress),
|
||||
"CONTACTPHONE" or "CONTACT_PHONE" => nameof(ObCompany.ContactPhone),
|
||||
_ => sourceField
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user