5d2abaf430
Tests / frontend-test (push) Successful in 2m1s
## Что сделано **Чат заявки: отметки и оповещения** - В поле ввода «@» открывает подсказку с участниками заявки: инициатор, согласующие и исполнители из маршрута, а также те, кому открыты «Все заявки» этого типа (список из request-type-access). - Отметка — обычный текст «@ФИО», без штатного упоминания SharePoint, чтобы не уходило его письмо. - После отправки сообщения портал вызывает поток Power Automate (`FLOW_CHAT_NOTIFY_URL`): отмеченным — «Вас упомянули», инициатору — «Новое сообщение по вашей заявке». Сбой потока не мешает отправке. - В письмо добавляется строка «Прикреплены файлы: …», чтобы сообщение из одного файла не приходило пустым. - Свойство веб-части «Чат: уведомлять о своих сообщениях (для теста)», по умолчанию выключено: письма и о своих сообщениях, можно отметить себя. - Когда пишет сам инициатор с отметками, в `initiatorEmail` уходит первый отмеченный — поток шлёт инициатору всегда, если его нет среди отмеченных, и иначе он получил бы письмо о своём же сообщении. **Чат включён для:** Обходной лист, заявка на подбор, заявка на приём, заявка в отдел 1С. **Исправление:** редактор маршрута может удалять исполнителей в Обходном листе, Командировке и заявке в 1С (не передавалось `canRemoveRow`). **Прочее:** убраны 4 предупреждения линтера (`no-new-null`, `no-script-url`). ## Не проверено на тенанте - Ответ потока 200 через AadHttpClient и доставка писем. - Права согласующих на комментарии и на запись в библиотеку «Файлы чата». - Папки в «Файлы чата» наследуют права библиотеки, а не закрыты на заявку — для подбора и приёма это важно решить до выкладки. - Если поток вставляет `messageText` в HTML-письмо, перенос строки перед «Прикреплены файлы» может не отобразиться. --------- Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz> Reviewed-on: http://git.tnsu.kz/timur.gorodetskiy/request-portal/pulls/26
Заявка на командировку (hr-business-trip)
Назначение: заявка о направлении сотрудника в служебную командировку — куда, когда,
с каким заданием и сметой расходов.
Категория: Отдел кадров (плитка «Заявка на командировку», пока comingSoon — только тестировщикам)
Списки SP: «Заявка на командировку — данные» / «Заявка на командировку — согласование»
RequestTypeId (внешний API маршрутов): плейсхолдер — получит числовой id при заведении
типа в админке approval-route с pageUrl «hr-business-trip».
Маршрут
- Маршрут настраивается в админке approval-route другим человеком — форма его только получает.
- Фазы: согласование + исполнение, обе грузятся общим
usePhasedRoute(shared/approval). Нет шагов исполнения — после согласования статус «Согласовано»; нет согласующих —initialSubmitStatusсразу ставит «Выполнение». - Планируемый маршрут резолвится по e-mail выбранного сотрудника; согласующих заявитель может править (новая / черновик / доработка), исполнителей — нет.
Особое поведение
- Можно подать за другого сотрудника. По умолчанию — сам инициатор; при выборе другого
подтягиваются его должность и организации (
Employee/ByEmail,useTripEmployee). - Маршрут — лента точек (
components/route, логика —route.ts; гибрид «маршрут + смета» по образцу Concur/Navan/TripIt). Город отправления → точки (город + объект из/Project+ даты прибытия/отъезда) → (возвращение — переключатель). Простая поездка — одна точка; «+ Добавить точку маршрута» — для поездок по нескольким объектам.- Участки пути не хранятся, а выводятся из точек (
routeLegs, ключоткуда>куда); у каждого участка — вид транспорта плашками (legTransport,TRANSPORT_TYPES), обязателен. - Объект точки — только выбор из справочника (
projectId): по объектам разносят затраты. - Два вида маршрута — переключатель «Форма | Схема» (
RouteViewSwitch). Схема (RouteScheme) — только просмотр, как схема метро: узлы-точки (город, объект, даты, ночи, расходы по точке из сметы —stopTotals), на линиях — вид транспорта, внизу сводка «дни · объекты · переезды · итог». Клик по точке — форма с прокруткой к ней. Заявитель начинает с формы, согласующий (режим чтения) — со схемы. Широкий экран — слева направо, узкий — сверху вниз. Сумму под точками Тимур может попросить убрать, если будет громоздко. - Новая точка начинается с даты отъезда из предыдущей (то, что человек уже ввёл); прибытие раньше отъезда из предыдущей точки — ошибка.
- Хранение:
TripRouteJson; для отчётов из маршрута пишутсяTripRoute(текстом),TripCity(города),Project/ProjectId(объект ПЕРВОЙ точки — колонка у всех форм одна),TripProjects(все объекты),TripStartDate/TripEndDate/TripDaysCount(весь период).
- Участки пути не хранятся, а выводятся из точек (
- Задание — нумерованный список задач, хранится в
TripTasksJson(+ читаемая копияTripTasksдля представлений SP). Пустые строки не сохраняются. - Смета (
components/estimate, логика —estimate.ts). Всё вводится вручную, кроме суточных:- Суточные считаются сами (с 10-09, по просьбе кадров): по позиции на каждую точку
маршрута (
syncPerDiem,itemsFromRouteвESTIMATE_KINDS), город и проект — из точки, дни — из её дат включительно, но день переезда считается один раз (stopPerDiemDays). Человек вводит только кол-во МРП в день; ставка = кол-во ×MRP_VALUE(захардкожен в model.ts вместе сMRP_YEAR— обновлять раз в год). Ставка сохраняется в заявке (price), поэтому просмотр старой заявки не пересчитывается по новому МРП —syncPerDiemприменяется только в форме. - Статьи: основные Суточные / Проезд / Проживание (переключатель «Требуется / Не требуется», выключенная печатается «не требуется»), Страховка и Виза (по одной) и «Другой расход» со своим названием (сколько угодно) — кнопками «+», удаляются корзиной.
- Внутри статьи — позиции («+ Ещё гостиница», «+ Ещё участок пути»; у суточных
позиции только из маршрута). Позиция привязана к точке маршрута (суточные, проживание, другой расход) или
к участку пути (проезд); страховка/виза — без привязки. Вариант один — выбор скрыт и
подставляется сам (
resolveLinkId); точку удалили — позицию нужно привязать заново. - Сумма позиции — «Суммой» или «Кол-во × цена» (только перемножение введённого), подписи над полями. Пробовали таблицу «в строку» и смету «по точкам маршрута» — Тимур вернул карточки (10-05): «самые понятные».
- Итог на лету: полоса долей по видам статей (палитра проверена dataviz-валидатором) и,
если объектов несколько, итог по объектам (
projectShares; участок — к объекту пункта назначения, обратный — к объекту, откуда уезжают; страховка/виза — «без объекта»). - Смета сама не обязательна, но у включённой статьи каждая позиция — с суммой и привязкой, у «Другого расхода» — название, у суточных — кол-во МРП.
- Хранение:
TripEstimateJson(статьи + total), читаемо —TripEstimate(позиция на строку), итог числом —TripEstimateTotal. Просмотр/печать — таблица по статьям.
- Суточные считаются сами (с 10-09, по просьбе кадров): по позиции на каждую точку
маршрута (
- Обязательство по авансовому отчёту (текст бланка) — флажок, без него не отправить.
- Дата подачи (
SubmitDate, общий столбец сайта) — ставится сегодняшней, пока заявку можно править (см. shared/submitDate.ts). - Подсветка незаполненных полей —
FieldIssuesProvider+ правила вvalidation.ts. Черновику нужен только сотрудник. - Печать — данные заявки и маршрут согласования/исполнения, без шапки с адресатом: бумажный бланк не повторяется (решение Тимура).
- Заголовок элемента (
Title):Заявка на командировку — {ФИО} — {города}, {дата начала}. - Новые колонки — с префиксом
Trip*:StartDateв других формах уже занят с другим заголовком (см. грабли коллизий internalName).
Секции формы
EmployeeSection (сотрудник · должность · дата подачи · организация) → RouteSection (маршрут лентой + цель) → TasksSection (задачи) → EstimateSection (смета + итог) → ObligationSection (текст обязательства + согласие).
Точки входа
- rptype:
hr-business-trip - Режим согласующего (просмотр): есть (
BusinessTripView) - «Создать на основе»: нет
Не сделано
- Авансовый отчёт после командировки — отдельной формой, пока не придумано как.