feat: читать заявки в admin-вкладках от имени приложения, а не пользователя

«Редактирование заявок» и «Заявки по согласующему» раньше читали списки
SharePoint напрямую с фронтенда (PnP от имени залогиненного администратора),
из-за чего видимые заявки молча урезались правами САМОГО администратора на
списки. Добавлен RequestManageService/RequestManageController на бэкенде
(app-only SharePointClient, по образцу ReminderService) — теперь чтение
(поиск заявки, матрица маршрута, строки по согласующему) идёт через него,
а правка (переназначить/удалить/переставить/уведомить) остаётся на PnP.

Заодно кнопка уведомления в таблице маршрута включена и для строк в статусе
«Возвращена на доработку» — по клику поток Power Automate уведомляет автора
заявки, что её вернули на доработку.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
gorbenko.pavel
2026-09-25 10:51:08 +05:00
parent 2b8fe77fac
commit d9d68405ab
12 changed files with 607 additions and 479 deletions
@@ -0,0 +1,76 @@
namespace Tnsu.ApprovalRoute.Application.RequestManage;
// Формы 1:1 с фронтендом (frontend/src/webparts/approvalAdmin/models/requestManage.ts,
// manageByUser.ts) — эти DTO заменяют собой то, что раньше собирал PnP-клиент
// НАПРЯМУЮ в SharePoint от имени текущего пользователя (см. requestManageService.ts):
// тут это делает бэкенд от имени приложения (см. ISharePointClient), поэтому
// результат не зависит от прав конкретного пользователя на списки SharePoint.
/// <summary>Заявка (строка списка «… — данные»), как её видит комбобокс выбора заявки.</summary>
public sealed record ManagedRequestSummaryDto(
int Id,
string Title,
string Status,
/// <summary>ISO 8601 или пустая строка.</summary>
string Created,
string AuthorName,
string? UniqueCode,
/// <summary>Партиция (серверный относительный url списка данных), где физически лежит заявка.</summary>
string ListId);
public sealed record ManagedRequestPageDto(IReadOnlyList<ManagedRequestSummaryDto> Items, bool HasMore);
/// <summary>Строка списка «… — согласование».</summary>
public sealed record ManagedApprovalRowDto(
int Id,
int TicketId,
int? ApproverId,
string ApproverName,
string ApproverEmail,
string Position,
string Status,
/// <summary>ISO 8601 или пустая строка — форматирование под «дд.мм.гггг» остаётся на фронтенде.</summary>
string DateIso,
string Comment,
double Order,
bool AllowReassign,
string Phase,
int? SlaHours,
bool? AskOverdueReason);
/// <summary>Заявка + полный маршрут (обе фазы) — для экрана редактирования заявок.</summary>
public sealed record ManagedRequestMatrixDto(
ManagedRequestSummaryDto Request,
string SiteUrl,
string DataListTitle,
string DataListUrl,
string ApprovalListTitle,
IReadOnlyList<ManagedApprovalRowDto> Rows);
/// <summary>
/// Строка согласования, найденная сразу по ВСЕМ типам заявок и партициям — для
/// экрана «Заявки по согласующему» (UserApprovalRow во фронтенде — тот же набор
/// полей, что и ManagedApprovalRowDto, только развёрнутый, а не вложенный).
/// </summary>
public sealed record UserApprovalRowDto(
int Id,
int TicketId,
int? ApproverId,
string ApproverName,
string ApproverEmail,
string Position,
string Status,
string DateIso,
string Comment,
double Order,
bool AllowReassign,
string Phase,
int? SlaHours,
bool? AskOverdueReason,
int RequestTypeId,
string RequestTypeName,
string SiteUrl,
string ListId,
string ApprovalListTitle,
string RequestTitle,
string? RequestUniqueCode);