import { WebPartContext } from '@microsoft/sp-webpart-base'; import { resolveRoute } from './approvalRoute.service'; import { ApprovalListService, IApproverToWrite } from './approvalList.service'; import { IMatrixRow } from './models/IMatrixRow'; import { ApprovalStatus, IResolveFieldValue } from './models/IApprovalRouteApi'; import { APPROVAL_PHASE, REQUEST_STATUS } from './models/statuses'; // Планируемый маршрут для НОВОЙ заявки: resolve по email инициатора → строки матрицы. // status выбирает фазу: 'Approval' (согласующие, по умолчанию) или 'Execution' // (исполнители). Имена подтягиваются по executorEmail (бэкенд отдаёт email + должность). // departmentId — Id отдела из справочника (влияет на маршрут, если он различается по отделу). export async function getPlannedMatrix( context: WebPartContext, requestTypeId: number, userEmail: string, approval: ApprovalListService, status: ApprovalStatus = 'Approval', // eslint-disable-next-line @rushstack/no-new-null -- транзитом в resolveRoute(), см. её departmentId departmentId?: string | null, fieldValues?: IResolveFieldValue[], // eslint-disable-next-line @rushstack/no-new-null -- см. departmentId projectId?: string | null ): Promise { if (!userEmail) return []; const route = await resolveRoute(context, requestTypeId, userEmail, status, departmentId, fieldValues, projectId); const phase = status === 'Execution' ? APPROVAL_PHASE.execution : APPROVAL_PHASE.approval; const ordered = route.steps.slice().sort((a, b) => a.orderNo - b.orderNo); return Promise.all( ordered.map(async (s) => ({ order: s.orderNo, who: s.executorEmail ? await approval.resolveUserName(s.executorEmail) : '', email: s.executorEmail || '', position: s.position || '', status: '—', date: '', comment: '', allowReassign: s.allowReassignToOtherApprovers, phase, slaHours: s.slaHours, askOverdueReason: s.askOverdueReason, warning: s.warning, })) ); } // Записать строки согласующих для заявки с указанным статусом (только фаза согласования). // Матрица перезаписывается целиком (для повторной отправки/черновика). export async function writeApprovers( approval: ApprovalListService, requestId: number, approvers: IApproverToWrite[], status: string ): Promise { await approval.deleteForRequest(requestId); const submitted = status === REQUEST_STATUS.onApproval; const rowStatus = submitted ? REQUEST_STATUS.queued : status; await approval.createSteps(requestId, approvers, rowStatus, APPROVAL_PHASE.approval, 1); if (submitted) { await approval.activateNextQueued(requestId); } } // Записать ОБЕ фазы маршрута заявки: согласующих (Order 1..N) и исполнителей // (Order N+1..N+M) в один список. Исполнители пишутся сразу при отправке — // стороне согласующего внешний API уже не нужен, переход в фазу исполнения // делает computeRequestStatus, когда все согласующие одобрили. // // Исполнители стартуют ВСЕ как «Ждёт очереди» (rowStatus, та же логика, что и // у согласующих) — до прохождения фазы согласования у исполнителей нет текущей // очереди. Первого исполнителя переключит на «На исполнении» // approval.activateNextQueued, когда фаза согласования будет пройдена целиком // (см. approverDecision.service.ts/decide). export async function writeRoute( approval: ApprovalListService, requestId: number, approvers: IApproverToWrite[], executors: IApproverToWrite[], status: string ): Promise { await approval.deleteForRequest(requestId); // При ОТПРАВКЕ все шаги пишем «Ждёт очереди», затем активируем первый — // так активен ровно текущий шаг, остальные ждут. В черновике — статус заявки // (Черновик), без активации. const submitted = status === REQUEST_STATUS.onApproval; const rowStatus = submitted ? REQUEST_STATUS.queued : status; // Смещение фазы исполнения — по МАКСИМАЛЬНОМУ номеру шага согласующих, а не по // их количеству: при параллельных шагах несколько согласующих делят один номер, // поэтому approvers.length больше последнего реального шага (три согласующих, // из которых двое параллельны, — это шаги 1 и 2, а не 1..3). На очередь это не // влияет (activateNextQueued берёт минимальный order среди ждущих, разрывы ему // безразличны) — но нумерация шагов в таблице «Исполнение» шла бы с пропуском. const lastApprovalStep = approvers.reduce( (max, a, i) => Math.max(max, a.order ?? i + 1), 0 ); await approval.createSteps(requestId, approvers, rowStatus, APPROVAL_PHASE.approval, 1); await approval.createSteps( requestId, executors, rowStatus, APPROVAL_PHASE.execution, lastApprovalStep + 1 ); if (submitted) { await approval.activateNextQueued(requestId); } }