feat: добавление согласующих и исполнителей в поданные заявки на подбор и приём
Алтынай Бултурукова (право canEditRoute) просила добавлять участников в уже поданный маршрут. Новый согласующий или исполнитель встаёт в конец своего этапа со статусом «Ждёт очереди» (дальше его можно поднять стрелками); согласующего — пока идёт согласование, исполнителя — пока не завершено исполнение, без дублей среди ещё не решивших. Заявка «трогается», чтобы бэкенд выдал новому участнику права на элемент данных. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,11 @@ import { IApprovalRow } from './models/IApprovalRow';
|
||||
import { ISiteUser } from './models/ISiteUser';
|
||||
import { emitRequestsChanged } from '../requestEvents';
|
||||
import { planQueuedStepMove, StepMoveDirection } from './queuedStepMove';
|
||||
import { planStepAdd } from './routeStepAdd';
|
||||
|
||||
function isActiveStatus(status: string): boolean {
|
||||
return status === REQUEST_STATUS.onApproval || status === REQUEST_STATUS.onExecution;
|
||||
}
|
||||
|
||||
// approve/return/reject — согласующий; execute — исполнитель отметил «Выполнено».
|
||||
export type ApproverDecision = 'approve' | 'return' | 'reject' | 'execute';
|
||||
@@ -165,6 +170,45 @@ export class ApproverService {
|
||||
emitRequestsChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавить участника в поданную заявку: согласующего или исполнителя — в
|
||||
* КОНЕЦ его этапа со статусом «Ждёт очереди» (право — routeEditRights.ts,
|
||||
* правило — routeStepAdd.ts). Строки перечитываются перед записью.
|
||||
*
|
||||
* Заявку «трогаем» (touchRequest): новый участник должен получить права на
|
||||
* элемент данных, иначе откроет её с «Элемент не найден».
|
||||
*
|
||||
* Возвращает Id строк, ставших активными (обычно пусто — активный шаг уже
|
||||
* есть); им нужно оповещение (отправляет вызывающая сторона).
|
||||
*/
|
||||
public async addStep(requestId: number, phase: string, user: ISiteUser): Promise<number[]> {
|
||||
const [rows, approverId] = await Promise.all([
|
||||
this.approval.getForRequest(requestId),
|
||||
this.approval.getUserIdByEmail(user.email),
|
||||
]);
|
||||
const plan = planStepAdd(rows, phase, approverId);
|
||||
if (!plan.ok) throw new Error(plan.error);
|
||||
|
||||
const position = await this.approval.getJobTitle(user.loginName).catch(() => '');
|
||||
await this.approval.addApproverRow(
|
||||
requestId,
|
||||
{ email: user.email, position, allowReassign: false },
|
||||
plan.order,
|
||||
REQUEST_STATUS.queued,
|
||||
phase
|
||||
);
|
||||
|
||||
// На случай, если активного шага почему-то не было: очередь сама подхватит
|
||||
// нового участника. При обычном ходе заявки ничего не меняется.
|
||||
const activeBefore = new Set(rows.filter((r) => isActiveStatus(r.status)).map((r) => r.id));
|
||||
await this.approval.activateNextQueued(requestId);
|
||||
const rowsAfter = await this.approval.getForRequest(requestId);
|
||||
|
||||
await this.touchRequest(requestId);
|
||||
emitRequestsChanged();
|
||||
return rowsAfter.filter((r) => isActiveStatus(r.status) && !activeBefore.has(r.id)).map((r) => r.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Шаг фазы «Исполнение», который ещё можно заменить или удалить: ждёт очереди
|
||||
* или уже активен («На исполнении»). Выполненный шаг — решение человека, его
|
||||
|
||||
Reference in New Issue
Block a user