feat: тип приёма «Вместо переведенного сотрудника»
This commit is contained in:
@@ -22,7 +22,8 @@
|
|||||||
`RecruitingAgency`; при включении показываются «Название компании» (`AgencyName`)
|
`RecruitingAgency`; при включении показываются «Название компании» (`AgencyName`)
|
||||||
и «Условия» (`AgencyTerms`), при выключении оба поля очищаются.
|
и «Условия» (`AgencyTerms`), при выключении оба поля очищаются.
|
||||||
- **Условное поле «Взамен кого» (ReplacedEmployee)** — показывается только когда
|
- **Условное поле «Взамен кого» (ReplacedEmployee)** — показывается только когда
|
||||||
тип приёма = замена уволенного (см. `HIRE_TYPE_REPLACEMENT` в модели).
|
тип приёма = вместо уволенного / вместо переведенного / декрет
|
||||||
|
(см. `REPLACED_EMPLOYEE_LABELS` в `sections/ApplicationSection.tsx`).
|
||||||
- Секция **СИЗ** (рост, размеры одежды/обуви).
|
- Секция **СИЗ** (рост, размеры одежды/обуви).
|
||||||
- **Является источником для «Организация рабочего места»** — из просмотра этой
|
- **Является источником для «Организация рабочего места»** — из просмотра этой
|
||||||
заявки кнопка «Организация рабочего места на основе этой» открывает форму
|
заявки кнопка «Организация рабочего места на основе этой» открывает форму
|
||||||
|
|||||||
@@ -9,13 +9,20 @@ describe('hireTypeFromSelection', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('«Замена уволенного сотрудника» → «Вместо уволенного» + ФИО', () => {
|
it('«Замена уволенного сотрудника» → «Вместо уволенного сотрудника» + ФИО', () => {
|
||||||
expect(hireTypeFromSelection('Замена уволенного сотрудника', 'Петров Пётр Петрович')).toEqual({
|
expect(hireTypeFromSelection('Замена уволенного сотрудника', 'Петров Пётр Петрович')).toEqual({
|
||||||
hireType: 'Вместо уволенного',
|
hireType: 'Вместо уволенного сотрудника',
|
||||||
replacedEmployee: 'Петров Пётр Петрович'
|
replacedEmployee: 'Петров Пётр Петрович'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('«Перевод сотрудника» → «Вместо переведенного сотрудника» + ФИО', () => {
|
||||||
|
expect(hireTypeFromSelection('Перевод сотрудника', 'Сидоров Сидор Сидорович')).toEqual({
|
||||||
|
hireType: 'Вместо переведенного сотрудника',
|
||||||
|
replacedEmployee: 'Сидоров Сидор Сидорович'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('«Новая штатная единица» → «Новый сотрудник» без ФИО', () => {
|
it('«Новая штатная единица» → «Новый сотрудник» без ФИО', () => {
|
||||||
expect(hireTypeFromSelection('Новая штатная единица', 'что-то')).toEqual({
|
expect(hireTypeFromSelection('Новая штатная единица', 'что-то')).toEqual({
|
||||||
hireType: 'Новый сотрудник',
|
hireType: 'Новый сотрудник',
|
||||||
@@ -23,15 +30,14 @@ describe('hireTypeFromSelection', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('перевод, «Другое» и пустая причина — без подстановки', () => {
|
it('«Другое» и пустая причина — без подстановки', () => {
|
||||||
expect(hireTypeFromSelection('Перевод сотрудника', 'Сидоров')).toBeUndefined();
|
|
||||||
expect(hireTypeFromSelection('Другое', 'уточнение')).toBeUndefined();
|
expect(hireTypeFromSelection('Другое', 'уточнение')).toBeUndefined();
|
||||||
expect(hireTypeFromSelection('', '')).toBeUndefined();
|
expect(hireTypeFromSelection('', '')).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('подставляемый тип всегда есть среди вариантов «Тип приёма»', () => {
|
it('подставляемый тип всегда есть среди вариантов «Тип приёма»', () => {
|
||||||
const allowed = HIRE_TYPE_OPTIONS.map((o) => o.value);
|
const allowed = HIRE_TYPE_OPTIONS.map((o) => o.value);
|
||||||
['Декрет', 'Замена уволенного сотрудника', 'Новая штатная единица'].forEach((reason) => {
|
['Декрет', 'Замена уволенного сотрудника', 'Перевод сотрудника', 'Новая штатная единица'].forEach((reason) => {
|
||||||
expect(allowed).toContain(hireTypeFromSelection(reason, '')?.hireType);
|
expect(allowed).toContain(hireTypeFromSelection(reason, '')?.hireType);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,23 +1,25 @@
|
|||||||
import {
|
import {
|
||||||
OPEN_REASON_REPLACE,
|
OPEN_REASON_REPLACE,
|
||||||
|
OPEN_REASON_TRANSFER,
|
||||||
OPEN_REASON_NEW,
|
OPEN_REASON_NEW,
|
||||||
OPEN_REASON_MATERNITY
|
OPEN_REASON_MATERNITY
|
||||||
} from '../RecruitingSelection/model';
|
} from '../RecruitingSelection/model';
|
||||||
import { HIRE_TYPE_NEW, HIRE_TYPE_REPLACEMENT, HIRE_TYPE_MATERNITY } from './model';
|
import { HIRE_TYPE_NEW, HIRE_TYPE_REPLACEMENT, HIRE_TYPE_TRANSFER, HIRE_TYPE_MATERNITY } from './model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Причина открытия вакансии (заявка на подбор) → тип приёма (заявка на приём).
|
* Причина открытия вакансии (заявка на подбор) → тип приёма (заявка на приём).
|
||||||
* «Перевод сотрудника» и «Другое» однозначного соответствия не имеют — их тут
|
* «Другое» однозначного соответствия не имеет — его тут нет, тип приёма в таком
|
||||||
* нет, тип приёма в таком случае выбирает инициатор сам.
|
* случае выбирает инициатор сам.
|
||||||
*/
|
*/
|
||||||
const REASON_TO_HIRE_TYPE: Record<string, string> = {
|
const REASON_TO_HIRE_TYPE: Record<string, string> = {
|
||||||
[OPEN_REASON_REPLACE]: HIRE_TYPE_REPLACEMENT,
|
[OPEN_REASON_REPLACE]: HIRE_TYPE_REPLACEMENT,
|
||||||
|
[OPEN_REASON_TRANSFER]: HIRE_TYPE_TRANSFER,
|
||||||
[OPEN_REASON_MATERNITY]: HIRE_TYPE_MATERNITY,
|
[OPEN_REASON_MATERNITY]: HIRE_TYPE_MATERNITY,
|
||||||
[OPEN_REASON_NEW]: HIRE_TYPE_NEW
|
[OPEN_REASON_NEW]: HIRE_TYPE_NEW
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Типы приёма, для которых переносим ФИО замещаемого сотрудника. */
|
/** Типы приёма, для которых переносим ФИО замещаемого сотрудника. */
|
||||||
const HIRE_TYPES_WITH_REPLACED_EMPLOYEE = [HIRE_TYPE_REPLACEMENT, HIRE_TYPE_MATERNITY];
|
const HIRE_TYPES_WITH_REPLACED_EMPLOYEE = [HIRE_TYPE_REPLACEMENT, HIRE_TYPE_TRANSFER, HIRE_TYPE_MATERNITY];
|
||||||
|
|
||||||
export interface IHireTypePrefill {
|
export interface IHireTypePrefill {
|
||||||
hireType: string;
|
hireType: string;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { getSP } from '../../shared/pnp/pnpjs';
|
|||||||
import { ICompany } from '../../shared/dictionary';
|
import { ICompany } from '../../shared/dictionary';
|
||||||
import { dataListTitle } from '../../shared/listTitles';
|
import { dataListTitle } from '../../shared/listTitles';
|
||||||
import { IFieldChange, parseFieldChanges } from '../../shared/fieldChanges/fieldChanges';
|
import { IFieldChange, parseFieldChanges } from '../../shared/fieldChanges/fieldChanges';
|
||||||
import { FORM_ID, IFormData, EMPTY_DATA, ICompanyShare } from './model';
|
import { FORM_ID, IFormData, EMPTY_DATA, ICompanyShare, LEGACY_HIRE_TYPES } from './model';
|
||||||
import { APPROVER_CHANGES_FIELD } from './changeTracking';
|
import { APPROVER_CHANGES_FIELD } from './changeTracking';
|
||||||
|
|
||||||
/** Безопасный разбор JSON-массива из Note-колонки (пустой при ошибке/пустом). */
|
/** Безопасный разбор JSON-массива из Note-колонки (пустой при ошибке/пустом). */
|
||||||
@@ -81,6 +81,7 @@ export async function loadHireRequest(itemId: number, listId?: string): Promise<
|
|||||||
writable[key] = String(value);
|
writable[key] = String(value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
data.HireType = LEGACY_HIRE_TYPES[data.HireType] || data.HireType;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data,
|
data,
|
||||||
|
|||||||
@@ -127,7 +127,10 @@ export const HIRE_ON_ARRIVAL_LABEL = 'По приезду на объект';
|
|||||||
export const HIRE_TYPE_NEW = 'Новый сотрудник';
|
export const HIRE_TYPE_NEW = 'Новый сотрудник';
|
||||||
|
|
||||||
/** Значение «Тип приёма», при котором показывается поле «Взамен кого». */
|
/** Значение «Тип приёма», при котором показывается поле «Взамен кого». */
|
||||||
export const HIRE_TYPE_REPLACEMENT = 'Вместо уволенного';
|
export const HIRE_TYPE_REPLACEMENT = 'Вместо уволенного сотрудника';
|
||||||
|
|
||||||
|
/** Приём на место сотрудника, переведённого на другую должность, — тоже спрашиваем «Взамен кого». */
|
||||||
|
export const HIRE_TYPE_TRANSFER = 'Вместо переведенного сотрудника';
|
||||||
|
|
||||||
/** Приём на время декретного отпуска сотрудника — тоже спрашиваем «Взамен кого». */
|
/** Приём на время декретного отпуска сотрудника — тоже спрашиваем «Взамен кого». */
|
||||||
export const HIRE_TYPE_MATERNITY = 'Декрет';
|
export const HIRE_TYPE_MATERNITY = 'Декрет';
|
||||||
@@ -136,9 +139,18 @@ export const HIRE_TYPE_MATERNITY = 'Декрет';
|
|||||||
export const HIRE_TYPE_OPTIONS: ISelectOption[] = [
|
export const HIRE_TYPE_OPTIONS: ISelectOption[] = [
|
||||||
{ value: HIRE_TYPE_NEW, label: HIRE_TYPE_NEW },
|
{ value: HIRE_TYPE_NEW, label: HIRE_TYPE_NEW },
|
||||||
{ value: HIRE_TYPE_REPLACEMENT, label: HIRE_TYPE_REPLACEMENT },
|
{ value: HIRE_TYPE_REPLACEMENT, label: HIRE_TYPE_REPLACEMENT },
|
||||||
|
{ value: HIRE_TYPE_TRANSFER, label: HIRE_TYPE_TRANSFER },
|
||||||
{ value: HIRE_TYPE_MATERNITY, label: HIRE_TYPE_MATERNITY }
|
{ value: HIRE_TYPE_MATERNITY, label: HIRE_TYPE_MATERNITY }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Прежние значения «Тип приёма» → текущие. В уже поданных заявках SP хранит
|
||||||
|
* старый текст; без замены при загрузке поле 1.5 в них показывалось бы пустым.
|
||||||
|
*/
|
||||||
|
export const LEGACY_HIRE_TYPES: Record<string, string> = {
|
||||||
|
'Вместо уволенного': HIRE_TYPE_REPLACEMENT
|
||||||
|
};
|
||||||
|
|
||||||
/** Значение-триггер «Другое»: при нём показываем поле ручного ввода. */
|
/** Значение-триггер «Другое»: при нём показываем поле ручного ввода. */
|
||||||
export const OTHER_VALUE = 'Другое';
|
export const OTHER_VALUE = 'Другое';
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
{ "internalName": "CompanySharesJson", "title": "Распределение ЗП по компаниям (JSON)", "type": "Note" },
|
{ "internalName": "CompanySharesJson", "title": "Распределение ЗП по компаниям (JSON)", "type": "Note" },
|
||||||
|
|
||||||
{ "internalName": "Phone", "title": "Телефон", "type": "Text" },
|
{ "internalName": "Phone", "title": "Телефон", "type": "Text" },
|
||||||
{ "internalName": "HireType", "title": "Тип приёма", "type": "Choice", "choices": ["Новый сотрудник", "Вместо уволенного", "Декрет"] },
|
{ "internalName": "HireType", "title": "Тип приёма", "type": "Choice", "choices": ["Новый сотрудник", "Вместо уволенного сотрудника", "Вместо переведенного сотрудника", "Декрет"] },
|
||||||
{ "internalName": "HireReplacedEmployee", "title": "Взамен кого (Ф.И.О. уволенного)", "type": "Text" },
|
{ "internalName": "HireReplacedEmployee", "title": "Взамен кого (Ф.И.О. уволенного)", "type": "Text" },
|
||||||
|
|
||||||
{ "internalName": "Project", "title": "Проект", "type": "Text" },
|
{ "internalName": "Project", "title": "Проект", "type": "Text" },
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { CollapseSection, FormField, TextInput, PhoneInput, Select } from '../../../shared/ui';
|
import { CollapseSection, FormField, TextInput, PhoneInput, Select } from '../../../shared/ui';
|
||||||
import { CompanyPickerMulti, ProjectPicker, ICompany } from '../../../shared/dictionary';
|
import { CompanyPickerMulti, ProjectPicker, ICompany } from '../../../shared/dictionary';
|
||||||
import { ISectionProps, HIRE_TYPE_OPTIONS, HIRE_TYPE_REPLACEMENT, HIRE_TYPE_MATERNITY } from '../model';
|
import { ISectionProps, HIRE_TYPE_OPTIONS, HIRE_TYPE_REPLACEMENT, HIRE_TYPE_TRANSFER, HIRE_TYPE_MATERNITY } from '../model';
|
||||||
import { SelectionRequestField } from './SelectionRequestField';
|
import { SelectionRequestField } from './SelectionRequestField';
|
||||||
import { CompanySharesField } from './CompanySharesField';
|
import { CompanySharesField } from './CompanySharesField';
|
||||||
|
|
||||||
/** Подпись поля «Взамен кого» — уточняем, чьё ФИО вписывать, по типу приёма. */
|
/** Подпись поля «Взамен кого» — уточняем, чьё ФИО вписывать, по типу приёма. */
|
||||||
const REPLACED_EMPLOYEE_LABELS: Record<string, string> = {
|
const REPLACED_EMPLOYEE_LABELS: Record<string, string> = {
|
||||||
[HIRE_TYPE_REPLACEMENT]: 'Взамен кого (Ф.И.О. уволенного, полностью, пример: Иванов Иван Иванович)',
|
[HIRE_TYPE_REPLACEMENT]: 'Взамен кого (Ф.И.О. уволенного, полностью, пример: Иванов Иван Иванович)',
|
||||||
|
[HIRE_TYPE_TRANSFER]: 'Взамен кого (Ф.И.О. переведенного сотрудника, полностью, пример: Иванов Иван Иванович)',
|
||||||
[HIRE_TYPE_MATERNITY]: 'Взамен кого (Ф.И.О. сотрудника в декрете, полностью, пример: Иванова Анна Ивановна)'
|
[HIRE_TYPE_MATERNITY]: 'Взамен кого (Ф.И.О. сотрудника в декрете, полностью, пример: Иванова Анна Ивановна)'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user