refactor(RecruitingSelection): OpenReason -> VacancyOpenReason (обход коллизии Search)

Колонка OpenReason/OpenReasonDetails называлась одинаково с полями в других
списках сайта, из-за чего Search индексировал managed property только у ОДНОГО
из них — не у этого (см. sp-write props/field, разбирались 2026-08-28/29 в
tnsu-approval-route). Переименование снимает коллизию: VacancyOpenReasonOWSMTXT/
VacancyOpenReasonDetailsOWSTEXT теперь индексируются нормально, проверено.

Данные из старых колонок на живом сайте уже перенесены отдельным скриптом
(migrate-openreason.sh, разово, вне репозитория). provisioning.json обновлён на
новые internalName — он только добавляет колонки, никогда не удаляет, так что
старые OpenReason/OpenReasonDetails на сайте провижининг сам не уберёт.

load.ts/submit.ts менять не пришлось — оба читают/пишут поля по ключам
IFormData обобщённо.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
gorbenko.pavel
2026-08-28 16:18:48 +05:00
parent 0701736e23
commit bd7d83b9ff
3 changed files with 24 additions and 17 deletions
@@ -18,8 +18,15 @@ export interface IFormData {
Responsible: string; Responsible: string;
SubmitDate: string; SubmitDate: string;
ClosingDeadline: string; ClosingDeadline: string;
OpenReason: string; /**
OpenReasonDetails: string; * Префикс Vacancy — не для читаемости, а обход коллизии managed properties:
* колонка называлась просто OpenReason, и Search индексировал её только у
* ОДНОГО из списков сайта с таким internal name (см. sp-write props/field в
* tools). Переименовали и перенесли данные скриптом (2026-08-29) — трогать
* имя обратно нельзя, коллизия вернётся.
*/
VacancyOpenReason: string;
VacancyOpenReasonDetails: string;
Companies: ICompany[]; Companies: ICompany[];
ObjectProject: string; ObjectProject: string;
ObjectProjectId: string; ObjectProjectId: string;
@@ -92,8 +99,8 @@ export const EMPTY_DATA: IFormData = {
Responsible: '', Responsible: '',
SubmitDate: '', SubmitDate: '',
ClosingDeadline: '', ClosingDeadline: '',
OpenReason: '', VacancyOpenReason: '',
OpenReasonDetails: '', VacancyOpenReasonDetails: '',
Companies: [], Companies: [],
ObjectProject: '', ObjectProject: '',
ObjectProjectId: '', ObjectProjectId: '',
@@ -149,7 +156,7 @@ export const OPEN_REASON_REPLACE = 'Замена уволенного сотру
export const OPEN_REASON_TRANSFER = 'Перевод сотрудника'; export const OPEN_REASON_TRANSFER = 'Перевод сотрудника';
export const OPEN_REASON_NEW = 'Новая штатная единица'; export const OPEN_REASON_NEW = 'Новая штатная единица';
/** Варианты «Причина открытия вакансии» — совпадают с choices колонки OpenReason. */ /** Варианты «Причина открытия вакансии» — совпадают с choices колонки VacancyOpenReason. */
export const OPEN_REASON_OPTIONS: ISelectOption[] = [ export const OPEN_REASON_OPTIONS: ISelectOption[] = [
{ value: OPEN_REASON_REPLACE, label: OPEN_REASON_REPLACE }, { value: OPEN_REASON_REPLACE, label: OPEN_REASON_REPLACE },
{ value: OPEN_REASON_TRANSFER, label: OPEN_REASON_TRANSFER }, { value: OPEN_REASON_TRANSFER, label: OPEN_REASON_TRANSFER },
@@ -5,8 +5,8 @@
{ "internalName": "RequestStatus", "title": "Статус", "type": "Choice", "choices": ["Черновик", "На согласовании", "Согласовано", "Отклонено", "Возвращена на доработку", "Выполнение", "Закрыта"] }, { "internalName": "RequestStatus", "title": "Статус", "type": "Choice", "choices": ["Черновик", "На согласовании", "Согласовано", "Отклонено", "Возвращена на доработку", "Выполнение", "Закрыта"] },
{ "internalName": "Responsible", "title": "Ответственный за подачу заявки", "type": "User", "userSelectionMode": "PeopleOnly", "required": true }, { "internalName": "Responsible", "title": "Ответственный за подачу заявки", "type": "User", "userSelectionMode": "PeopleOnly", "required": true },
{ "internalName": "SubmitDate", "title": "Дата подачи заявки", "type": "DateTime", "dateOnly": true }, { "internalName": "SubmitDate", "title": "Дата подачи заявки", "type": "DateTime", "dateOnly": true },
{ "internalName": "OpenReason", "title": "Причина открытия вакансии", "type": "Choice", "choices": ["Замена уволенного сотрудника", "Перевод сотрудника", "Новая штатная единица", "Другое"] }, { "internalName": "VacancyOpenReason", "title": "Причина открытия вакансии", "type": "Choice", "choices": ["Замена уволенного сотрудника", "Перевод сотрудника", "Новая штатная единица", "Другое"] },
{ "internalName": "OpenReasonDetails", "title": "Причина открытия — ФИО / уточнение", "type": "Text" }, { "internalName": "VacancyOpenReasonDetails", "title": "Причина открытия — ФИО / уточнение", "type": "Text" },
{ "internalName": "CompaniesJson", "title": "Компании (JSON)", "type": "Note" }, { "internalName": "CompaniesJson", "title": "Компании (JSON)", "type": "Note" },
{ "internalName": "ObjectProject", "title": "Объект/Проект", "type": "Text" }, { "internalName": "ObjectProject", "title": "Объект/Проект", "type": "Text" },
{ "internalName": "ObjectProjectId", "title": "Объект/Проект — Id", "type": "Text" }, { "internalName": "ObjectProjectId", "title": "Объект/Проект — Id", "type": "Text" },
@@ -11,7 +11,7 @@ import {
} from '../model'; } from '../model';
export const ApplicationSection: React.FC<ISectionProps> = ({ data, set, context, onResponsibleChange }) => { export const ApplicationSection: React.FC<ISectionProps> = ({ data, set, context, onResponsibleChange }) => {
const reason = data.OpenReason; const reason = data.VacancyOpenReason;
const showReasonDetails = reason !== '' && reason !== OPEN_REASON_NEW; const showReasonDetails = reason !== '' && reason !== OPEN_REASON_NEW;
const reasonDetailsLabel = const reasonDetailsLabel =
reason === OPEN_REASON_REPLACE || reason === OPEN_REASON_TRANSFER ? 'ФИО сотрудника' : 'Уточните причину'; reason === OPEN_REASON_REPLACE || reason === OPEN_REASON_TRANSFER ? 'ФИО сотрудника' : 'Уточните причину';
@@ -45,24 +45,24 @@ export const ApplicationSection: React.FC<ISectionProps> = ({ data, set, context
onChange={(v) => set('ClosingDeadline', v)} onChange={(v) => set('ClosingDeadline', v)}
/> />
</FormField> </FormField>
<FormField label="1.5 Причина открытия вакансии" htmlFor="OpenReason"> <FormField label="1.5 Причина открытия вакансии" htmlFor="VacancyOpenReason">
<Select <Select
id="OpenReason" id="VacancyOpenReason"
value={data.OpenReason} value={data.VacancyOpenReason}
onChange={(v) => { onChange={(v) => {
set('OpenReason', v); set('VacancyOpenReason', v);
if (v === '' || v === OPEN_REASON_NEW) set('OpenReasonDetails', ''); if (v === '' || v === OPEN_REASON_NEW) set('VacancyOpenReasonDetails', '');
}} }}
options={OPEN_REASON_OPTIONS} options={OPEN_REASON_OPTIONS}
placeholder="— выберите —" placeholder="— выберите —"
/> />
</FormField> </FormField>
{showReasonDetails && ( {showReasonDetails && (
<FormField label={reasonDetailsLabel} htmlFor="OpenReasonDetails"> <FormField label={reasonDetailsLabel} htmlFor="VacancyOpenReasonDetails">
<TextInput <TextInput
id="OpenReasonDetails" id="VacancyOpenReasonDetails"
value={data.OpenReasonDetails} value={data.VacancyOpenReasonDetails}
onChange={(v) => set('OpenReasonDetails', v)} onChange={(v) => set('VacancyOpenReasonDetails', v)}
/> />
</FormField> </FormField>
)} )}