fix: условия маршрута по организации в заявке на рабочее место
Форма не передавала в approval-route значения полей, только отдел, поэтому условные шаги («WorkplaceCompaniesJson содержит АСТЕЛ-К», «Organization содержит …», «Software содержит AutoCAD») считались неверно. Теперь передаются организации (имена через пробел, как в приёме и подборе) и «Необходимое ПО»; матрица пересчитывается при их смене. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -34,8 +34,11 @@ import {
|
|||||||
isEditableStatus,
|
isEditableStatus,
|
||||||
IApproverToWrite,
|
IApproverToWrite,
|
||||||
APPROVAL_PHASE,
|
APPROVAL_PHASE,
|
||||||
|
IResolveFieldValue,
|
||||||
unassignedStepMessage
|
unassignedStepMessage
|
||||||
} from '../../shared/approval';
|
} from '../../shared/approval';
|
||||||
|
import { useDebouncedQuery } from '../../shared/usePersistedQuery';
|
||||||
|
import { routeFieldValues } from './routeFields';
|
||||||
import {
|
import {
|
||||||
uploadAttachments,
|
uploadAttachments,
|
||||||
getAttachments,
|
getAttachments,
|
||||||
@@ -165,6 +168,15 @@ const WorkplaceSetupForm: React.FC<IRequestFormProps> = ({
|
|||||||
// data/requests.ts) → числовой RequestTypeId, нужный approval-route API.
|
// data/requests.ts) → числовой RequestTypeId, нужный approval-route API.
|
||||||
const requestTypeIdState = useRequestTypeId(context, requestType.id);
|
const requestTypeIdState = useRequestTypeId(context, requestType.id);
|
||||||
const requestTypeId = requestTypeIdState.id;
|
const requestTypeId = requestTypeIdState.id;
|
||||||
|
// Условные шаги маршрута зависят от организаций и ПО (см. routeFields.ts).
|
||||||
|
// ПО — свободный текст: в маршрут уходит после паузы в наборе, а не на
|
||||||
|
// каждую букву. Сравниваем по содержимому — массив пересоздаётся на каждый рендер.
|
||||||
|
const softwareForRoute = useDebouncedQuery(data.Software);
|
||||||
|
const fieldValuesKey = JSON.stringify(routeFieldValues(data, softwareForRoute));
|
||||||
|
const fieldValues = useMemo(() => JSON.parse(fieldValuesKey) as IResolveFieldValue[], [fieldValuesKey]);
|
||||||
|
// Отдел и поля условий влияют на резолв маршрута — их смена у НОВОЙ заявки перепланирует матрицу.
|
||||||
|
const matrixKey = `${userEmail}-${editId ?? 'new'}-${data.DepartmentId}-${fieldValuesKey}`;
|
||||||
|
|
||||||
// У новой заявки маршрут ПЛАНИРУЕТСЯ (resolve по внешнему API), у открытой на
|
// У новой заявки маршрут ПЛАНИРУЕТСЯ (resolve по внешнему API), у открытой на
|
||||||
// редактирование — читается из уже записанных строк: их могли поправить
|
// редактирование — читается из уже записанных строк: их могли поправить
|
||||||
// вручную при первом сохранении, и планирование затёрло бы эти правки.
|
// вручную при первом сохранении, и планирование затёрло бы эти правки.
|
||||||
@@ -174,13 +186,12 @@ const WorkplaceSetupForm: React.FC<IRequestFormProps> = ({
|
|||||||
? approval
|
? approval
|
||||||
.getMatrixForRequest(editId)
|
.getMatrixForRequest(editId)
|
||||||
.then((rows) => rows.filter((r) => r.phase !== APPROVAL_PHASE.execution))
|
.then((rows) => rows.filter((r) => r.phase !== APPROVAL_PHASE.execution))
|
||||||
: getPlannedMatrix(context, requestTypeId as number, userEmail, approval, 'Approval', data.DepartmentId),
|
: getPlannedMatrix(context, requestTypeId as number, userEmail, approval, 'Approval', data.DepartmentId, fieldValues),
|
||||||
[context, userEmail, approval, editId, data.DepartmentId, requestTypeId]
|
[context, userEmail, approval, editId, data.DepartmentId, requestTypeId, fieldValues]
|
||||||
);
|
);
|
||||||
const matrix = useMatrixEditor(
|
const matrix = useMatrixEditor(
|
||||||
loadMatrix,
|
loadMatrix,
|
||||||
// Отдел влияет на резолв маршрута — смена отдела у НОВОЙ заявки должна перепланировать матрицу.
|
matrixKey,
|
||||||
`${userEmail}-${editId ?? 'new'}-${data.DepartmentId}`,
|
|
||||||
!readOnly,
|
!readOnly,
|
||||||
!!editId || !!requestTypeId,
|
!!editId || !!requestTypeId,
|
||||||
(login) => approval.getJobTitle(login)
|
(login) => approval.getJobTitle(login)
|
||||||
@@ -193,12 +204,12 @@ const WorkplaceSetupForm: React.FC<IRequestFormProps> = ({
|
|||||||
? approval
|
? approval
|
||||||
.getMatrixForRequest(editId)
|
.getMatrixForRequest(editId)
|
||||||
.then((rows) => rows.filter((r) => r.phase === APPROVAL_PHASE.execution))
|
.then((rows) => rows.filter((r) => r.phase === APPROVAL_PHASE.execution))
|
||||||
: getPlannedMatrix(context, requestTypeId as number, userEmail, approval, 'Execution', data.DepartmentId),
|
: getPlannedMatrix(context, requestTypeId as number, userEmail, approval, 'Execution', data.DepartmentId, fieldValues),
|
||||||
[context, userEmail, approval, editId, data.DepartmentId, requestTypeId]
|
[context, userEmail, approval, editId, data.DepartmentId, requestTypeId, fieldValues]
|
||||||
);
|
);
|
||||||
const executors = useMatrixEditor(
|
const executors = useMatrixEditor(
|
||||||
loadExecutors,
|
loadExecutors,
|
||||||
`${userEmail}-${editId ?? 'new'}-${data.DepartmentId}`,
|
matrixKey,
|
||||||
canEditExecutors(context, readOnly),
|
canEditExecutors(context, readOnly),
|
||||||
!!editId || !!requestTypeId,
|
!!editId || !!requestTypeId,
|
||||||
(login) => approval.getJobTitle(login)
|
(login) => approval.getJobTitle(login)
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { IResolveFieldValue } from '../../shared/approval';
|
||||||
|
import { COMPANIES_JSON_FIELD, IFormData } from './model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Значения полей заявки для условных шагов маршрута (fieldValues при resolve).
|
||||||
|
* В админке approval-route условия заданы по internalName колонок:
|
||||||
|
* «WorkplaceCompaniesJson содержит АСТЕЛ-К», «Organization содержит …»,
|
||||||
|
* «Software содержит AutoCAD».
|
||||||
|
*
|
||||||
|
* Организации — одной строкой, имена через пробел: бэкенд принимает только
|
||||||
|
* строку (массив → 400), а «содержит» ищет подстроку. Тот же формат, что в
|
||||||
|
* заявках на приём и подбор (см. RecruitingHireForm).
|
||||||
|
*
|
||||||
|
* Маршрут планируется при подаче, поэтому условие по Software сработает,
|
||||||
|
* только если «Необходимое ПО» указал сам инициатор (руководитель заполняет
|
||||||
|
* его позже, на своём шаге).
|
||||||
|
*/
|
||||||
|
export function routeFieldValues(
|
||||||
|
data: Pick<IFormData, 'Companies'>,
|
||||||
|
software: string
|
||||||
|
): IResolveFieldValue[] {
|
||||||
|
const fieldValues: IResolveFieldValue[] = [];
|
||||||
|
const companyNames = data.Companies.map((c) => c.Name).sort().join(' ');
|
||||||
|
if (companyNames) {
|
||||||
|
fieldValues.push({ fieldName: COMPANIES_JSON_FIELD, value: companyNames });
|
||||||
|
fieldValues.push({ fieldName: 'Organization', value: companyNames });
|
||||||
|
}
|
||||||
|
const softwareText = software.trim();
|
||||||
|
if (softwareText) {
|
||||||
|
fieldValues.push({ fieldName: 'Software', value: softwareText });
|
||||||
|
}
|
||||||
|
return fieldValues;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user