feat: added optin to add delegant for executor and change delegant
This commit is contained in:
@@ -11,6 +11,13 @@ import { emitRequestsChanged } from '../requestEvents';
|
||||
// approve/return/reject — согласующий; execute — исполнитель отметил «Выполнено».
|
||||
export type ApproverDecision = 'approve' | 'return' | 'reject' | 'execute';
|
||||
|
||||
// Активная строка текущего пользователя: либо он сам назначен на неё
|
||||
// (isDelegator=false), либо это его делегат недоступен (в отпуске и т.п.) и он,
|
||||
// как делегировавший, вправе переназначить шаг ещё раз (isDelegator=true).
|
||||
export interface IPendingRow extends IApprovalRow {
|
||||
isDelegator: boolean;
|
||||
}
|
||||
|
||||
// Решение → статус его строки в списке согласования.
|
||||
const ROW_STATUS: Record<ApproverDecision, string> = {
|
||||
approve: REQUEST_STATUS.approved,
|
||||
@@ -35,7 +42,12 @@ export class ApproverService {
|
||||
// Очередь уже проставлена на запись (см. createSteps/advanceQueue) — активна
|
||||
// ровно одна строка со статусом «На согласовании» на фазу, искать «первую по
|
||||
// порядку» не нужно.
|
||||
public async getPendingRowForCurrentUser(requestId: number): Promise<IApprovalRow | undefined> {
|
||||
//
|
||||
// Если пользователь сам не назначен на активную строку, но именно он когда-то
|
||||
// делегировал её текущему держателю (delegatedById) — строка тоже считается
|
||||
// «его», но с isDelegator=true: DecisionPanel в этом случае даёт только
|
||||
// переназначить (не решать за делегата), см. её использование там.
|
||||
public async getPendingRowForCurrentUser(requestId: number): Promise<IPendingRow | undefined> {
|
||||
const rows = await this.approval.getForRequest(requestId);
|
||||
const userId = await this.approval.getCurrentUserId();
|
||||
// Активные строки текущего шага: согласующий («На согласовании») или, когда
|
||||
@@ -45,11 +57,17 @@ export class ApproverService {
|
||||
const active = rows.filter(
|
||||
(r) => r.status === REQUEST_STATUS.onApproval || r.status === REQUEST_STATUS.onExecution
|
||||
);
|
||||
return active.filter((r) => r.approverId === userId)[0];
|
||||
const own = active.filter((r) => r.approverId === userId)[0];
|
||||
if (own) return { ...own, isDelegator: false };
|
||||
const delegated = active.filter((r) => r.delegatedById === userId)[0];
|
||||
return delegated ? { ...delegated, isDelegator: true } : undefined;
|
||||
}
|
||||
|
||||
// Делегирование: согласующий добавляет делеганта ПЕРЕД собой (Order — между
|
||||
// предыдущей строкой и своей). Делегат согласует раньше и сам не делегирует.
|
||||
// предыдущей строкой и своей). Делегат согласует раньше и сам не делегирует
|
||||
// (allowReassign всегда false у новой строки) — зато делегировавший (текущий
|
||||
// пользователь) сохраняет право переназначить эту строку ещё раз, если делегат
|
||||
// тоже окажется недоступен (см. getPendingRowForCurrentUser/isDelegator).
|
||||
public async delegate(
|
||||
requestId: number,
|
||||
currentRowId: number,
|
||||
@@ -62,6 +80,7 @@ export class ApproverService {
|
||||
const prevOrder = before.length > 0 ? before[before.length - 1].order : current.order - 1;
|
||||
const newOrder = (prevOrder + current.order) / 2;
|
||||
const position = await this.approval.getJobTitle(user.loginName);
|
||||
const delegatedById = await this.approval.getCurrentUserId();
|
||||
// Делегат наследует фазу той строки, вместо которой согласует (согласование/исполнение).
|
||||
// Обе строки — делегат и прежний согласующий — уходят в «Ждёт очереди»,
|
||||
// activateNextQueued затем активирует делегата (у него меньший order).
|
||||
@@ -70,7 +89,8 @@ export class ApproverService {
|
||||
{ email: user.email, position, allowReassign: false },
|
||||
newOrder,
|
||||
REQUEST_STATUS.queued,
|
||||
current.phase
|
||||
current.phase,
|
||||
delegatedById
|
||||
);
|
||||
await this.approval.setStatus(current.id, REQUEST_STATUS.queued);
|
||||
await this.approval.activateNextQueued(requestId);
|
||||
|
||||
Reference in New Issue
Block a user