90 lines
4.3 KiB
C#
90 lines
4.3 KiB
C#
namespace SimpleAdmin.Application;
|
|
|
|
/// <summary>
|
|
/// 实现入职合同预览和归档 DOCX 文件生成能力。
|
|
/// </summary>
|
|
public class OnboardingContractDocumentService : IOnboardingContractDocumentService
|
|
{
|
|
private readonly SqlSugarScope _db;
|
|
private readonly IFileService _fileService;
|
|
|
|
public OnboardingContractDocumentService(IFileService fileService)
|
|
{
|
|
_db = DbContext.DB;
|
|
_fileService = fileService;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 根据锁定的模板版本和任务变量快照生成已替换变量的合同 DOCX。
|
|
/// </summary>
|
|
public async Task<long> Generate(OnboardingGenerateContractInput input)
|
|
{
|
|
var contract = await _db.Queryable<ObTaskContract>().InSingleAsync(input.TaskContractId)
|
|
?? throw Oops.Bah("任务合同不存在");
|
|
var task = await _db.Queryable<ObOnboardingTask>().InSingleAsync(contract.TaskId)
|
|
?? throw Oops.Bah("入职任务不存在");
|
|
var statusAllowsGeneration = task.TaskStatus == OnboardingTaskStatus.PendingFill
|
|
|| task.TaskStatus == OnboardingTaskStatus.Rejected
|
|
|| task.TaskStatus == OnboardingTaskStatus.Reviewing
|
|
|| task.TaskStatus == OnboardingTaskStatus.Approved;
|
|
if (!statusAllowsGeneration)
|
|
throw Oops.Bah("当前任务状态不能生成合同");
|
|
if (contract.GeneratedDocxFileId.HasValue)
|
|
return contract.GeneratedDocxFileId.Value;
|
|
|
|
var version = await _db.Queryable<ObContractTemplateVersion>().InSingleAsync(contract.TemplateVersionId)
|
|
?? throw Oops.Bah("合同版本不存在");
|
|
var source = await _db.Queryable<SysFile>().InSingleAsync(version.SourceDocxFileId)
|
|
?? throw Oops.Bah("合同源文件不存在");
|
|
var definitions = await _db.Queryable<ObTemplateVariable>()
|
|
.Where(item => item.TemplateVersionId == version.Id)
|
|
.ToListAsync();
|
|
var variables = await _db.Queryable<ObTaskContractVariable>()
|
|
.Where(item => item.TaskContractId == contract.Id)
|
|
.ToListAsync();
|
|
var duplicateVariable = variables
|
|
.GroupBy(item => item.VariableCode, StringComparer.OrdinalIgnoreCase)
|
|
.FirstOrDefault(group => group.Count() > 1);
|
|
if (duplicateVariable != null)
|
|
{
|
|
throw Oops.Bah(
|
|
$"合同变量快照“{duplicateVariable.Key}”存在重复数据,请联系管理员修复后重试");
|
|
}
|
|
|
|
var missing = definitions
|
|
.Where(item => item.Required)
|
|
.FirstOrDefault(definition => string.IsNullOrWhiteSpace(
|
|
variables.FirstOrDefault(variable => variable.VariableCode == definition.VariableCode)?.VariableValue));
|
|
if (missing != null)
|
|
throw Oops.Bah($"合同变量“{missing.VariableName}”尚未填写,暂时不能预览合同");
|
|
|
|
var sourceResult = await _fileService.Download(new BaseIdInput { Id = source.Id })
|
|
?? throw Oops.Bah("无法读取合同源文件");
|
|
await using var sourceStream = sourceResult.FileStream;
|
|
using var sourceBytes = new MemoryStream();
|
|
await sourceStream.CopyToAsync(sourceBytes);
|
|
|
|
var rendered = DocxTemplateProcessor.Render(
|
|
sourceBytes.ToArray(),
|
|
variables.ToDictionary(
|
|
item => item.VariableCode,
|
|
item => item.VariableValue ?? string.Empty,
|
|
StringComparer.OrdinalIgnoreCase));
|
|
var generatedAt = DateTime.Now;
|
|
// 在文件名中加入生成批次,避免手机系统把同名的新合同误认为历史下载文件。
|
|
var name = $"{task.TaskNo}_{contract.ContractName}_{generatedAt:yyyyMMddHHmmssfff}.docx";
|
|
var fileId = await _fileService.StoreGeneratedFile(
|
|
SysDictConst.FILE_ENGINE_ALIYUN_OSS,
|
|
name,
|
|
rendered);
|
|
|
|
contract.GeneratedDocxFileId = fileId;
|
|
contract.GeneratedAt = generatedAt;
|
|
contract.ContractStatus = task.TaskStatus == OnboardingTaskStatus.Approved
|
|
? TaskContractStatus.OfflinePendingSign
|
|
: TaskContractStatus.PendingConfirm;
|
|
await _db.Updateable(contract).ExecuteCommandAsync();
|
|
return fileId;
|
|
}
|
|
}
|