Humanresources 26.600.0: триггер БП на первый вход сотрудника и закрытый селектор физлиц из 1С
Обновление безопасности
Закрыта уязвимость или ослабленная проверка прав. Ставить в первую очередь.
В humanresources 26.600.0 для коробочного Битрикс24 новый конструктор процессов получил триггер «Появился новый сотрудник», который срабатывает на первом входе сотрудника на портал. Ещё в релизе закрыли селектор физлиц из 1С со СНИЛС, который раньше открывался любому пользователю, и сделали одноразовым ПИН для запроса расчётного листка и данных об отпуске в HCM Link. Обновление касается тех, кто строит онбординг на бизнес-процессах, и авторов приложений-коннекторов к 1С.
Новое
Встречайте нового сотрудника бизнес-процессом
В каталоге конструктора появился узел CBPNewEmployeeTrigger в группах STARTER, HR и TEAM_MANAGEMENT. Дальше по сценарию он отдаёт «Сотрудника» (USER, в виде user_N) и «Дату и время появления» (EventDateTime).
В свойстве «Сотрудники, подразделения и команды» выбирают сотрудников, узлы оргструктуры (с подчинёнными или без) и старые отделы, которые модуль сам переводит в узлы. Команда работает как отдел. Пустое свойство значит «любой новый сотрудник». Выражения над параметрами и переменными шаблона в фильтр не пишите. Правила триггера движок проверяет на процессе-заглушке с пустыми параметрами, такое выражение там ничего не находит, и запуск отклоняется. Голый числовой id ядро читает как группу пользователей, его триггер тоже отклонит. Людей и отделы выбирайте в селекторе.
Если узла нет в каталоге, обновите bizproc и ui. .description.php триггера молча ничего не регистрирует, если в bizproc нет типа TRIGGER и нужных групп или в ui нет иконки o-add-person.
Кого модуль считает новым сотрудником
Первый вход ловит Integration\Bizproc\FirstLoginDispatcher, обработчик main:OnAfterUserAuthorize из install/migrations/events.php. Вход считается первым, если выполнено всё сразу:
- в снимке пользователя пустой
LAST_LOGIN; $params['update'] === true, по комментарию в коде так ядро отличает обычный вход от REST-авторизации;- сессия не виртуальная (
BX_SECURITY_SESSION_VIRTUAL); EXTERNAL_AUTH_IDне изUserTable::getExternalUserTypes(), при этом LDAP и вход через соцсети проходят;- способ входа не
LoginAs, неAppPasswordи неController.
Потом отсеиваются экстранет и участники коллаб. Сценарии запускаются один раз на сотрудника, отметку об этом модуль хранит в CUserOptions: категория humanresources, имя new_employee_trigger_launched, значение Y.
Администратор, вошедший под сотрудником, сценарий не запустит. Сотрудники, которые входили до обновления, триггер не вызовут, у них уже заполнен LAST_LOGIN. А давно заведённый аккаунт, который ни разу не входил, вызовет его при первом входе.
Проверять сценарий проще на свежем пользователе.
Обработчик стоит на каждом входе, но любое исключение ловит сам, так что вход из-за него не упадёт. Если сценарий с триггером есть, но не стартовал, причину модуль пишет через AddMessage2Log в файл из константы LOG_FILENAME, а без этой константы не пишет никуда. Туда же уходят пойманные исключения. В записи будет одна из причин: bizprocUnavailable, extranetMember, collabMember, alreadyRun, filteredOut, launchFailed или unexpectedFailure. Отказ по тарифу (BPDesignerConstraint) тоже записывается как launchFailed.
Запускайте сценарии из своего кода
Лаунчер берётся через Service\Container::getBizprocProcessLauncher() (сервис humanresources.integration.bizproc.processLauncher). Его launchForNewEmployee(int $userId) поднимает событие триггера, сам исключений не бросает и отвечает Result. Так можно запустить онбординг сотруднику, который вошёл до обновления. Отметку о запуске ставит обработчик входа, лаунчер её не трогает, а экстранет и коллаберов не отсеивает, это ваша забота. Если сотрудник ещё не входил, без отметки его первый вход запустит сценарии второй раз:
<?php declare(strict_types=1);
namespace Vendor\Onboarding\Application\Service;
use Bitrix\Bizproc\Starter\Starter;
use Bitrix\Extranet\User as ExtranetUser;
use Bitrix\HumanResources\Service\Container;
use Bitrix\Main\Error;
use Bitrix\Main\Loader;
use Bitrix\Main\Result;
final class NewEmployeeScenarioStarter
{
// та же отметка, которую проверяет FirstLoginDispatcher
private const MARKER_CATEGORY = 'humanresources';
private const MARKER_NAME = 'new_employee_trigger_launched';
private const MARKER_VALUE = 'Y';
public function start(int $userId): Result
{
if (
!Loader::includeModule('humanresources')
|| !Loader::includeModule('bizproc')
|| !class_exists(Starter::class)
) {
return (new Result())->addError(new Error('Нет модуля humanresources или bizproc', 'MODULE_MISSING'));
}
if (Loader::includeModule('extranet') && (new ExtranetUser($userId))->isExtranet()) {
return (new Result())->addError(new Error('Пользователь экстранета', 'EXTRANET_USER'));
}
// коллаберов модуль отсеивает через getCollaberService()->isCollaberById() из extranet
$marker = \CUserOptions::GetOption(self::MARKER_CATEGORY, self::MARKER_NAME, false, $userId);
if ($marker === self::MARKER_VALUE) {
return (new Result())->addError(new Error('Сценарии уже запускались', 'ALREADY_STARTED'));
}
// модуль ставит отметку до запуска, повторяем его порядок
\CUserOptions::SetOption(self::MARKER_CATEGORY, self::MARKER_NAME, self::MARKER_VALUE, false, $userId);
return Container::getBizprocProcessLauncher()->launchForNewEmployee($userId);
}
}
Ошибка в Result ещё не значит, что ничего не стартовало. Туда же попадают отказы фильтров других опубликованных сценариев, поэтому модуль дополнительно смотрит StartResult::isTriggerApplied() и getWorkflowIds().
Процесс стартует вне текущего хита. Лаунчер зовёт Starter::getByScenario(Scenario::onEvent) с setDelay(0), а bizproc включает отложенный старт от самого факта переданной задержки, нулевой тоже: $shouldStartLater = $useDelays && $startDelay !== null; в bizproc/classes/general/document.php. Выключает это опция bizproc disable_start_workflow_delay = Y. Тот же setDelay(0) пригодится, когда тяжёлый процесс запускается из вашего обработчика события.
Что сломается
Проверьте свои диалоги с селектором физлиц из 1С
До 26.600.0 PersonDataProvider::isAvailable() у сущности hcmlink-person-data (секция ui.entity-selector) возвращал true без проверки прав. Теперь провайдер спрашивает Container::getHcmLinkAccessService()->canRead(). Это право ACTION_B2E_DOCUMENT_ADD модуля sign, а без sign только администратор.
Если вы открывали этот селектор в своём диалоге, у обычного сотрудника он теперь пустой. Проверьте право тем же canRead() и не показывайте поле тем, кому оно ничего не найдёт.
Переименуйте companyGuid в коннекторе к 1С
В outputData заданий PIN_REQUEST и SALARY_VACATION_REQUEST ключ companyGuid стал companyUid, значение то же, UID организации в 1С. Эти задания уходят в события OnHumanResourcesHcmLinkPinRequested и OnHumanResourcesHcmLinkSalaryVacationRequested. Приложение, которое читает companyGuid, после обновления портала получит пустое значение. Сервис и события появились в humanresources 26.500.0, так что старое имя у кого-то уже в коде. Пока порталы обновляются, читайте оба ключа:
$companyUid = (string)($outputData['companyUid'] ?? $outputData['companyGuid'] ?? '');
Один ПИН на один запрос документа
Когда запрос документа завершился (DONE), SalaryVacationApiService сверяет ПИН через hash_equals, удаляет значение поля PIN на портале и освобождает слоты троттлинга pin_request и document_request. Тот же ПИН с портала больше не достать, а новый ПИН для следующего запроса сотрудник может попросить сразу, не дожидаясь конца интервала. Пока выданный ПИН не использован и не истёк, повторный запрос в пределах интервала вернёт то же задание, и новый запрос в 1С не уйдёт.
Найдите вызовы удалённого Member\Role
Вместе с Controller\Structure\Node\Member\Role пропали действия humanresources.api.Structure.Node.Member.Role.set (назначение роли участнику узла) и humanresources.api.Structure.Node.Member.Role.list (список ролей). JS модуля их не вызывал ни в 26.500.0, ни сейчас. Сломается только ваш код, который звал их через BX.ajax.runAction, поищите Member.Role в /local/.
Мелочи и находки
- В оргструктуре колесо мыши над карточкой мини-профиля двигает холст или прокручивает список под курсором, Ctrl+колесо масштабирует.
- Мастер настройки команды предупреждает, что у команды не назначен руководитель или заместитель. По комментарию в коде отчёты получает руководитель или заместитель команды, затем родительские команды, затем руководители отдела.
humanresources.hcmlink.field.value.setпринимает кодРасчетныйЛистокчерез «е» и сам переводит его вРасчётныйЛисток, который ждётPayrollType::SALARY. Значения полей типа DOCUMENT теперь пишутся в слот документа из задания. По комментарию в коде, sign кладёт туда id подписанта и по нему читает значение.
Устаревшие и удалённые API в этой версии
| Символ | Статус | Чем заменять |
|---|---|---|
Bitrix\HumanResources\Controller\Structure\Node\Member\Role::setAction()
|
Удалено | — |
Bitrix\HumanResources\Controller\Structure\Node\Member\Role::listAction()
|
Удалено | — |
humanresources.api.Structure.Node.Member.Role.set
|
Удалено | — |
humanresources.api.Structure.Node.Member.Role.list
|
Удалено | — |