ReminderDto: разделить на ApprovalOverdueReminderDto и ProbationEndingReminderDto
Абстрактный базовый класс + два sealed-наследника вместо одного DTO с опциональными полями под обе категории — так специфичные для каждого вида напоминания поля не путаются с полями другого вида. Полиморфная сериализация System.Text.Json ([JsonPolymorphic]/[JsonDerivedType]) нужна, иначе список IReadOnlyList<ReminderDto> сериализовался бы только по общим полям базового класса.
This commit is contained in:
@@ -1,52 +1,41 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Tnsu.ApprovalRoute.Application.Reminders;
|
||||
|
||||
/// <param name="Email">Согласующий/исполнитель из строки списка — кому напоминать.</param>
|
||||
/// <param name="HoursOverdue">
|
||||
/// На сколько часов просрочен шаг: сейчас минус (активация шага + SLA).
|
||||
/// Выходные не учитываются — считаются календарные часы.
|
||||
/// </param>
|
||||
/// <param name="Url">Ссылка на заявку, требующую решения.</param>
|
||||
/// <param name="AskOverdueReason">
|
||||
/// Спрашивать ли у пользователя причину просрочки. Значение уже с применённым
|
||||
/// наследованием (шаг перекрывает тип заявки).
|
||||
/// </param>
|
||||
/// <param name="Status">Статус просроченного шага (ApprovalStatus строки списка «… — согласование»).</param>
|
||||
/// <param name="Category">Вид напоминания — один на конкретный (sealed) наследник, см. их конструкторы.</param>
|
||||
/// <param name="Url">Ссылка на заявку.</param>
|
||||
/// <param name="RequestTypeId">Id типа заявки (RequestType).</param>
|
||||
/// <param name="RequestTypeName">Название типа заявки — для читаемости в письме/таблице, без похода в БД.</param>
|
||||
/// <param name="RequestId">Id заявки (TicketId строки списка согласования / Id строки списка данных).</param>
|
||||
/// <param name="Status">Статус заявки/шага — из того списка, который читает конкретный вид напоминания.</param>
|
||||
/// <param name="RequestUniqueCode">
|
||||
/// Уникальный код заявки (колонка RequestUniqueCode списка данных) — null, если у
|
||||
/// заявки его нет или строка данных не найдена.
|
||||
/// </param>
|
||||
/// <param name="Category">
|
||||
/// Вид напоминания. Необязательный — параметр добавлен позже остальных, поэтому по
|
||||
/// умолчанию <see cref="ReminderCategory.None"/> («не указана»): старые вызовы
|
||||
/// конструктора и потребители, ничего не знающие о категориях, продолжают работать
|
||||
/// как раньше.
|
||||
/// </param>
|
||||
/// <param name="ManagerEmail">
|
||||
/// Только для <see cref="ReminderCategory.ProbationEnding"/> — email руководителя
|
||||
/// принимаемого сотрудника (см. ReminderService.GetProbationEndingAsync). Для
|
||||
/// остальных категорий — null.
|
||||
/// </param>
|
||||
/// <param name="CandidateEmail">Только для ProbationEnding — email принимаемого сотрудника.</param>
|
||||
/// <param name="CandidateName">Только для ProbationEnding — ФИО принимаемого сотрудника (колонка CandidateName).</param>
|
||||
/// <param name="ProbationPeriod">Только для ProbationEnding — текст испытательного срока (колонка ProbationPeriod).</param>
|
||||
/// <param name="HireDate">Только для ProbationEnding — дата приёма (колонка HireDate).</param>
|
||||
/// <param name="ProbationEndsAt">Только для ProbationEnding — дата окончания испытательного срока (HireDate + срок).</param>
|
||||
/// <param name="DaysUntilProbationEnds">Только для ProbationEnding — сколько дней осталось до конца испытательного срока.</param>
|
||||
public sealed record ReminderDto(
|
||||
string Email,
|
||||
int HoursOverdue,
|
||||
/// <remarks>
|
||||
/// Общая часть двух видов напоминаний — <see cref="ApprovalOverdueReminderDto"/> и
|
||||
/// <see cref="ProbationEndingReminderDto"/>. У них разные поля-триггеры и разные
|
||||
/// адресаты, общее — только то, что описано здесь (к какой заявке относится строка
|
||||
/// и как её открыть).
|
||||
///
|
||||
/// [JsonPolymorphic]/[JsonDerivedType] — вместо того чтобы полагаться на
|
||||
/// compile-time тип элемента (ReminderService всегда работает со списком именно
|
||||
/// этого базового типа, см. IReadOnlyList<ReminderDto>), System.Text.Json без
|
||||
/// этих атрибутов сериализовал бы только поля базового класса, теряя специфичные
|
||||
/// для наследника (Email/HoursOverdue или ManagerEmail/CandidateEmail и т.д.).
|
||||
/// Дискриминатор — отдельное системное поле "$type", а не Category: значение
|
||||
/// Category читаемое (совпадает с именем enum-константы через уже подключенный
|
||||
/// глобально JsonStringEnumConverter, см. Program.cs) и не привязано к деталям
|
||||
/// сериализации.
|
||||
/// </remarks>
|
||||
[JsonPolymorphic]
|
||||
[JsonDerivedType(typeof(ApprovalOverdueReminderDto), nameof(ReminderCategory.ApprovalOverdue))]
|
||||
[JsonDerivedType(typeof(ProbationEndingReminderDto), nameof(ReminderCategory.ProbationEnding))]
|
||||
public abstract record ReminderDto(
|
||||
ReminderCategory Category,
|
||||
string Url,
|
||||
bool AskOverdueReason,
|
||||
int RequestTypeId,
|
||||
string RequestTypeName,
|
||||
int RequestId,
|
||||
string Status,
|
||||
string? RequestUniqueCode,
|
||||
ReminderCategory Category = ReminderCategory.None,
|
||||
string? ManagerEmail = null,
|
||||
string? CandidateEmail = null,
|
||||
string? CandidateName = null,
|
||||
string? ProbationPeriod = null,
|
||||
DateTimeOffset? HireDate = null,
|
||||
DateTimeOffset? ProbationEndsAt = null,
|
||||
int? DaysUntilProbationEnds = null);
|
||||
string? RequestUniqueCode);
|
||||
Reference in New Issue
Block a user