完善第三方签署
This commit is contained in:
+358
-17
@@ -5,10 +5,14 @@ using System.Text.Json;
|
||||
namespace SimpleAdmin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 实现入职合同“员工先签、企业自动盖章”的契约锁电子签流程。
|
||||
/// 实现入职合同“员工先签、后台核对、企业人工盖章”的契约锁电子签流程。
|
||||
/// </summary>
|
||||
public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
{
|
||||
private const string AdminPreviewEventSource = "admin_preview";
|
||||
private const string AdminCompanySealEventSource = "admin_company_seal";
|
||||
private const string PreviewEventTypePrefix = "employee_signed_preview:";
|
||||
|
||||
private readonly SqlSugarScope _db;
|
||||
private readonly IQiyuesuoClient _qiyuesuoClient;
|
||||
private readonly IOnboardingContractDocumentService _contractDocumentService;
|
||||
@@ -68,11 +72,22 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
var context = await GetInitiationContext(task);
|
||||
if (process == null)
|
||||
{
|
||||
var created = await CreateProcess(task, context.Employee);
|
||||
var created = await CreateProcess(
|
||||
task,
|
||||
context.Employee,
|
||||
context.CategoryId,
|
||||
context.SealId);
|
||||
process = created.Process;
|
||||
isNewProcess = created.Created;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(process.ProviderContractId))
|
||||
{
|
||||
// 第三方合同尚未创建时允许采用公司资料中的最新配置,便于修正配置后直接重试。
|
||||
process.CategoryId = context.CategoryId;
|
||||
process.SealId = context.SealId;
|
||||
}
|
||||
|
||||
return await StartProcess(
|
||||
task,
|
||||
context.CompanyName,
|
||||
@@ -97,6 +112,8 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
var process = await CreateReplacementProcess(
|
||||
task,
|
||||
context.Employee,
|
||||
context.CategoryId,
|
||||
context.SealId,
|
||||
previousProcess,
|
||||
input.Reason.Trim());
|
||||
|
||||
@@ -114,6 +131,8 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
private async Task<(
|
||||
ObEmployee Employee,
|
||||
string CompanyName,
|
||||
string CategoryId,
|
||||
string SealId,
|
||||
List<ObTaskContract> TaskContracts)> GetInitiationContext(
|
||||
ObOnboardingTask task)
|
||||
{
|
||||
@@ -140,6 +159,15 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
if (string.IsNullOrWhiteSpace(companyName))
|
||||
throw Oops.Bah("任务所属公司法定名称为空,不能发起电子签");
|
||||
|
||||
var categoryId = company.QiyuesuoCategoryId?.Trim();
|
||||
var sealId = company.QiyuesuoSealId?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(categoryId))
|
||||
throw Oops.Bah($"公司“{companyName}”未配置契约锁默认业务分类 Id,请先到公司与岗位中编辑公司资料");
|
||||
if (string.IsNullOrWhiteSpace(sealId))
|
||||
throw Oops.Bah($"公司“{companyName}”未配置契约锁企业印章 Id,请先到公司与岗位中编辑公司资料");
|
||||
if (!long.TryParse(categoryId, out _) || !long.TryParse(sealId, out _))
|
||||
throw Oops.Bah($"公司“{companyName}”的契约锁业务分类或印章 Id 格式不正确");
|
||||
|
||||
var taskContracts = await _db.Queryable<ObTaskContract>()
|
||||
.Where(item => item.TaskId == task.Id)
|
||||
.OrderBy(item => item.Id)
|
||||
@@ -152,7 +180,7 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
if (unconfirmed != null)
|
||||
throw Oops.Bah($"合同“{unconfirmed.ContractName}”尚未由员工确认");
|
||||
|
||||
return (employee, companyName, taskContracts);
|
||||
return (employee, companyName, categoryId, sealId, taskContracts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -258,6 +286,159 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
return await BuildDetail(task, process);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<OnboardingElectronicSignPreviewOutput> PreviewEmployeeSignedDocument(
|
||||
OnboardingElectronicSignPreviewInput input)
|
||||
{
|
||||
var task = await GetAuthorizedTask(input.TaskId);
|
||||
var process = await GetRequiredProcess(task.Id);
|
||||
|
||||
// 不信任前端缓存状态。每次预览前重新查询契约锁,确保员工确实已完成签署。
|
||||
await SyncProcess(process, "preview_employee_signed");
|
||||
if (process.SignStatus != ElectronicSignStatus.PendingCompanySeal)
|
||||
throw Oops.Bah("只有员工已签、企业待盖章的合同才能在此处核对");
|
||||
|
||||
var document = await _db.Queryable<ObElectronicSignDocument>()
|
||||
.FirstAsync(item =>
|
||||
item.Id == input.SignDocumentId
|
||||
&& item.SignProcessId == process.Id)
|
||||
?? throw Oops.Bah("电子签文档不存在或不属于当前签约流程");
|
||||
if (string.IsNullOrWhiteSpace(document.ProviderDocumentId))
|
||||
throw Oops.Bah("契约锁文档尚未创建完成,不能预览");
|
||||
|
||||
var companyName = await GetCompanyLegalName(task);
|
||||
var previewUrl = await _qiyuesuoClient.GetViewPageUrl(
|
||||
new QiyuesuoViewPageInput
|
||||
{
|
||||
ContractId = process.ProviderContractId,
|
||||
DocumentId = document.ProviderDocumentId,
|
||||
CompanyName = companyName
|
||||
});
|
||||
if (string.IsNullOrWhiteSpace(previewUrl)
|
||||
|| !Uri.TryCreate(previewUrl, UriKind.Absolute, out var previewUri)
|
||||
|| (previewUri.Scheme != Uri.UriSchemeHttps
|
||||
&& previewUri.Scheme != Uri.UriSchemeHttp))
|
||||
{
|
||||
throw Oops.Bah("契约锁返回的合同浏览地址无效");
|
||||
}
|
||||
|
||||
await RecordAdminOperation(
|
||||
process,
|
||||
AdminPreviewEventSource,
|
||||
BuildPreviewEventType(document.Id),
|
||||
JsonSerializer.Serialize(new
|
||||
{
|
||||
signDocumentId = document.Id,
|
||||
providerDocumentId = document.ProviderDocumentId,
|
||||
document.DocumentName,
|
||||
operatorUserId = UserManager.UserId,
|
||||
operatorName = UserManager.Name
|
||||
}),
|
||||
"已生成预览地址");
|
||||
|
||||
return new OnboardingElectronicSignPreviewOutput
|
||||
{
|
||||
SignDocumentId = document.Id,
|
||||
PreviewUrl = previewUrl
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<OnboardingElectronicSignDetailOutput> CompanySeal(
|
||||
OnboardingElectronicSignTaskInput input)
|
||||
{
|
||||
var task = await GetAuthorizedTask(input.TaskId);
|
||||
var process = await GetRequiredProcess(task.Id);
|
||||
|
||||
// 先查第三方真实状态。重复点击时,如果契约锁已经完成,则直接返回最新详情。
|
||||
await SyncProcess(process, "company_seal_precheck");
|
||||
if (process.SignStatus is ElectronicSignStatus.Completed
|
||||
or ElectronicSignStatus.Archived)
|
||||
{
|
||||
return await BuildDetail(task, process);
|
||||
}
|
||||
if (process.SignStatus != ElectronicSignStatus.PendingCompanySeal)
|
||||
throw Oops.Bah("员工尚未完成签署,当前不能执行企业盖章");
|
||||
|
||||
var documents = await _db.Queryable<ObElectronicSignDocument>()
|
||||
.Where(item => item.SignProcessId == process.Id)
|
||||
.OrderBy(item => item.DocumentSort)
|
||||
.ToListAsync();
|
||||
if (documents.Count == 0)
|
||||
throw Oops.Bah("当前电子签流程没有可盖章的合同文件");
|
||||
|
||||
var previewedDocumentIds = await GetPreviewedDocumentIds(process.Id);
|
||||
var notPreviewed = documents
|
||||
.Where(item => !previewedDocumentIds.Contains(item.Id))
|
||||
.Select(item => item.DocumentName)
|
||||
.ToList();
|
||||
if (notPreviewed.Count > 0)
|
||||
{
|
||||
throw Oops.Bah(
|
||||
$"请先逐份查看员工已签文件:{string.Join("、", notPreviewed)}");
|
||||
}
|
||||
|
||||
var companyName = await GetCompanyLegalName(task);
|
||||
try
|
||||
{
|
||||
await _qiyuesuoClient.CompanySign(
|
||||
new QiyuesuoCompanySignInput
|
||||
{
|
||||
ContractId = process.ProviderContractId,
|
||||
CompanyName = companyName,
|
||||
SealId = process.SealId
|
||||
});
|
||||
}
|
||||
catch (Exception signException)
|
||||
{
|
||||
// POST 响应中断时结果可能不明确,立即反查一次,避免实际已盖章却提示用户反复重试。
|
||||
try
|
||||
{
|
||||
await SyncProcess(process, "company_seal_verify");
|
||||
}
|
||||
catch
|
||||
{
|
||||
// SyncProcess 已保存同步或归档错误,下面仍按内存中的真实状态判断是否已经盖章。
|
||||
}
|
||||
if (process.SignStatus is ElectronicSignStatus.Completed
|
||||
or ElectronicSignStatus.Archived)
|
||||
{
|
||||
return await BuildDetail(task, process);
|
||||
}
|
||||
|
||||
process.LastError = $"企业盖章失败:{LimitError(signException.Message)}";
|
||||
process.UpdateTime = DateTime.Now;
|
||||
await _db.Updateable(process).ExecuteCommandAsync();
|
||||
throw;
|
||||
}
|
||||
|
||||
await RecordAdminOperation(
|
||||
process,
|
||||
AdminCompanySealEventSource,
|
||||
"company_seal_submitted",
|
||||
JsonSerializer.Serialize(new
|
||||
{
|
||||
process.ProviderContractId,
|
||||
companyName,
|
||||
process.SealId,
|
||||
operatorUserId = UserManager.UserId,
|
||||
operatorName = UserManager.Name
|
||||
}),
|
||||
"企业盖章请求已提交");
|
||||
|
||||
// 盖章接口成功即代表请求已受理;后续查询短暂失败不能误导管理员再次盖章。
|
||||
try
|
||||
{
|
||||
await SyncProcess(process, "company_seal_sync");
|
||||
}
|
||||
catch
|
||||
{
|
||||
// LastError 已由 SyncProcess 保存,页面自动刷新或回调会继续完成归档。
|
||||
}
|
||||
|
||||
return await BuildDetail(task, process);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task Notice(OnboardingElectronicSignTaskInput input)
|
||||
{
|
||||
@@ -284,6 +465,7 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
|
||||
await _qiyuesuoClient.Invalid(
|
||||
process.ProviderContractId,
|
||||
process.SealId,
|
||||
input.Reason.Trim());
|
||||
process.SignStatus = ElectronicSignStatus.Invalid;
|
||||
process.ProviderStatus = "INVALIDED";
|
||||
@@ -390,9 +572,11 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
/// </summary>
|
||||
private async Task<(ObElectronicSignProcess Process, bool Created)> CreateProcess(
|
||||
ObOnboardingTask task,
|
||||
ObEmployee employee)
|
||||
ObEmployee employee,
|
||||
string categoryId,
|
||||
string sealId)
|
||||
{
|
||||
var process = BuildProcess(task, employee);
|
||||
var process = BuildProcess(task, employee, categoryId, sealId);
|
||||
try
|
||||
{
|
||||
await _db.Insertable(process).ExecuteCommandAsync();
|
||||
@@ -415,10 +599,12 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
private async Task<ObElectronicSignProcess> CreateReplacementProcess(
|
||||
ObOnboardingTask task,
|
||||
ObEmployee employee,
|
||||
string categoryId,
|
||||
string sealId,
|
||||
ObElectronicSignProcess previousProcess,
|
||||
string reason)
|
||||
{
|
||||
var process = BuildProcess(task, employee);
|
||||
var process = BuildProcess(task, employee, categoryId, sealId);
|
||||
var now = DateTime.Now;
|
||||
|
||||
await _db.Ado.BeginTranAsync();
|
||||
@@ -458,7 +644,9 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
/// </summary>
|
||||
private ObElectronicSignProcess BuildProcess(
|
||||
ObOnboardingTask task,
|
||||
ObEmployee employee)
|
||||
ObEmployee employee,
|
||||
string categoryId,
|
||||
string sealId)
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
var processId = global::SimpleAdmin.Core.Utils.CommonUtils.GetSingleId();
|
||||
@@ -470,8 +658,8 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
Provider = ElectronicSignProvider.Qiyuesuo,
|
||||
BizId = $"{task.TaskNo}-SIGN-{processId}",
|
||||
IsCurrent = true,
|
||||
CategoryId = _setting.CategoryId.Trim(),
|
||||
SealId = _setting.SealId.Trim(),
|
||||
CategoryId = categoryId,
|
||||
SealId = sealId,
|
||||
Subject = $"{employee.EmployeeName}-{task.TaskNo}-入职合同",
|
||||
EmployeeName = employee.EmployeeName.Trim(),
|
||||
EmployeeMobile = employee.Phone.Trim(),
|
||||
@@ -612,11 +800,12 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
?? throw Oops.Bah("契约锁草稿未返回企业签署方");
|
||||
var companyAction = companySignatory.Actions.FirstOrDefault(item =>
|
||||
string.Equals(item.Type, "COMPANY", StringComparison.OrdinalIgnoreCase))
|
||||
?? throw Oops.Bah("契约锁草稿未返回企业自动盖章动作");
|
||||
?? throw Oops.Bah("契约锁草稿未返回企业盖章动作");
|
||||
var personalSignatoryId = GetSignatoryId(personalSignatory);
|
||||
var companyActionId = GetActionId(companyAction);
|
||||
var stampers = new List<QiyuesuoStamperInput>();
|
||||
foreach (var document in documents.OrderBy(item => item.DocumentSort))
|
||||
var orderedDocuments = documents.OrderBy(item => item.DocumentSort).ToList();
|
||||
foreach (var document in orderedDocuments)
|
||||
{
|
||||
document.EmployeeActionId = personalSignatoryId;
|
||||
document.CompanyActionId = companyActionId;
|
||||
@@ -637,10 +826,50 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
DocumentId = document.ProviderDocumentId,
|
||||
SealId = process.SealId,
|
||||
Keyword = document.CompanySealKeyword,
|
||||
KeywordIndex = Math.Max(1, _setting.CompanySealKeywordIndex)
|
||||
KeywordIndex = Math.Max(1, _setting.CompanySealKeywordIndex),
|
||||
OffsetX = _setting.CompanySealOffsetX,
|
||||
OffsetY = _setting.CompanySealOffsetY
|
||||
});
|
||||
}
|
||||
|
||||
if (_setting.EnableAcrossPageSeal)
|
||||
{
|
||||
var providerDocumentIds = orderedDocuments
|
||||
.Select(item => item.ProviderDocumentId)
|
||||
.Where(item => !string.IsNullOrWhiteSpace(item))
|
||||
.ToList();
|
||||
if (providerDocumentIds.Count == 0)
|
||||
throw Oops.Bah("契约锁未返回可用于骑缝章的合同文档 Id");
|
||||
|
||||
var acrossType = _setting.AcrossPageSealType.Trim().ToUpperInvariant();
|
||||
if (acrossType == "ALL_DOCUMENT")
|
||||
{
|
||||
stampers.Add(new QiyuesuoStamperInput
|
||||
{
|
||||
ActionId = companyActionId,
|
||||
Type = "ACROSS_PAGE",
|
||||
DocumentId = providerDocumentIds[0],
|
||||
DocumentIds = string.Join(",", providerDocumentIds),
|
||||
SealId = process.SealId,
|
||||
AcrossType = acrossType
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var providerDocumentId in providerDocumentIds)
|
||||
{
|
||||
stampers.Add(new QiyuesuoStamperInput
|
||||
{
|
||||
ActionId = companyActionId,
|
||||
Type = "ACROSS_PAGE",
|
||||
DocumentId = providerDocumentId,
|
||||
SealId = process.SealId,
|
||||
AcrossType = acrossType
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var sent = await _qiyuesuoClient.Send(new QiyuesuoSendContractInput
|
||||
{
|
||||
ContractId = process.ProviderContractId,
|
||||
@@ -861,6 +1090,7 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
.Where(item => item.SignProcessId == process.Id)
|
||||
.OrderBy(item => item.DocumentSort)
|
||||
.ToListAsync();
|
||||
var previewedDocumentIds = await GetPreviewedDocumentIds(process.Id);
|
||||
result.ProcessId = process.Id;
|
||||
result.ProviderContractId = process.ProviderContractId;
|
||||
result.BizId = process.BizId;
|
||||
@@ -890,7 +1120,8 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
DocumentName = item.DocumentName,
|
||||
DocumentSort = item.DocumentSort,
|
||||
OriginalDocxFileId = item.OriginalDocxFileId,
|
||||
SignedPdfFileId = item.SignedPdfFileId
|
||||
SignedPdfFileId = item.SignedPdfFileId,
|
||||
EmployeeSignedPreviewed = previewedDocumentIds.Contains(item.Id)
|
||||
}).ToList();
|
||||
}
|
||||
else
|
||||
@@ -913,6 +1144,108 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取任务当前所属公司的法定名称。集团共用令牌时,该名称用于明确子公司主体。
|
||||
/// </summary>
|
||||
private async Task<string> GetCompanyLegalName(ObOnboardingTask task)
|
||||
{
|
||||
var company = await _db.Queryable<ObCompany>()
|
||||
.InSingleAsync(task.CompanyId)
|
||||
?? throw Oops.Bah("任务所属公司不存在");
|
||||
var companyName = string.IsNullOrWhiteSpace(company.LegalName)
|
||||
? company.CompanyName
|
||||
: company.LegalName;
|
||||
if (string.IsNullOrWhiteSpace(companyName))
|
||||
throw Oops.Bah("任务所属公司法定名称为空");
|
||||
return companyName.Trim();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回当前流程中已由管理员生成过员工签后预览的文档 Id。
|
||||
/// </summary>
|
||||
private async Task<HashSet<long>> GetPreviewedDocumentIds(long processId)
|
||||
{
|
||||
var eventTypes = await _db.Queryable<ObElectronicSignEvent>()
|
||||
.Where(item =>
|
||||
item.SignProcessId == processId
|
||||
&& item.EventSource == AdminPreviewEventSource
|
||||
&& item.ProcessResult == "已生成预览地址")
|
||||
.Select(item => item.EventType)
|
||||
.ToListAsync();
|
||||
var result = new HashSet<long>();
|
||||
foreach (var eventType in eventTypes)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(eventType)
|
||||
&& eventType.StartsWith(
|
||||
PreviewEventTypePrefix,
|
||||
StringComparison.Ordinal)
|
||||
&& long.TryParse(
|
||||
eventType[PreviewEventTypePrefix.Length..],
|
||||
out var documentId))
|
||||
{
|
||||
result.Add(documentId);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将管理员预览、确认盖章等关键操作写入现有电子签事件表。
|
||||
/// 固定操作键生成固定哈希,可防止双击或重试留下重复审计记录。
|
||||
/// </summary>
|
||||
private async Task RecordAdminOperation(
|
||||
ObElectronicSignProcess process,
|
||||
string eventSource,
|
||||
string eventType,
|
||||
string payloadJson,
|
||||
string processResult)
|
||||
{
|
||||
var eventKey = $"{eventSource}:{process.Id}:{eventType}";
|
||||
var payloadHash = Convert.ToHexString(
|
||||
SHA256.HashData(Encoding.UTF8.GetBytes(eventKey)))
|
||||
.ToLowerInvariant();
|
||||
var existing = await _db.Queryable<ObElectronicSignEvent>()
|
||||
.FirstAsync(item => item.PayloadHash == payloadHash);
|
||||
if (existing != null)
|
||||
return;
|
||||
|
||||
var now = DateTime.Now;
|
||||
var operationEvent = new ObElectronicSignEvent
|
||||
{
|
||||
Id = global::SimpleAdmin.Core.Utils.CommonUtils.GetSingleId(),
|
||||
SignProcessId = process.Id,
|
||||
PayloadHash = payloadHash,
|
||||
EventSource = eventSource,
|
||||
EventType = eventType,
|
||||
ProviderStatus = process.ProviderStatus,
|
||||
PayloadJson = payloadJson,
|
||||
ProcessResult = processResult,
|
||||
ReceivedAt = now,
|
||||
ProcessedAt = now,
|
||||
CreateTime = now,
|
||||
CreateUserId = UserManager.UserId,
|
||||
CreateUser = UserManager.Name,
|
||||
IsDelete = false
|
||||
};
|
||||
try
|
||||
{
|
||||
await _db.Insertable(operationEvent).ExecuteCommandAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 并发重复操作由 PayloadHash 唯一索引兜底;其他插入错误继续抛出。
|
||||
existing = await _db.Queryable<ObElectronicSignEvent>()
|
||||
.FirstAsync(item => item.PayloadHash == payloadHash);
|
||||
if (existing == null)
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private static string BuildPreviewEventType(long documentId)
|
||||
{
|
||||
return $"{PreviewEventTypePrefix}{documentId}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 电子签管理沿用入职审核人权限,不新增另一套权限来源。
|
||||
/// </summary>
|
||||
@@ -1151,10 +1484,7 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
throw Oops.Bah("请先配置契约锁 AppToken");
|
||||
if (string.IsNullOrWhiteSpace(_setting.AppSecret))
|
||||
throw Oops.Bah("请先配置契约锁 AppSecret");
|
||||
if (string.IsNullOrWhiteSpace(_setting.CategoryId))
|
||||
throw Oops.Bah("请先配置契约锁默认业务分类 Id");
|
||||
if (string.IsNullOrWhiteSpace(_setting.SealId))
|
||||
throw Oops.Bah("请先配置契约锁企业印章 Id");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(_setting.CreatorName)
|
||||
|| string.IsNullOrWhiteSpace(_setting.CreatorMobile))
|
||||
{
|
||||
@@ -1165,6 +1495,17 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
{
|
||||
throw Oops.Bah("请配置员工签名和企业盖章定位关键字");
|
||||
}
|
||||
if (_setting.CompanySealOffsetX <= -1m || _setting.CompanySealOffsetX >= 1m
|
||||
|| _setting.CompanySealOffsetY <= -1m || _setting.CompanySealOffsetY >= 1m)
|
||||
{
|
||||
throw Oops.Bah("企业盖章 X/Y 偏移量必须在 -1 与 1 之间");
|
||||
}
|
||||
if (_setting.EnableAcrossPageSeal
|
||||
&& !string.Equals(_setting.AcrossPageSealType, "ALL_DOCUMENT", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(_setting.AcrossPageSealType, "SINGLE_DOCUMENT", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw Oops.Bah("契约锁骑缝章模式只能配置为 ALL_DOCUMENT 或 SINGLE_DOCUMENT");
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureCanOpenEmployeeSignPage(
|
||||
|
||||
Reference in New Issue
Block a user