humanresources 26.700.0 Ломающее

Humanresources 26.700.0: триггер на перевод и смену роли, «Появился новый сотрудник» только по отделам и командам

5 мин чтения
Узнавайте о ломающих изменениях Битрикса раньше, чем они доедут до прода: свежие разборы — в канале @bxmax_updates

Ломающее обновление

Удалены или изменены публичные API — прикладной код может перестать работать.

В humanresources 26.700.0 новый конструктор процессов получил триггер на перевод сотрудника, смену его роли и увольнение, а в обмене с 1С для КЭДО появились исключения из сопоставления и отключение компании. Ломаются сценарии «Появился новый сотрудник» с поимённо выбранными людьми, а AJAX Mapper.delete и $arResult грида сотрудников 1С сменили контракт. Прошлый разбор модуля — Humanresources 26.600.0.

Новое

Запускайте сценарий при переводе и смене роли

Триггер CBPStructurePositionChangedTrigger называется в каталоге «Изменилась позиция сотрудника в структуре», в официальном описании версии — «Изменение позиции в структуре». В обязательном поле «Типы изменений» выбирают, на что реагировать: добавление в отдел или команду, исключение или перевод, назначение на структурную роль (руководитель, заместитель и другие) или снятие с неё. В поле «Сотрудники» можно выбрать только людей или выражения, пустое поле значит «любой сотрудник».

Триггер отдаёт сотрудника (USER), тип изменения (CHANGE_TYPE: added, removed, moved, role_assigned, role_revoked), прежние и новые отделы и команды (ID и названия), прежнюю и новую роль (MEMBER_HEAD, MEMBER_TEAM_DEPUTY_HEAD и другие) и время изменения.

Изменения членства модуль пишет в журнал и сверяет со структурой в фоновой задаче после хита. На сотрудника за хит приходится одно изменение. Исключение вместе с добавлением дают moved, перенос участников удалённого отдела в родительский тоже. Назначение руководителем или заместителем даёт role_assigned, остальные смены роли дают role_revoked. Виртуальных пользователей триггер не видит, а без bizproc или на несконвертированной структуре журнал выключен. Процесс стартует вне текущего запроса, ошибки запуска уходят в логгер humanresources.structurePositionJournal. Увольнение тоже доходит до триггера: новый обработчик intranet:onAfterUserFire на сконвертированной структуре деактивирует все членства уволенного, сверка видит это как removed, а выборки по активному членству, например getCommonUsersFromRelation(), перестают его считать.

Узел «Получить данные отделов и команд» пока не появится

В официальном описании версии узел CBPGetStructureDataNode заявлен как добавленный, но в каталог конструктора не попадает. Его .description.php требует класс Bitrix\Bizproc\Public\Feature\Node\GetStructureDataNodeFlag, а в bizproc 26.1800.0 такого нет. Узел будет отдавать отделы и команды от выбранного узла с руководителями, заместителями и сотрудниками, когда флаг появится в bizproc и его включат.

Проверяйте отделы в своём триггере тем же фильтром

Привязку триггеров сотрудников к отделам и командам вынесли в классы StructureNodeFilter, StructureNodeBinding и StructureNodeValue из Integration\Bizproc. На них построены «Появился новый сотрудник» и «Сотрудник уволен» из bizproc (разбор Bizproc 26.1800.0), второй учитывает неактивные членства (withInactiveMembership: true). Свой триггер может проверять привязку тем же StructureNodeFilter::check(int $userId, mixed $storedValue, mixed $resolvedValue, bool $withInactiveMembership = false).

Селектор привязки показывает всю структуру без проверки прав. По комментарию в коде, доступ к конструктору сценариев сам даёт такое право.

Исключайте сотрудников из сопоставления с 1С

В гриде сопоставленных сотрудников появился список людей, которых не связывают с персонами 1С. В окне подготовки документа несопоставленного участника можно исключить на месте, процент синхронизации его не считает. Ещё окно может попросить sign убрать участника из документа событием BX.Humanresources.HcmLink.DataMapper:onMemberRemoveRequested ({ userId, companyId, documentUid }).

Из своего кода исключениями управляет AJAX-контроллер humanresources.HcmLink.Exclusion с действиями add, delete и list (companyId, userIds). Только POST с JSON, до 500 пользователей за вызов. В JS те же вызовы и disconnectCompany() есть в Api расширения humanresources.hcmlink.api, код ошибки из ответа достаёт getErrorCode().

Исключение в той же транзакции снимает связь с персоной 1С. Ручное сопоставление и REST humanresources.hcmlink.employee.set наоборот убирают человека из исключений, данные 1С важнее. Mapper.load в режиме direct отдаёт ещё excludedUserIds, matchedUserIds и canManageExclusions. Исключениями управляет тот, кто работает с интеграцией: при модуле sign обладатель права ACTION_B2E_DOCUMENT_ADD, без sign администратор. Для добавления нужна ещё функция sign hcmLinkExclusions, её включает Sign 26.1100.0. До него добавление отвечает HCMLINK_ACCESS_DENIED, а кнопки нет.

Отключайте компанию 1С из плитки

Администратор портала видит в плитке компании (humanresources.hcmlink.company.list) пункт «Отключить интеграцию». Действие humanresources.HcmLink.Company.disconnect через CompanyDisconnectService::disconnect() в одной транзакции удаляет поля, исключения и компанию. По комментарию в коде, обычное право на интеграцию роль «Сотрудник» по умолчанию даёт всем, поэтому отключать может только администратор. REST humanresources.hcmlink.company.delete идёт через тот же сервис, на отсутствующую компанию по-прежнему отвечает ObjectNotFoundException, на остальные ошибки — RestException с кодом сервиса.

Следите за обменом с 1С из своего кода

Public\Service\Container::getHcmLinkMonitoringService() отдаёт сводку обмена заданиями с 1С. isAvailable() отвечает, доступна ли интеграция и подключена ли хоть одна компания. У каждой компании из getSummary()->companies есть health() (enum ExchangeHealth: NO_DATA, OK, UNFINISHED, PARTIAL, BROKEN, вердикт по последним суткам), счётчики заданий за месяц и сутки и время последнего ответа 1С. portalHealth() возвращает BROKEN, только когда сломаны все компании с заданиями, иначе null. Сам модуль сервис пока не вызывает, права сервис не проверяет, описание — в lib/Public/docs/hcm-link-monitoring.md.

        <?php declare(strict_types=1);

namespace Vendor\Hr\HcmLink;

use Bitrix\HumanResources\Public\Service\Container;
use Bitrix\HumanResources\Type\HcmLink\Monitoring\ExchangeHealth;
use Bitrix\Main\Engine\CurrentUser;
use Bitrix\Main\Loader;

final class ExchangeAlert
{
    /**
     * @return list<string> компании, где обмен с 1С не работает или теряет задания
     */
    public function troubledCompanies(): array
    {
        // Сервис прав не проверяет: сводку видит только администратор
        if (!CurrentUser::get()->isAdmin() || !Loader::includeModule('humanresources')) {
            return [];
        }

        $monitoring = Container::getHcmLinkMonitoringService();
        if (!$monitoring->isAvailable()) {
            return [];
        }

        $titles = [];
        foreach ($monitoring->getSummary()->companies as $company) {
            if (in_array($company->health(), [ExchangeHealth::BROKEN, ExchangeHealth::PARTIAL], true)) {
                $titles[] = $company->companyTitle;
            }
        }

        return $titles;
    }
}

    

Читайте структуру новыми методами публичных сервисов

  • NodeService::getNodeIdsGroupedByAccessCode(array $accessCodes) — ID узлов по каждому коду доступа.
  • NodeService::findAll() и findAllByIds() с viewerUserId и structureAction проверяют права этого пользователя вместо текущего.
  • NodeMemberService::findAllByEntityIds(..., memberActive: null) снимает фильтр по активности членства, по умолчанию true.
  • Department\UserService::filterActiveEmployeeIds(array $userIds) оставляет сотрудников с активным членством в отделе.

Что сломается

Пересохраните «Появился новый сотрудник» без поимённых людей

Свойство триггера теперь называется «Подразделения и команды», и селектор предлагает только их. Если в опубликованной привязке остался хоть один сотрудник (user_<id>), даже рядом с отделами, она отклоняется целиком (HUMANRESOURCES_NEW_EMPLOYEE_TRIGGER_STALE_USER_CODES), и сценарий не запускается. При пересохранении настроек сотрудники молча выпадают из привязки. Если в ней были только люди, она становится пустой, и сценарий запускается для каждого нового сотрудника. Решите, какими отделами или командами заменить людей, пока никто не пересохранил настройки триггера.

Передавайте companyId в Mapper.delete

Действие humanresources.HcmLink.Mapper.delete стало deleteAction(?int $companyId = null, array $mappingIds = []) и снимает сопоставление только в пределах компании. Без companyId оно отвечает ошибкой COMPANY_ID_REQUIRED. Нечисловой или неположительный ID либо запись другой компании отклоняют весь набор с INVALID_MAPPING_IDS, а строки исключений в гриде имеют ID excl_<userId>. BX.Humanresources.Hcmlink.MappedPerson.deleteLinkMappedPerson() тоже ждёт { companyId } и без аргумента падает. Свой вызов:

        // Extension::load(['humanresources.hcmlink.exclusions', 'ui.notification'])
async function unlinkPersons(companyId, selectedRowIds)
{
	// строки исключений (excl_<userId>) в mappingIds не отправляем
	const { personIds } = BX.Humanresources.Hcmlink.splitGridSelection(selectedRowIds);
	if (personIds.length === 0)
	{
		return;
	}

	try
	{
		await BX.ajax.runAction('humanresources.HcmLink.Mapper.delete', {
			json: { companyId, mappingIds: personIds },
		});
	}
	catch (response)
	{
		// COMPANY_ID_REQUIRED или INVALID_MAPPING_IDS: набор отклонён целиком
		BX.UI.Notification.Center.notify({ content: BX.Text.encode(response.errors?.[0]?.message ?? 'Ошибка') });
	}
}

    

Обновите копии шаблона humanresources.hcmlink.mapped.users

Компонент больше не отдаёт $arResult['MAPPED_PERSONS'] и $arResult['USERS']. Строки грида приходят готовыми и уже экранированными в $arResult['ROWS'], добавлены флаги CAN_MANAGE_EXCLUSIONS и IS_EXCLUSION_LIST. Кнопку удаления в копии переведите на deleteLinkMappedPerson({ companyId }), номер компании лежит в $arResult['COMPANY_ID'].

Допишите методы в свои реализации интерфейсов

Это касается только своих классов, подменённых через ServiceLocator. В Contract\Repository\HcmLink\PersonRepository добавлены filterMappedUserIds(int $companyId, array $userIds): array и dropLinksByUserIds(int $companyId, array $userIds): int, в Integration\Bizproc\ProcessLauncherInterface — launchForPositionChanges(StructurePositionChange ...$changes): Result. Без них класс не загрузится. Обёртку над штатным лаунчером проще дописать делегированием:

        <?php declare(strict_types=1);

namespace Vendor\Hr\Bizproc;

use Bitrix\HumanResources\Integration\Bizproc\ProcessLauncher;
use Bitrix\HumanResources\Integration\Bizproc\ProcessLauncherInterface;
use Bitrix\HumanResources\Integration\Bizproc\StructurePositionChange;
use Bitrix\Main\Diag\Debug;
use Bitrix\Main\Result;

final class LoggingProcessLauncher implements ProcessLauncherInterface
{
    public function __construct(
        private readonly ProcessLauncherInterface $inner = new ProcessLauncher(),
    ) {
    }

    public function launchForNewEmployee(int $userId): Result
    {
        return $this->logFailure($this->inner->launchForNewEmployee($userId));
    }

    // Метод из 26.700.0: без него класс не загрузится
    public function launchForPositionChanges(StructurePositionChange ...$changes): Result
    {
        return $this->logFailure($this->inner->launchForPositionChanges(...$changes));
    }

    private function logFailure(Result $result): Result
    {
        if (!$result->isSuccess()) {
            Debug::writeToFile($result->getErrorMessages(), 'hr-launcher', '/local/logs/hr-launcher.log');
        }

        return $result;
    }
}

    

БД

Новая таблица b_hr_hcmlink_exclusion (ORM Model\HcmLink\ExclusionTable) с полями ID, COMPANY_ID, USER_ID, CREATED_BY, CREATED_AT, пара COMPANY_ID + USER_ID в ней не повторяется. Пишите через ExclusionService, прямая вставка не снимет связь с персоной 1С.

Мелочи и находки

  • Закрыли две дыры. NodeMemberRepository::getCommonUsersFromRelation() собирал SQL из ID без приведения типов, теперь ID приводятся к int и идут плейсхолдерами. Так же чистит вход NodeRelationService::getUsersNotInRelation(), его вызывают im и socialnetwork. Грид сотрудников 1С теперь экранирует имена персон и пользователей.
  • При удалении отдела участники переезжают в родительский постранично по ENTITY_ID. Раньше offset в отделе больше 1000 человек перескакивал через часть участников.
  • Мастер оргструктуры при создании пускает назад без проверки шага, на шаге сотрудников стоит компактная заглушка поиска (getCompactSearchTabOptions() в company-structure/structure-components). Запросы company-structure/api идут без Content-Type: application/json, и, по официальному описанию, сетевые фильтры портала больше не блокируют создание отдела.
  • REST humanresources.node.member.set на сбой удаления отвечает MEMBER_DELETE_FAILED.

Новая версия вышла — разбор уже в Telegram

В канале @bxmax_updates публикуем каждый свежий разбор: что сломается, что устарело и что появилось в API. Узнаете до того, как обновите прод.

Подписаться

Читайте дальше

humanresources 26.600.0 Безопасность Свежее

Humanresources 26.600.0: триггер БП на первый вход сотрудника и закрытый селектор физлиц из 1С

В humanresources 26.600.0 для коробочного Битрикс24 новый конструктор процессов получил триггер «Появился новый сотрудник», который срабатывает на первом входе сотрудника на портал. Ещё в релизе закрыли селектор физлиц из 1С со СНИЛС, который раньше открывался любому пользователю, и сделали одноразо…

4 мин
humanresources 26.500.0 Ломающее

Humanresources 26.500.0: виртуальные пользователи пропали из выборок и счётчиков оргструктуры

В humanresources 26.500.0 (коробочный Битрикс24) фильтры, репозитории и счётчики оргструктуры по умолчанию перестали видеть ботов, пользователей приложений и остальных виртуальных пользователей. В том же релизе поменяли местами перепутанные `ONLY_ACTIVE` и `ONLY_GLOBAL_ACTIVE`, `RolePermissionServic…

3 мин
vibecodeconnector 26.1000.0 Заметное Свежее

Vibecodeconnector 26.1000.0: «Доступы» и «Публичная ссылка» в каталоге, чат в настройках приложения и доступ по живой оргструктуре

В меню приложения в каталоге Вайбкода пункт «Поделиться» разделён на «Доступы к приложению» и «Публичную ссылку», переключатель чата переехал в «Настройки приложения», а доступ по отделам проверяется по текущей оргструктуре. Баланс Вайбкода для виджета тарифа уже лежит в модуле, но выключен флагом….

4 мин
sign 26.1100.0 Ломающее Свежее

Sign 26.1100.0: ручное напоминание подписантам, скачивание шаблонов и REST провайдеров только для администратора

В sign 26.1100.0 подписантам можно напомнить из грида документа, подписание запускается из списка подписантов, а шаблоны и комплекты скачиваются незаполненными. REST провайдеров подписи теперь только для администратора, у сервисов списка символьных кодов новые сигнатуры. Версия требует main и humanr…

7 мин
Мы используем файлы cookie для улучшения работы сайта. Продолжая использовать сайт, вы соглашаетесь с нашей политикой конфиденциальности.
AI Домовой

AI Домовой История

на связи

пишет…

Можно закрыть чат и перейти на другую страницу. Когда ответ будет готов, на кнопке Домового появится отметка.

Нет истории чатов
AI Домовой

Нужна авторизация

Войдите, чтобы задавать вопросы AI Домовому.

Войти