feat: письмо инициатору при отклонении и возврате заявки

Поток RequestsNotification умеет ветки «Отклонено» и «Возврат на доработку»,
но портал их не вызывал: notifyActiveStep ищет только активные строки, а после
такого решения их нет — инициатор узнавал о решении, только открыв заявку.

notifyInitiatorOfReturn шлёт в тот же поток RowID строки, по которой решил
текущий пользователь; подключён в onDecided всех форм, кроме «Изменения
условий ТД» (доработаем позже).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Тимур Городецкий
2026-10-28 16:50:31 +05:00
parent 72e330e659
commit 9cacb6b271
17 changed files with 198 additions and 76 deletions
@@ -10,6 +10,7 @@ import {
StatusBadge,
ApprovalHistory,
notifyActiveStep,
notifyInitiatorOfReturn,
useRequestTypeId,
usePhasedRoute
} from '../../shared/approval';
@@ -108,14 +109,17 @@ const BusinessTripView: React.FC<IBusinessTripViewProps> = ({ context, itemId, f
);
}
const notify = (): void => {
const notify = (newStatus?: string): void => {
// Решение уже применено; без requestTypeId просто некого уведомлять — UI не роняем.
if (!requestTypeId) return;
notifyActiveStep(context, approval, itemId, {
const target = {
requestTypeId,
dataListName: listId ? dataListTitleForListId(FORM_ID, listId) : dataListTitle(FORM_ID),
approvalListName: listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID)
}).catch(() => undefined);
};
notifyActiveStep(context, approval, itemId, target).catch(() => undefined);
// Отклонили или вернули на доработку — письмо инициатору (при других статусах ничего не делает).
if (newStatus) notifyInitiatorOfReturn(context, approval, itemId, target, newStatus).catch(() => undefined);
};
const sectionProps = { data, set: NOOP_SET, context };
@@ -173,7 +177,7 @@ const BusinessTripView: React.FC<IBusinessTripViewProps> = ({ context, itemId, f
onDecided={(newStatus) => {
setStatus(newStatus);
setDecisionSeq((n) => n + 1);
notify();
notify(newStatus);
}}
onDelegated={() => {
setDecisionSeq((n) => n + 1);
@@ -11,6 +11,7 @@ import {
ApprovalHistory,
useMatrixEditor,
notifyActiveStep,
notifyInitiatorOfReturn,
useRequestTypeId,
APPROVAL_PHASE
} from '../../shared/approval';
@@ -255,16 +256,19 @@ const ClearanceView: React.FC<IClearanceViewProps> = ({ context, itemId, formKey
printOrgIndex
};
const notify = (): void => {
const notify = (newStatus?: string): void => {
// requestTypeId ещё не резолвился — решение уже применилось (строка списка
// обновлена), просто нечего уведомлять на следующем шаге; не проваливаем
// весь UI ради необязательного оповещения.
if (!requestTypeId) return;
notifyActiveStep(context, approval, itemId, {
const target = {
requestTypeId,
dataListName: listId ? dataListTitleForListId(FORM_ID, listId) : dataListTitle(FORM_ID),
approvalListName: listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID)
}).catch(() => undefined);
};
notifyActiveStep(context, approval, itemId, target).catch(() => undefined);
// Отклонили или вернули на доработку — письмо инициатору (при других статусах ничего не делает).
if (newStatus) notifyInitiatorOfReturn(context, approval, itemId, target, newStatus).catch(() => undefined);
};
return (
@@ -348,7 +352,7 @@ const ClearanceView: React.FC<IClearanceViewProps> = ({ context, itemId, formKey
onDecided={(newStatus) => {
setStatus(newStatus);
setDecisionSeq((n) => n + 1);
notify();
notify(newStatus);
}}
onDelegated={() => {
setDecisionSeq((n) => n + 1);
@@ -12,6 +12,7 @@ import {
ApprovalHistory,
useMatrixEditor,
notifyActiveStep,
notifyInitiatorOfReturn,
useRequestTypeId,
useViewExecutors,
approvalPhaseRows
@@ -118,16 +119,19 @@ const ConcreteRequestView: React.FC<IConcreteRequestViewProps> = ({ context, ite
const sectionProps = { data, set: NOOP_SET, context, printOrgIndex };
const notify = (): void => {
const notify = (newStatus?: string): void => {
// requestTypeId ещё не резолвился — решение уже применилось (строка списка
// обновлена), просто нечего уведомлять на следующем шаге; не проваливаем
// весь UI ради необязательного оповещения.
if (!requestTypeId) return;
notifyActiveStep(context, approval, itemId, {
const target = {
requestTypeId,
dataListName: listId ? dataListTitleForListId(FORM_ID, listId) : dataListTitle(FORM_ID),
approvalListName: listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID)
}).catch(() => undefined);
};
notifyActiveStep(context, approval, itemId, target).catch(() => undefined);
// Отклонили или вернули на доработку — письмо инициатору (при других статусах ничего не делает).
if (newStatus) notifyInitiatorOfReturn(context, approval, itemId, target, newStatus).catch(() => undefined);
};
return (
@@ -175,7 +179,7 @@ const ConcreteRequestView: React.FC<IConcreteRequestViewProps> = ({ context, ite
onDecided={(newStatus) => {
setStatus(newStatus);
setDecisionSeq((n) => n + 1);
notify();
notify(newStatus);
}}
onDelegated={() => {
setDecisionSeq((n) => n + 1);
@@ -12,6 +12,7 @@ import {
ApprovalHistory,
useMatrixEditor,
notifyActiveStep,
notifyInitiatorOfReturn,
useRequestTypeId,
REQUEST_STATUS,
approvalPhaseRows,
@@ -218,16 +219,19 @@ const DismissalView: React.FC<IDismissalViewProps> = ({ context, itemId, formKey
await updateAssetsAcceptor(itemId, data.AssetsAcceptor, listId);
};
const notify = (): void => {
const notify = (newStatus?: string): void => {
// requestTypeId ещё не резолвился — решение уже применилось (строка списка
// обновлена), просто нечего уведомлять на следующем шаге; не проваливаем
// весь UI ради необязательного оповещения.
if (!requestTypeId) return;
notifyActiveStep(context, approval, itemId, {
const target = {
requestTypeId,
dataListName: listId ? dataListTitleForListId(FORM_ID, listId) : dataListTitle(FORM_ID),
approvalListName: listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID)
}).catch(() => undefined);
};
notifyActiveStep(context, approval, itemId, target).catch(() => undefined);
// Отклонили или вернули на доработку — письмо инициатору (при других статусах ничего не делает).
if (newStatus) notifyInitiatorOfReturn(context, approval, itemId, target, newStatus).catch(() => undefined);
};
// Заявление согласовано целиком → сразу заводим обходной лист по нему (данные
@@ -311,7 +315,7 @@ const DismissalView: React.FC<IDismissalViewProps> = ({ context, itemId, formKey
onDecided={(newStatus) => {
setStatus(newStatus);
setDecisionSeq((n) => n + 1);
notify();
notify(newStatus);
// «Согласовано» = маршрут заявления пройден целиком (фазы исполнения у
// него нет, см. README формы) — значит увольнение подтверждено и пора
// заводить обходной лист. Промис ВОЗВРАЩАЕМ: пока он не разрешится,
@@ -14,6 +14,7 @@ import {
ExecutorsMatrix,
approvalPhaseRows,
notifyActiveStep,
notifyInitiatorOfReturn,
useRequestTypeId
} from '../../shared/approval';
import { friendlyErrorMessage } from '../../shared/diagnostics';
@@ -117,16 +118,19 @@ const EmployeeTransferView: React.FC<IEmployeeTransferViewProps> = ({ context, i
const sectionProps = { data, set: NOOP_SET, context, printOrgIndex };
const notify = (): void => {
const notify = (newStatus?: string): void => {
// requestTypeId ещё не резолвился — решение уже применилось (строка списка
// обновлена), просто нечего уведомлять на следующем шаге; не проваливаем
// весь UI ради необязательного оповещения.
if (!requestTypeId) return;
notifyActiveStep(context, approval, itemId, {
const target = {
requestTypeId,
dataListName: listId ? dataListTitleForListId(FORM_ID, listId) : dataListTitle(FORM_ID),
approvalListName: listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID)
}).catch(() => undefined);
};
notifyActiveStep(context, approval, itemId, target).catch(() => undefined);
// Отклонили или вернули на доработку — письмо инициатору (при других статусах ничего не делает).
if (newStatus) notifyInitiatorOfReturn(context, approval, itemId, target, newStatus).catch(() => undefined);
};
return (
@@ -172,7 +176,7 @@ const EmployeeTransferView: React.FC<IEmployeeTransferViewProps> = ({ context, i
onDecided={(newStatus) => {
setStatus(newStatus);
setDecisionSeq((n) => n + 1);
notify();
notify(newStatus);
}}
onDelegated={() => {
setDecisionSeq((n) => n + 1);
@@ -24,6 +24,7 @@ import {
ApprovalHistory,
useMatrixEditor,
notifyActiveStep,
notifyInitiatorOfReturn,
useRequestTypeId,
APPROVAL_PHASE,
isApprovedStatus,
@@ -283,13 +284,16 @@ const RecruitingHireView: React.FC<IRecruitingHireViewProps> = ({ context, itemI
);
// Выше ранних return (загрузка/ошибка): зовётся и из колбэков хуков ниже.
const notify = (): void => {
const notify = (newStatus?: string): void => {
if (!requestTypeId) return;
notifyActiveStep(context, approval, itemId, {
const target = {
requestTypeId,
dataListName: listId ? dataListTitleForListId(FORM_ID, listId) : dataListTitle(FORM_ID),
approvalListName: listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID),
}).catch(() => undefined);
};
notifyActiveStep(context, approval, itemId, target).catch(() => undefined);
// Отклонили или вернули на доработку — письмо инициатору (при других статусах ничего не делает).
if (newStatus) notifyInitiatorOfReturn(context, approval, itemId, target, newStatus).catch(() => undefined);
};
// Добавить согласующего/исполнителя в поданную заявку — то же право
@@ -479,7 +483,7 @@ const RecruitingHireView: React.FC<IRecruitingHireViewProps> = ({ context, itemI
setStatus(newStatus);
setDecisionSeq((n) => n + 1);
// Очередь сдвинулась — уведомляем следующий активный шаг.
notify();
notify(newStatus);
}}
onDelegated={() => {
// Шаг переназначен: активной стала строка делегата — обновляем
@@ -22,6 +22,7 @@ import {
ApprovalHistory,
useMatrixEditor,
notifyActiveStep,
notifyInitiatorOfReturn,
useRequestTypeId,
isApprovedStatus,
resolveApproverOrgInfo,
@@ -204,20 +205,25 @@ const RecruitingSelectionView: React.FC<IRecruitingSelectionViewProps> = ({ cont
await saveAllFields();
};
// rowId — оповестить конкретную активную строку (см. notifyActiveStep).
const notify = (rowId?: number): void => {
if (!requestTypeId) return;
notifyActiveStep(
context,
approval,
itemId,
{
// Куда смотрит поток оповещения; undefined — тип заявки ещё не резолвился.
const notifyTarget = requestTypeId
? {
requestTypeId,
dataListName: listId ? dataListTitleForListId(FORM_ID, listId) : dataListTitle(FORM_ID),
approvalListName: listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID)
},
rowId
).catch(() => undefined);
}
: undefined;
// rowId — оповестить конкретную активную строку (см. notifyActiveStep).
const notify = (rowId?: number): void => {
if (!notifyTarget) return;
notifyActiveStep(context, approval, itemId, notifyTarget, rowId).catch(() => undefined);
};
// Отклонили или вернули на доработку — письмо инициатору (при других статусах ничего не делает).
const notifyInitiator = (newStatus: string): void => {
if (!notifyTarget) return;
notifyInitiatorOfReturn(context, approval, itemId, notifyTarget, newStatus).catch(() => undefined);
};
// Удалить ещё не решённый шаг маршрута (см. ApproverService.deleteQueuedStep).
@@ -467,6 +473,7 @@ const RecruitingSelectionView: React.FC<IRecruitingSelectionViewProps> = ({ cont
setStatus(newStatus);
setDecisionSeq((n) => n + 1);
notify();
notifyInitiator(newStatus);
}}
onDelegated={() => {
setDecisionSeq((n) => n + 1);
@@ -21,6 +21,7 @@ import {
ApprovalHistory,
useMatrixEditor,
notifyActiveStep,
notifyInitiatorOfReturn,
useRequestTypeId,
APPROVAL_PHASE,
isApprovedStatus,
@@ -169,16 +170,19 @@ const ReferralView: React.FC<IReferralViewProps> = ({ context, itemId, formKey,
const sectionProps = { data, set: NOOP_SET, context, printOrgIndex };
const notify = (): void => {
const notify = (newStatus?: string): void => {
// requestTypeId ещё не резолвился — решение уже применилось (строка списка
// обновлена), просто нечего уведомлять на следующем шаге; не проваливаем
// весь UI ради необязательного оповещения.
if (!requestTypeId) return;
notifyActiveStep(context, approval, itemId, {
const target = {
requestTypeId,
dataListName: listId ? dataListTitleForListId(FORM_ID, listId) : dataListTitle(FORM_ID),
approvalListName: listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID)
}).catch(() => undefined);
};
notifyActiveStep(context, approval, itemId, target).catch(() => undefined);
// Отклонили или вернули на доработку — письмо инициатору (при других статусах ничего не делает).
if (newStatus) notifyInitiatorOfReturn(context, approval, itemId, target, newStatus).catch(() => undefined);
};
return (
@@ -253,7 +257,7 @@ const ReferralView: React.FC<IReferralViewProps> = ({ context, itemId, formKey,
onDecided={(newStatus) => {
setStatus(newStatus);
setDecisionSeq((n) => n + 1);
notify();
notify(newStatus);
}}
onDelegated={() => {
setDecisionSeq((n) => n + 1);
@@ -24,6 +24,7 @@ import {
ExecutorsMatrix,
approvalPhaseRows,
notifyActiveStep,
notifyInitiatorOfReturn,
useRequestTypeId,
isEditableStatus
} from '../../shared/approval';
@@ -141,13 +142,16 @@ const ServiceRequestView: React.FC<IServiceRequestViewProps> = ({ context, itemI
const sectionProps = { data, set, context, printOrgIndex, attachmentUrls };
const notify = (): void => {
const notify = (newStatus?: string): void => {
if (!requestTypeId) return;
notifyActiveStep(context, approval, itemId, {
const target = {
requestTypeId,
dataListName: listId ? dataListTitleForListId(FORM_ID, listId) : dataListTitle(FORM_ID),
approvalListName: listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID)
}).catch(() => undefined);
};
notifyActiveStep(context, approval, itemId, target).catch(() => undefined);
// Отклонили или вернули на доработку — письмо инициатору (при других статусах ничего не делает).
if (newStatus) notifyInitiatorOfReturn(context, approval, itemId, target, newStatus).catch(() => undefined);
};
return (
@@ -205,7 +209,7 @@ const ServiceRequestView: React.FC<IServiceRequestViewProps> = ({ context, itemI
onDecided={(newStatus) => {
setStatus(newStatus);
setDecisionSeq((n) => n + 1);
notify();
notify(newStatus);
}}
onDelegated={() => {
setDecisionSeq((n) => n + 1);
@@ -9,6 +9,7 @@ import {
StatusBadge,
ApprovalHistory,
notifyActiveStep,
notifyInitiatorOfReturn,
useRequestTypeId,
usePhasedRoute
} from '../../shared/approval';
@@ -110,14 +111,17 @@ const SkudExplanationView: React.FC<ISkudExplanationViewProps> = ({ context, ite
);
}
const notify = (): void => {
const notify = (newStatus?: string): void => {
// Решение уже применено; без requestTypeId просто некого уведомлять — UI не роняем.
if (!requestTypeId) return;
notifyActiveStep(context, approval, itemId, {
const target = {
requestTypeId,
dataListName: listId ? dataListTitleForListId(FORM_ID, listId) : dataListTitle(FORM_ID),
approvalListName: listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID)
}).catch(() => undefined);
};
notifyActiveStep(context, approval, itemId, target).catch(() => undefined);
// Отклонили или вернули на доработку — письмо инициатору (при других статусах ничего не делает).
if (newStatus) notifyInitiatorOfReturn(context, approval, itemId, target, newStatus).catch(() => undefined);
};
const sectionProps = { data, set: NOOP_SET, context, printOrgIndex };
@@ -175,7 +179,7 @@ const SkudExplanationView: React.FC<ISkudExplanationViewProps> = ({ context, ite
onDecided={(newStatus) => {
setStatus(newStatus);
setDecisionSeq((n) => n + 1);
notify();
notify(newStatus);
}}
onDelegated={() => {
setDecisionSeq((n) => n + 1);
@@ -23,6 +23,7 @@ import {
ApprovalHistory,
useMatrixEditor,
notifyActiveStep,
notifyInitiatorOfReturn,
useRequestTypeId,
isEditableStatus,
APPROVAL_PHASE
@@ -102,20 +103,25 @@ const Ticket1CView: React.FC<ITicket1CViewProps> = ({ context, itemId, formKey,
approval.getJobTitle(l)
);
// rowId — оповестить конкретную активную строку (см. notifyActiveStep).
const notify = (rowId?: number): void => {
if (!requestTypeId) return;
notifyActiveStep(
context,
approval,
itemId,
{
// Куда смотрит поток оповещения; undefined — тип заявки ещё не резолвился.
const notifyTarget = requestTypeId
? {
requestTypeId,
dataListName: listId ? dataListTitleForListId(FORM_ID, listId) : dataListTitle(FORM_ID),
approvalListName: listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID)
},
rowId
).catch(() => undefined);
}
: undefined;
// rowId — оповестить конкретную активную строку (см. notifyActiveStep).
const notify = (rowId?: number): void => {
if (!notifyTarget) return;
notifyActiveStep(context, approval, itemId, notifyTarget, rowId).catch(() => undefined);
};
// Отклонили или вернули на доработку — письмо инициатору (при других статусах ничего не делает).
const notifyInitiator = (newStatus: string): void => {
if (!notifyTarget) return;
notifyInitiatorOfReturn(context, approval, itemId, notifyTarget, newStatus).catch(() => undefined);
};
const executorEditing = useExecutorEditing({
@@ -246,6 +252,7 @@ const Ticket1CView: React.FC<ITicket1CViewProps> = ({ context, itemId, formKey,
setDecisionSeq((n) => n + 1);
// Очередь сдвинулась — уведомляем следующий активный шаг.
notify();
notifyInitiator(newStatus);
// Дошла до исполнения / завершилась / отклонена — карточка в Planner
// (повторно не создаётся, см. plannerHandoff.ts).
@@ -24,6 +24,7 @@ import {
ApprovalHistory,
useMatrixEditor,
notifyActiveStep,
notifyInitiatorOfReturn,
useRequestTypeId,
isEditableStatus,
APPROVAL_PHASE
@@ -144,13 +145,16 @@ const TmcTransferView: React.FC<ITmcTransferViewProps> = ({ context, itemId, for
const sectionProps = { data, set, context, printOrgIndex };
const notify = (): void => {
const notify = (newStatus?: string): void => {
if (!requestTypeId) return;
notifyActiveStep(context, approval, itemId, {
const target = {
requestTypeId,
dataListName: listId ? dataListTitleForListId(FORM_ID, listId) : dataListTitle(FORM_ID),
approvalListName: listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID)
}).catch(() => undefined);
};
notifyActiveStep(context, approval, itemId, target).catch(() => undefined);
// Отклонили или вернули на доработку — письмо инициатору (при других статусах ничего не делает).
if (newStatus) notifyInitiatorOfReturn(context, approval, itemId, target, newStatus).catch(() => undefined);
};
return (
@@ -222,7 +226,7 @@ const TmcTransferView: React.FC<ITmcTransferViewProps> = ({ context, itemId, for
onDecided={(newStatus) => {
setStatus(newStatus);
setDecisionSeq((n) => n + 1);
notify();
notify(newStatus);
}}
onDelegated={() => {
setDecisionSeq((n) => n + 1);
@@ -22,6 +22,7 @@ import {
useViewExecutors,
approvalPhaseRows,
notifyActiveStep,
notifyInitiatorOfReturn,
useRequestTypeId
} from '../../shared/approval';
import { friendlyErrorMessage } from '../../shared/diagnostics';
@@ -125,16 +126,19 @@ const UnpaidLeaveView: React.FC<IUnpaidLeaveViewProps> = ({ context, itemId, for
const sectionProps = { data, set: NOOP_SET, context, printOrgIndex };
const notify = (): void => {
const notify = (newStatus?: string): void => {
// requestTypeId ещё не резолвился — решение уже применилось (строка списка
// обновлена), просто нечего уведомлять на следующем шаге; не проваливаем
// весь UI ради необязательного оповещения.
if (!requestTypeId) return;
notifyActiveStep(context, approval, itemId, {
const target = {
requestTypeId,
dataListName: listId ? dataListTitleForListId(FORM_ID, listId) : dataListTitle(FORM_ID),
approvalListName: listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID)
}).catch(() => undefined);
};
notifyActiveStep(context, approval, itemId, target).catch(() => undefined);
// Отклонили или вернули на доработку — письмо инициатору (при других статусах ничего не делает).
if (newStatus) notifyInitiatorOfReturn(context, approval, itemId, target, newStatus).catch(() => undefined);
};
return (
@@ -182,7 +186,7 @@ const UnpaidLeaveView: React.FC<IUnpaidLeaveViewProps> = ({ context, itemId, for
onDecided={(newStatus) => {
setStatus(newStatus);
setDecisionSeq((n) => n + 1);
notify();
notify(newStatus);
}}
onDelegated={() => {
setDecisionSeq((n) => n + 1);
@@ -23,6 +23,7 @@ import {
ExecutorsMatrix,
approvalPhaseRows,
notifyActiveStep,
notifyInitiatorOfReturn,
useRequestTypeId
} from '../../shared/approval';
import { completesApprovalPhase } from '../../shared/approval/models/statuses';
@@ -143,16 +144,19 @@ const VacationView: React.FC<IVacationViewProps> = ({ context, itemId, formKey,
const sectionProps = { data, set: NOOP_SET, context, printOrgIndex };
const notify = (): void => {
const notify = (newStatus?: string): void => {
// requestTypeId ещё не резолвился — решение уже применилось (строка списка
// обновлена), просто нечего уведомлять на следующем шаге; не проваливаем
// весь UI ради необязательного оповещения.
if (!requestTypeId) return;
notifyActiveStep(context, approval, itemId, {
const target = {
requestTypeId,
dataListName: listId ? dataListTitleForListId(FORM_ID, listId) : dataListTitle(FORM_ID),
approvalListName: listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID)
}).catch(() => undefined);
};
notifyActiveStep(context, approval, itemId, target).catch(() => undefined);
// Отклонили или вернули на доработку — письмо инициатору (при других статусах ничего не делает).
if (newStatus) notifyInitiatorOfReturn(context, approval, itemId, target, newStatus).catch(() => undefined);
};
// Заявление уходит на подпись в ЭДО (по документу на каждую компанию сотрудника, одним запросом).
@@ -263,7 +267,7 @@ const VacationView: React.FC<IVacationViewProps> = ({ context, itemId, formKey,
onDecided={(newStatus) => {
setStatus(newStatus);
setDecisionSeq((n) => n + 1);
notify();
notify(newStatus);
return VACATION_EDO_SIGNING_ENABLED && sentBeforeDecision.current ?'Документы отправлены на подписание в ЭДО.' : undefined;
}}
onDelegated={() => {
@@ -23,6 +23,7 @@ import {
ApprovalHistory,
useMatrixEditor,
notifyActiveStep,
notifyInitiatorOfReturn,
useRequestTypeId,
isEditableStatus,
APPROVAL_PHASE,
@@ -224,13 +225,16 @@ const WorkplaceSetupView: React.FC<IWorkplaceSetupViewProps> = ({ context, itemI
const sectionProps = { data, set, context, printOrgIndex };
const canEditAnything = canEditAll || canEditReviewFields;
const notify = (): void => {
const notify = (newStatus?: string): void => {
if (!requestTypeId) return;
notifyActiveStep(context, approval, itemId, {
const target = {
requestTypeId,
dataListName: listId ? dataListTitleForListId(FORM_ID, listId) : dataListTitle(FORM_ID),
approvalListName: listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID),
}).catch(() => undefined);
};
notifyActiveStep(context, approval, itemId, target).catch(() => undefined);
// Отклонили или вернули на доработку — письмо инициатору (при других статусах ничего не делает).
if (newStatus) notifyInitiatorOfReturn(context, approval, itemId, target, newStatus).catch(() => undefined);
};
return (
@@ -316,7 +320,7 @@ const WorkplaceSetupView: React.FC<IWorkplaceSetupViewProps> = ({ context, itemI
setStatus(newStatus);
setDecisionSeq((n) => n + 1);
// Очередь сдвинулась — уведомляем следующий активный шаг.
notify();
notify(newStatus);
}}
onDelegated={() => {
// Шаг переназначен: активной стала строка делегата — обновляем