Напоминания: убрать дубль ManagerEmail, ссылка из настроек; None первым во всех enum
Напоминания: - ProbationEndingReminderDto: ManagerEmail убран — это был унаследованный ReceiverEmail под вторым именем. - Ссылка для ProbationEnding больше не ведёт на саму заявку на приём (она уже закрыта, решать по ней нечего) — берётся из новой настройки RemindersOptions.ProbationReminderUrl и ведёт в раздел, где заводят новую заявку. Подстановок в ней нет: адрес конкретной формы в портал не передать, rptype без rpid/rpsource игнорируется (см. parseRoute в request-portal). Заодно ушли BuildProbationUrl и ненужные больше параметры type/listId. Стайлгайд (CLAUDE.md) — у enum первое значение None: - ReminderFeed: None=0 трактуется как ApprovalOverdue, чтобы вызов без явного выбора работал как раньше. - EmploymentStatus: заодно инвертирован switch в ReminderService — раньше «продолжить» было веткой по умолчанию, и новый None молча означал бы «сотрудник работает». Теперь по умолчанию пропуск с предупреждением. - ConditionsLogic: None — НЕвалидное значение, отвергается валидаторами шага (в том числе новым PatchTemplateRouteStepRequestValidator, его не было вовсе). Поэтому у ConditionsLogic в Create/Update-запросах убрано значение по умолчанию: System.Text.Json в .NET 10 уважает дефолты параметров конструктора, и пропущенное поле молча означало «И». Теперь пропущенное поле даёт None и упирается в валидатор. ЛОМАЮЩЕЕ ИЗМЕНЕНИЕ КОНТРАКТА: клиент, не присылающий conditionsLogic в POST/PUT шага, получит 400 вместо прежнего молчаливого «И». Админка не затронута — она это поле всегда отправляет.
This commit is contained in:
@@ -403,15 +403,20 @@ public sealed class ReminderService(
|
||||
var reminders = new List<ReminderDto>();
|
||||
foreach (var row in rows)
|
||||
{
|
||||
var reminder = await TryBuildProbationReminderAsync(type, row, listId, directory, now, cancellationToken);
|
||||
var reminder = await TryBuildProbationReminderAsync(row, directory, now, cancellationToken);
|
||||
if (reminder is not null) reminders.Add(reminder);
|
||||
}
|
||||
|
||||
return reminders;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ни type, ни listId здесь больше не нужны: ссылка в этом виде напоминаний —
|
||||
/// константа из настроек (см. ProbationReminderUrl), а поля самой заявки
|
||||
/// (RequestTypeId и т.п.) в ProbationEndingReminderDto не входят.
|
||||
/// </summary>
|
||||
private async Task<ReminderDto?> TryBuildProbationReminderAsync(
|
||||
RequestType type, HireRow row, string listId, EmployeeDirectorySnapshot directory,
|
||||
HireRow row, EmployeeDirectorySnapshot directory,
|
||||
DateTimeOffset now, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(row.CandidateName) || row.HireDate is not { } hireDate) return null;
|
||||
@@ -425,11 +430,17 @@ public sealed class ReminderService(
|
||||
|
||||
var candidateName = row.CandidateName.Trim();
|
||||
|
||||
// Перечислены оба «продолжающих» исхода явно, а «пропустить» — это default:
|
||||
// так любое НЕ подтверждённое трудоустройство (в том числе EmploymentStatus.None,
|
||||
// если он когда-нибудь сюда доедет) приводит к пропуску с предупреждением, а не
|
||||
// молча считается «работает».
|
||||
switch (directory.EmploymentOf(candidateName))
|
||||
{
|
||||
case EmploymentStatus.Employed:
|
||||
break;
|
||||
case EmploymentStatus.Dismissed:
|
||||
return null; // уже уволен — напоминать не о чем.
|
||||
case EmploymentStatus.NotFound:
|
||||
default:
|
||||
logger.LogWarning(
|
||||
"Заявка на приём {RequestId}: кандидат «{Fio}» не найден в /Employee/FullBase — статус трудоустройства не подтверждён, напоминание пропущено",
|
||||
row.Id, candidateName);
|
||||
@@ -455,26 +466,17 @@ public sealed class ReminderService(
|
||||
}
|
||||
|
||||
return new ProbationEndingReminderDto(
|
||||
ManagerEmail: managerEmail,
|
||||
ReceiverEmail: managerEmail,
|
||||
CandidateEmail: candidateEmail,
|
||||
CandidateName: candidateName,
|
||||
ProbationPeriod: row.ProbationPeriod,
|
||||
HireDate: hireDate,
|
||||
ProbationEndsAt: probationEndsAt,
|
||||
DaysUntilProbationEnds: daysLeft,
|
||||
Url: BuildProbationUrl(type, row, listId),
|
||||
// Не ссылка на саму заявку на приём (она уже закрыта, решать по ней
|
||||
// нечего) — константный адрес раздела, где руководитель заводит новую
|
||||
// заявку по итогам испытательного срока. См. ProbationReminderUrl.
|
||||
Url: options.Value.ProbationReminderUrl,
|
||||
ReceiverName: directory.NameByEmail(managerEmail));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ссылка на саму заявку (не на шаг согласования — этого вида напоминаний
|
||||
/// понятие "фаза" не касается), в том же формате, что и BuildUrl.
|
||||
/// </summary>
|
||||
private string BuildProbationUrl(RequestType type, HireRow row, string listId) =>
|
||||
options.Value.RequestUrlTemplate
|
||||
.Replace("{siteUrl}", type.SiteUrl!.TrimEnd('/'))
|
||||
.Replace("{pageUrl}", type.PageUrl)
|
||||
.Replace("{requestId}", row.Id.ToString())
|
||||
.Replace("{listId}", Uri.EscapeDataString(listId))
|
||||
.Replace("{nav}", "approvals");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user