Files
request-portal/docs/forms.md
T
gorbenko.pavel 2d2194047b feat: совместители в заявлении на увольнение, печать после обходного листа, лицо принимающее ОС/НМА, суммы списания в обходном листе
Четыре независимых доработки поверх связки «Заявление на увольнение» ↔
«Обходной лист»:

1. Совместители (несколько компаний у одного сотрудника): approval-route уже
   резолвит директора/должностного эквивалента КАЖДОЙ компании отдельным шагом
   маршрута (HeadType.CompanyDirectors, шаблон route 17: Chief → CompanyDirectors).
   Organization на форме подачи заявления теперь интерактивная таблица
   (OrganizationsTable) вместо read-only списка — строку компании можно убрать,
   если сотрудник реально не увольняется отовсюду сразу; убранная компания сразу
   снимается и из уже спланированной матрицы (matrix.remove) — искать нужную
   строку вручную не надо. Новый shared/dictionary/employeeLookup.service.ts
   зеркалит DirectorPositionByCompany бэкенда (KazpromService → Главный механик,
   СТ Global → Генеральный директор, иначе Директор) и Employee/Manager
   (managerType=chief) — используется и здесь, и в следующем пункте.

2. Печать заявления заблокирована, пока парный обходной лист не согласован
   (статус читается напрямую по ClearanceUrl, без отдельного поля-дублёра).

3. «Лицо, принимающее ОС/НМА» (AssetsAcceptor, People) — обязательное поле,
   которое заполняет НЕ заявитель, а непосредственный руководитель увольняемого
   (identity-check по Employee/Manager, а не по должности, как в approverRights
   «Обходного листа») прямо перед своим решением (DecisionPanel.onBeforeDecide);
   пустое поле блокирует решение.

4. В обходном листе — 4 независимые пары «сумма к списанию + обязательный
   комментарий» (ОС/СИЗ/подотчёт, обучение, НМА, ТМЦ), отдельно от уже
   существующего TrainingAmount. Заполнить может любой активный согласующий
   (не только профильный), но как только сумма введена — пара блокируется
   навсегда для всех (лок по снимку на момент загрузки, не реактивно от текущего
   ввода — иначе поле блокировалось бы прямо во время набора цифр).

Списки на /sites/requests обновлены: AssetsAcceptor (Заявление на увольнение),
8 колонок WriteOff* (Обходной лист). tsc --noEmit и heft test (build+lint+179
тестов) чистые.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 16:46:41 +05:00

54 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Формы портала заявок — индекс
Каждая форма живёт в своей папке `src/webparts/requestPortal/forms/<Форма>/` и имеет
рядом **`README.md`** — карточку с её **бизнес-поведением** (то, что не видно из кода
с первого взгляда). Здесь — общий индекс.
## Правило (при добавлении формы)
1. Папка `forms/<Форма>/` + `README.md` по [шаблону](./form-readme-template.md).
2. Строка в индексе ниже.
3. Строка в `forms/registry.ts` (ленивая форма) и, если есть режим согласующего,
в `forms/viewRegistry.ts`.
4. Плитка в `data/requests.ts`.
## Формы больше не хардкодят RequestTypeId
Числовой id типа заявки во внешнем approval-route API (`GET /api/request-types`)
выдаётся сервером при регистрации типа в админке и непредсказуем заранее (в
старой pto-tracker у «отпуска» было 1, при заведении типа в новой админке он
получил id 11). Раньше каждая форма хардкодила это число константой вида
`VACATION_REQUEST_TYPE_ID = 11`; теперь — резолвит его в рантайме по своему
`pageUrl` (тот же rptype, что и `id` в `data/requests.ts`) через
`useRequestTypeId(context, pageUrl)` (`shared/approval`). Результат кешируется
на уровне модуля на время сессии (см. `getRequestTypeIdByPageUrl` в
`approvalRoute.service.ts`) — повторный вызов из другой формы не бьёт по сети заново.
- Форма подачи знает свой `pageUrl` из пропа `requestType.id`.
- Режим согласующего (`<Форма>View`) получает его пропом `formKey` (см.
`IApprovalViewProps` в `forms/viewRegistry.ts` и `ApproveFeature.tsx`).
## Что НЕ дублируем в карточке (лежит в других местах)
- Колонки списков → `forms/<Форма>/provisioning.json`.
- Параметры ссылок (rptype/rpmode/rpid/rpsource) → [`routing.md`](./routing.md).
- Как обращаться к спискам SP из кода → [`sp-lists-frontend.md`](./sp-lists-frontend.md).
- Общий жизненный цикл (черновик/upsert/блокировка/статусы), согласование, исполнение,
печать — **одинаковы для всех форм** (общие примитивы `shared/ui` и `shared/approval`).
Карточка — только про то, чем **эта** форма отличается.
---
## Индекс форм
| Ключ (rptype) | Форма | Категория | Согл. | Исп. | Просмотр | Фишки | Готово |
| --- | --- | --- | :---: | :---: | :---: | --- | :---: |
| [`recruiting-selection`](../src/webparts/requestPortal/forms/RecruitingSelection/README.md) | Заявка на подбор | Рекрутинг | нет | нет | нет | много полей (~42), поля-люди (в т.ч. мульти) | ✅ |
| [`recruiting-hire`](../src/webparts/requestPortal/forms/RecruitingHire/README.md) | Заявка на прием | Рекрутинг | да | да | да | маска телефона, деньги, условное «взамен кого», источник для орг. места | ✅ |
| [`recruiting-referral`](../src/webparts/requestPortal/forms/Referral/README.md) | Реферальная рекомендация | Рекрутинг | да | да | да | кандидат — внешний (текстовые поля, не People); маршрут по рекомендателю; исполнитель переназначает на реального; условное уточнение «откуда знаете» | ✅ |
| [`it-workplace-setup`](../src/webparts/requestPortal/forms/WorkplaceSetup/README.md) | Организация рабочего места | IT | да | да | да | префилл из «прием», поля ПО/доступы правит руководитель | ✅ |
| [`it-1c-ticket`](../src/webparts/requestPortal/forms/Ticket1C/README.md) | Заявка в отдел 1С | IT | да | нет | да | контакты предзаполняются из Graph (/me); вместо фазы исполнения — карточка в Microsoft Planner (согласовано/сразу без согласования — рабочий бакет, отклонено — отдельный бакет) | ✅ |
| [`clearance-form`](../src/webparts/requestPortal/forms/Clearance/README.md) | Обходной лист | Отдел кадров | да | нет | да | подаётся HR за увольняемого (People-picker) либо создаётся сам по согласованному «Заявлению на увольнение»; условие «IsManager» резолвится по должности из самой заявки; да/нет-поля (парковка, СКУД); 4 независимые пары «сумма к списанию + комментарий» (ОС/СИЗ/подотчёт, обучение, НМА, ТМЦ) — вводит любой активный согласующий, блокируется навсегда после первого ввода | ✅ |
| [`hr-dismissal`](../src/webparts/requestPortal/forms/Dismissal/README.md) | Заявление на увольнение | Отдел кадров | да | нет | да | совместители — таблица компаний с удалением строки (снимает и согласующего из матрицы); должность/организация из справочника; **после согласования сам создаёт обходной лист**; печать заблокирована до согласования обходного листа; «Лицо, принимающее ОС/НМА» — заполняет только непосредственный руководитель | ✅ |
| `hr-transfer` | Перемещение сотрудников | Отдел кадров | — | — | — | — | ⏳ заглушка (плитка есть, форма не сделана) |
Легенда: **Согл.** — есть фаза согласования; **Исп.** — есть фаза исполнения;
**Просмотр** — есть режим согласующего (`<Форма>View`).