From 36fb71da020cd89bcbaa5f297fb095dff404301c Mon Sep 17 00:00:00 2001 From: "gorbenko.pavel" Date: Tue, 18 Aug 2026 10:46:28 +0500 Subject: [PATCH] =?UTF-8?q?RequestUniqueCode=20=D0=B8=D0=B7=20=D0=B4=D0=B0?= =?UTF-8?q?=D0=BD=D0=BD=D1=8B=D1=85=20=D0=B7=D0=B0=D1=8F=D0=B2=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Reminders/ReminderDto.cs | 7 +++- .../Reminders/ReminderService.cs | 32 ++++++++++++++++++- .../ReminderServiceTests.cs | 7 ++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/backend/Tnsu.ApprovalRoute.Application/Reminders/ReminderDto.cs b/backend/Tnsu.ApprovalRoute.Application/Reminders/ReminderDto.cs index 739d177..73f808a 100644 --- a/backend/Tnsu.ApprovalRoute.Application/Reminders/ReminderDto.cs +++ b/backend/Tnsu.ApprovalRoute.Application/Reminders/ReminderDto.cs @@ -11,6 +11,10 @@ namespace Tnsu.ApprovalRoute.Application.Reminders; /// наследованием (шаг перекрывает тип заявки). /// /// Статус просроченного шага (ApprovalStatus строки списка «… — согласование»). +/// +/// Уникальный код заявки (колонка RequestUniqueCode списка данных) — null, если у +/// заявки его нет или строка данных не найдена. +/// public sealed record ReminderDto( string Email, int HoursOverdue, @@ -19,4 +23,5 @@ public sealed record ReminderDto( int RequestTypeId, string RequestTypeName, int RequestId, - string Status); + string Status, + string? RequestUniqueCode); diff --git a/backend/Tnsu.ApprovalRoute.Application/Reminders/ReminderService.cs b/backend/Tnsu.ApprovalRoute.Application/Reminders/ReminderService.cs index bc2d28d..9fea9c6 100644 --- a/backend/Tnsu.ApprovalRoute.Application/Reminders/ReminderService.cs +++ b/backend/Tnsu.ApprovalRoute.Application/Reminders/ReminderService.cs @@ -96,6 +96,9 @@ public sealed class ReminderService( var active = await ReadRowsAsync(siteUrl, approvalListTitle, ActiveStatusFilter, cancellationToken); if (active.Count == 0) return []; + var uniqueCodes = await ReadUniqueCodesAsync( + siteUrl, type.ListId!, active.Select(r => r.TicketId).Distinct(), cancellationToken); + var reminders = new List(); foreach (var row in active) { @@ -127,7 +130,8 @@ public sealed class ReminderService( type.Id, type.Name, row.TicketId, - row.Status)); + row.Status, + uniqueCodes.GetValueOrDefault(row.TicketId))); } return reminders; @@ -172,4 +176,30 @@ public sealed class ReminderService( private static List Parse(IEnumerable items) => items.Select(ApprovalRow.TryParse).Where(r => r is not null).Select(r => r!).ToList(); + + /// + /// RequestUniqueCode заявок из списка данных — только по заявкам, у которых + /// сейчас есть просроченный шаг (а не по всему списку: он может быть большим). + /// + private async Task> ReadUniqueCodesAsync( + string siteUrl, string dataListUrl, IEnumerable ticketIds, CancellationToken cancellationToken) + { + var filter = string.Join(" or ", ticketIds.Select(id => $"Id eq {id}")); + if (filter.Length == 0) return new Dictionary(); + + var items = await sharePoint.GetItemsByListUrlAsync( + siteUrl, dataListUrl, $"$select=Id,RequestUniqueCode&$filter={filter}", cancellationToken); + + var result = new Dictionary(); + foreach (var item in items) + { + if (!item.TryGetProperty("Id", out var idProp) || !idProp.TryGetInt32(out var id)) continue; + + result[id] = item.TryGetProperty("RequestUniqueCode", out var code) && code.ValueKind == JsonValueKind.String + ? code.GetString() + : null; + } + + return result; + } } diff --git a/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/ReminderServiceTests.cs b/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/ReminderServiceTests.cs index 9d60089..57d4861 100644 --- a/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/ReminderServiceTests.cs +++ b/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/ReminderServiceTests.cs @@ -92,6 +92,13 @@ public sealed class ReminderServiceTests : IClassFixture(q => q.Contains("ApprovalStatus eq")), It.IsAny())) .ReturnsAsync(activeRows.Select(Json).ToList()); + // RequestUniqueCode запрашивается по списку данных сразу для всех активных + // заявок — по умолчанию тесты его не проверяют, поэтому мок отдаёт пусто. + sharePoint + .Setup(x => x.GetItemsByListUrlAsync( + SiteUrl, listUrl, It.Is(q => q.Contains("RequestUniqueCode")), It.IsAny())) + .ReturnsAsync([]); + return new ReminderService( _services.GetRequiredService(), sharePoint.Object,