feat: оформление приёма прямо из согласованной заявки на подбор

Просили создавать заявку на приём из самого подбора, а не искать его в
поле 1.1. Под вложениями согласованного подбора — «+ Оформить приём по этой
заявке» со счётчиком «занято X из Y» (и предупреждением, если вакансии
заняты). Новая заявка на приём сразу связана с подбором и заполнена из
него: логика вынесена в selectionPrefill и общая с полем 1.1. Вместе с
rpsource в адресе передаётся партиция подбора (rplist): Id в партициях
повторяются. Приёмы по подбору грузятся один раз на оба блока (useLinkedHires).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Тимур Городецкий
2026-10-09 14:12:33 +05:00
parent 79963e4035
commit af93ae57f4
14 changed files with 330 additions and 84 deletions
@@ -90,6 +90,16 @@ describe('parseRoute', () => {
});
});
it('rplist при rpsource — партиция исходной заявки', () => {
expect(parseRoute('?rptype=recruiting-hire&rpsource=79&rplist=%2Fsites%2Frequests%2FLists%2Fsel1')).toEqual({
mode: 'create',
nav: 'new',
formKey: 'recruiting-hire',
sourceId: 79,
listId: '/sites/requests/Lists/sel1',
});
});
it('создание производной заявки всегда открывается в разделе «Новая заявка»', () => {
expect(parseRoute('?rptype=workplace&rpsource=15&rpnav=own').nav).toBe('new');
});
@@ -567,6 +577,17 @@ describe('navigate', () => {
});
});
it('round-trip для производной заявки с партицией исходной', () => {
navigate({ mode: 'create', nav: 'new', formKey: 'recruiting-hire', sourceId: 79, listId: '/sites/requests/Lists/sel1' });
expect(parseRoute(window.location.search)).toEqual({
mode: 'create',
nav: 'new',
formKey: 'recruiting-hire',
sourceId: 79,
listId: '/sites/requests/Lists/sel1',
});
});
it('возврат к подаче заявки убирает параметры открытой заявки из адреса', () => {
navigate({ mode: 'approve', nav: 'new', formKey: 'hire', itemId: 42 });
navigate({ mode: 'submit', nav: 'new' });
+7 -3
View File
@@ -427,9 +427,10 @@ export function parseRoute(search: string = window.location.search): IRoute {
if (mode === 'edit' && formKey && itemId && !isNaN(itemId)) {
return { mode: 'edit', nav, formKey, itemId, listId, ownTab, ownStatus, allTypeId, page, query };
}
// Создание производной заявки с предзаполнением из исходной.
// Создание производной заявки с предзаполнением из исходной. rplist здесь —
// партиция ИСХОДНОЙ заявки (Id в разных партициях повторяются).
if (formKey && sourceId && !isNaN(sourceId)) {
return { mode: 'create', nav: 'new', formKey, sourceId };
return { mode: 'create', nav: 'new', formKey, sourceId, listId };
}
// Ссылка на пустую новую форму конкретного типа — без предзаполнения
// (клик по плитке внутри портала, либо явная ссылка ?rptype=<форма> без
@@ -485,7 +486,10 @@ function buildQuery(route: IRoute): string {
if (route.listId) params.set('rplist', route.listId);
} else if (route.mode === 'create' && route.formKey) {
params.set('rptype', route.formKey);
if (route.sourceId) params.set('rpsource', String(route.sourceId));
if (route.sourceId) {
params.set('rpsource', String(route.sourceId));
if (route.listId) params.set('rplist', route.listId);
}
}
const query = params.toString();