From 2434ead7543a6f8850ef21629d3178a1b64ae136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D0=B8=D0=BC=D1=83=D1=80=20=D0=93=D0=BE=D1=80=D0=BE?= =?UTF-8?q?=D0=B4=D0=B5=D1=86=D0=BA=D0=B8=D0=B9?= Date: Thu, 29 Oct 2026 15:51:16 +0500 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=BF=D0=BE=D0=BB=D1=8F=20=D0=B2=D0=B8?= =?UTF-8?q?=D0=B4=D0=B0=20=C2=AB=D0=92=D1=80=D0=B5=D0=BC=D0=B5=D0=BD=D0=BD?= =?UTF-8?q?=D1=8B=D0=B9=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B2=D0=BE=D0=B4=C2=BB?= =?UTF-8?q?=20=D0=B2=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B8=20=D1=83=D1=81=D0=BB=D0=BE=D0=B2=D0=B8=D0=B9=20=D0=A2?= =?UTF-8?q?=D0=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Последний из разобранных видов: откуда и куда — проект из справочника и работа текстом, период не дольше 3 месяцев включительно (календарь не даёт выбрать лишнее, при отправке — проверка), основание (производственная необходимость / простой), обоснование и пометка из шаблона ТЗ о сохранении оплаты. Поля разобраны по всем видам, кроме продления срока ТД. Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/forms.md | 2 +- .../forms/ContractChange/README.md | 12 ++- .../byType/ChangeTypeSections.tsx | 4 +- .../TemporaryTransferSection.module.scss | 15 +++ .../TemporaryTransferSection.tsx | 99 +++++++++++++++++++ .../byType/TemporaryTransfer/options.ts | 17 ++++ .../byType/TemporaryTransfer/period.test.ts | 23 +++++ .../byType/TemporaryTransfer/period.ts | 25 +++++ .../ContractChange/byType/submitChecks.ts | 19 ++++ .../forms/ContractChange/load.ts | 24 ++++- .../forms/ContractChange/model.ts | 28 +++++- .../forms/ContractChange/provisioning.json | 13 ++- .../forms/ContractChange/submit.ts | 14 ++- 13 files changed, 283 insertions(+), 12 deletions(-) create mode 100644 src/webparts/requestPortal/forms/ContractChange/byType/TemporaryTransfer/TemporaryTransferSection.module.scss create mode 100644 src/webparts/requestPortal/forms/ContractChange/byType/TemporaryTransfer/TemporaryTransferSection.tsx create mode 100644 src/webparts/requestPortal/forms/ContractChange/byType/TemporaryTransfer/options.ts create mode 100644 src/webparts/requestPortal/forms/ContractChange/byType/TemporaryTransfer/period.test.ts create mode 100644 src/webparts/requestPortal/forms/ContractChange/byType/TemporaryTransfer/period.ts diff --git a/docs/forms.md b/docs/forms.md index 51094be..0dcf6a6 100644 --- a/docs/forms.md +++ b/docs/forms.md @@ -51,7 +51,7 @@ | [`hr-skud-explanation`](../src/webparts/requestPortal/forms/SkudExplanation/README.md) | Объяснительная об отсутствии отметок в СКУД | Отдел кадров | да | нет | да | только «на себя»; дни выбираются кликом в календаре «Мой СКУД» (проходы Hikvision текущего пользователя), сохраняются снимком для согласующего; текст записки собирается автоматически, печать — бланк объяснительной | ⏳ код готов, списки/тип/маршрут не заведены | | [`hr-business-trip`](../src/webparts/requestPortal/forms/BusinessTrip/README.md) | Заявка на командировку | Отдел кадров | да | да | да | можно за другого сотрудника; командирующая организация — выбор из организаций сотрудника; маршрут лентой (точки по Казахстану — город из справочника КАТО на русском и казахском + объект из справочника, за рубежом — страна/город/объект вручную; даты не задним числом, поездка ≤ 40 дней; участки с видом транспорта и временем выезда); суточные (≤ 6 МРП КЗ / ≤ 8 за рубежом) и проживание (ночи сами, ≤ 15 000 ₸ за ночь КЗ) — по точкам; комментарий после итога; задание — список задач; смета: статьи с позициями, привязанными к точкам/участкам (суммой или кол-во × цена — всё вручную), итог с долями и по объектам; обязательство по авансовому отчёту — флажок; печать без шапки адресата | ⏳ код готов, списки/тип/маршрут не заведены | | `hr-transfer` | Перемещение сотрудников | Отдел кадров | — | — | — | — | ⏳ заглушка (плитка есть, форма не сделана) | -| [`hr-contract-change`](../src/webparts/requestPortal/forms/ContractChange/README.md) | Изменение условий трудового договора | Отдел кадров | да | — | да | сотрудник из `Employee/FullBase` (и без учётки M365), снимок в текстовых колонках; маршрут по сотруднику, без учётки — по заявителю; 10 видов изменения (один, данные под несколько); поля по видам — в работе | ⏳ каркас, списки/тип/маршрут не заведены | +| [`hr-contract-change`](../src/webparts/requestPortal/forms/ContractChange/README.md) | Изменение условий трудового договора | Отдел кадров | да | — | да | сотрудник из `Employee/FullBase` (и без учётки M365), снимок в текстовых колонках; маршрут по сотруднику, без учётки — по заявителю; 10 видов изменения (один, данные под несколько), поля по каждому виду по ТЗ кадров (кроме «Продления срока ТД»); инициатор работник/работодатель; подписанные вложения по «Что приложить» | ⏳ код готов (кроме вида 6), списки/тип/маршрут не заведены | | [`wh-service-request`](../src/webparts/requestPortal/forms/ServiceRequest/README.md) | Заявка на услуги | Склад / Снабжение | да | нет | да | маршрут по проекту (руководитель проекта/ПТО); табличные части «Приложения» и «Смета» (JSON-колонки); сумма по смете считается на лету (qty × цена), итог дублируется числовой колонкой для отчётов | ✅ | Легенда: **Согл.** — есть фаза согласования; **Исп.** — есть фаза исполнения; diff --git a/src/webparts/requestPortal/forms/ContractChange/README.md b/src/webparts/requestPortal/forms/ContractChange/README.md index f4fc843..cae760f 100644 --- a/src/webparts/requestPortal/forms/ContractChange/README.md +++ b/src/webparts/requestPortal/forms/ContractChange/README.md @@ -8,10 +8,12 @@ `pageUrl` («hr-contract-change») через `useRequestTypeId` (см. «Формы больше не хардкодят RequestTypeId» в `docs/forms.md`). Тип и маршрут в админке approval-route ещё не заведены. -> **Статус: каркас.** Есть сотрудник и вид изменения; поля под конкретные виды -> добавляются по мере разбора ТЗ кадров. Таблица ТЗ (пример, кто инициирует, что -> приложить, сроки, маршрут А/Б/В/Г…) — общая, в форму из неё попадает только то, -> что явно согласовано. Печатного бланка пока нет. +> **Статус (2026-10-29):** поля разобраны по всем видам, кроме 6 «Продление срока ТД» +> (это автоматический запрос, не обычная заявка — отдельно). ТЗ кадров — файл +> «ТЗ_ст33_маршруты_v2» (листы «Виды изменений ст.33» и «Маршрут»); оно общее, в форму +> из него попадает только то, что явно согласовано. Ещё не сделано: передача вида и +> инициатора в маршрут (`fieldValues`: фин. блок — виды 1, 2, 3, 5, 9; маршрут А/Б — +> по инициатору), печатный бланк, заведение типа и маршрутов в админке. ## Маршрут - Фазы: согласование (+ исполнение, если его заведут в админке — форма поддерживает). @@ -66,7 +68,7 @@ RequestTypeId» в `docs/forms.md`). Тип и маршрут в админке | Изменение режима / графика работы | `ScheduleChange` | по ролям строго по ТЗ. Общее: текущий график + текущее время работы (списки как в подборе/приёме, «Другое» → текст; `OptionWithOtherField`, наборы — `byType/workSchedule.ts`), дата начала, вложение «Новый график» (необязательно). **Работник:** неполный рабочий день (часов) / неполная рабочая неделя (дней) — одно или оба, текст заявления. **Работодатель:** новый режим (вахтовый / сменный / иной + описание), новые график и время работы, причина (специфика объекта / смещение сроков проекта — только из ТЗ), обоснование. Поля другой роли при сохранении очищаются | | Изменение трудовой функции (без смены должности) | `FunctionChange` | ровно по шаблону ТЗ: дата изменения, «В связи с» (свободный текст — списка причин в ТЗ нет), вложение **«Новая должностная инструкция»** — обязательно. Инициатор — только руководитель | | Изменение условий труда по инициативе работодателя | `EmployerInitiative` | причина (из названия вида в ТЗ: экономические / технологические / изменения в организации / сокращение объёма работ + «Другое» со своим текстом); «Что меняется» — флажки а) график работы, б) должностной оклад (можно оба, при отправке — хотя бы один); а) текущий → новый график + дата; б) **один новый оклад + доля постоянной части в %** (по умолчанию 75 из ТЗ, 0–100, можно дробную), переменная доля = остаток до 100 %, суммы обеих частей в ₸ считаются сами (`salaryParts.ts`, превысить 100 % нельзя; в SP пишутся при сохранении) + дата; даты **не раньше +15 дней** (уведомление по ТЗ: блок в календаре + проверка при отправке); обоснование — **текстом ИЛИ документом**, одно из двух обязательно при отправке | -| Остальные 1 | — | ещё не разобран с кадрами | +| Временный перевод при производственной необходимости / простое | `TemporaryTransfer` | откуда и куда — проект из справочника + работа текстом; дата начала / окончания — **не дольше 3 месяцев** (по ТЗ «до 3 мес. в календарном году»; включительно: с 01.01 по 31.03, `period.ts`; сумму за год проверяет HR-директор); основание (производственная необходимость / простой), обоснование; пометка из шаблона ТЗ «Оплата — не ниже средней заработной платы по прежней работе». Инициатор — только руководитель | Обязательное по виду при отправке (инициатор, документы, принимающий руководитель, новая организация) — одна функция `byType/submitChecks.ts`; черновик сохраняется без них. diff --git a/src/webparts/requestPortal/forms/ContractChange/byType/ChangeTypeSections.tsx b/src/webparts/requestPortal/forms/ContractChange/byType/ChangeTypeSections.tsx index 748c817..a137888 100644 --- a/src/webparts/requestPortal/forms/ContractChange/byType/ChangeTypeSections.tsx +++ b/src/webparts/requestPortal/forms/ContractChange/byType/ChangeTypeSections.tsx @@ -9,6 +9,7 @@ import { WorkplaceChangeSection } from './WorkplaceChange/WorkplaceChangeSection import { ScheduleChangeSection } from './ScheduleChange/ScheduleChangeSection'; import { FunctionChangeSection } from './FunctionChange/FunctionChangeSection'; import { EmployerInitiativeSection } from './EmployerInitiative/EmployerInitiativeSection'; +import { TemporaryTransferSection } from './TemporaryTransfer/TemporaryTransferSection'; import styles from './ChangeTypeSections.module.scss'; /** @@ -24,7 +25,8 @@ const SECTION_BY_TYPE: Partial>> = { 'workplace-change': WorkplaceChangeSection, 'schedule-change': ScheduleChangeSection, 'function-change': FunctionChangeSection, - 'employer-initiative': EmployerInitiativeSection + 'employer-initiative': EmployerInitiativeSection, + 'temporary-transfer': TemporaryTransferSection }; /** diff --git a/src/webparts/requestPortal/forms/ContractChange/byType/TemporaryTransfer/TemporaryTransferSection.module.scss b/src/webparts/requestPortal/forms/ContractChange/byType/TemporaryTransfer/TemporaryTransferSection.module.scss new file mode 100644 index 0000000..566d188 --- /dev/null +++ b/src/webparts/requestPortal/forms/ContractChange/byType/TemporaryTransfer/TemporaryTransferSection.module.scss @@ -0,0 +1,15 @@ +@import '../../../../../../styles/design-tokens'; + +// Пояснение под полем (ограничение периода). +.hint { + margin-top: $sp-1; + font-size: $fs-label; + color: $gray-500; +} + +// Гарантия по оплате из шаблона ТЗ — на всю ширину сетки, приглушённо, как пометка. +.payNote { + grid-column: 1 / -1; + font-size: $fs-sm; + color: $gray-500; +} diff --git a/src/webparts/requestPortal/forms/ContractChange/byType/TemporaryTransfer/TemporaryTransferSection.tsx b/src/webparts/requestPortal/forms/ContractChange/byType/TemporaryTransfer/TemporaryTransferSection.tsx new file mode 100644 index 0000000..bdb1e55 --- /dev/null +++ b/src/webparts/requestPortal/forms/ContractChange/byType/TemporaryTransfer/TemporaryTransferSection.tsx @@ -0,0 +1,99 @@ +import * as React from 'react'; +import { FormGrid, FormField, TextInput, TextArea, Select } from '../../../../shared/ui'; +import { ProjectPicker } from '../../../../shared/dictionary'; +import { ISectionProps } from '../../model'; +import { TEMPORARY_TRANSFER_REASONS, TEMPORARY_TRANSFER_PAY_NOTE, TEMPORARY_TRANSFER_PERIOD_HINT } from './options'; +import { maxTransferEndDate } from './period'; +import styles from './TemporaryTransferSection.module.scss'; + +const PROJECT_PLACEHOLDER = 'Начните вводить название или код проекта…'; + +/** + * Поля вида «Временный перевод при производственной необходимости / простое» — по + * шаблону ТЗ: «прошу временно перевести работника с ___ (объект / работа) на ___ + * с … по … в связи с ___ (производственная необходимость / простой). Оплата — не + * ниже средней заработной платы по прежней работе». Откуда/куда — проект из + * справочника + работа текстом; период не длиннее 3 месяцев (period.ts). + * Инициатор — только руководитель. + * + * Поля — в FormGrid без заголовка: вид уже выбран выше, заголовок его только дублировал. + */ +export const TemporaryTransferSection: React.FC = ({ data, set, context }) => ( + + + { + set('TemporaryTransferFromProject', name); + set('TemporaryTransferFromProjectId', id); + }} + placeholder={PROJECT_PLACEHOLDER} + /> + + + set('TemporaryTransferFromWork', v)} + /> + + + { + set('TemporaryTransferToProject', name); + set('TemporaryTransferToProjectId', id); + }} + placeholder={PROJECT_PLACEHOLDER} + /> + + + set('TemporaryTransferToWork', v)} + /> + + + set('TemporaryTransferStartDate', v)} + /> + + + {/* Не раньше начала и не дольше 3 месяцев — календарь не даст выбрать лишнее. */} + set('TemporaryTransferEndDate', v)} + min={data.TemporaryTransferStartDate || undefined} + max={maxTransferEndDate(data.TemporaryTransferStartDate)} + /> +
{TEMPORARY_TRANSFER_PERIOD_HINT}
+
+ +