Синхронизация пользователей с внешней системой - ключ, группы, увольнения
Настраиваем регулярный обмен учётными записями с кадровой или учётной системой: ключ сопоставления, обновление, группы и уволенные сотрудники.
Что нужно знать заранее
Ключом сопоставления служит внешний код, а не адрес почты. Почта меняется у живых людей регулярно, и синхронизация по ней заводит второго пользователя вместо обновления первого.
Запись групп заменяет весь набор групп пользователя. Выданные вручную права после такой записи исчезают, и сотрудник теряет доступ к разделам, которые внешняя система не знает.
Ушедших сотрудников выключают, а не удаляют. Удаление рвёт связи с заказами, заявками и историей действий, а выключенная запись сохраняет всё это и не пускает человека на сайт.
Шаги
- Договориться о ключе сопоставления и получать его в каждой выгрузке.
- Сохранять внешний код при первом создании пользователя на сайте.
- Обновлять только изменившиеся записи, сверяя данные перед записью.
- Собирать группы из внешних и своих ролей, а не затирать их выгрузкой.
- Выключать отсутствующих в выгрузке вместо удаления учётных записей.
Решение
Ищем пользователя по внешнему коду:
$user = \Bitrix\Main\UserTable::getRow(['filter' => ['=XML_ID' => $row['code']], 'select' => ['ID', 'ACTIVE', 'EMAIL', 'NAME', 'LAST_NAME']]);// внешний код - единственный надёжный ключ регулярной синхронизации// поиск по почте заводит дубль, как только сотрудник её сменитВнешний код приходит из системы-источника и там же не меняется. Поэтому смена фамилии, почты или логина на сайте не мешает найти ту же самую учётную запись при следующем обмене.
Создаём или обновляем запись:
$cuser = new \CUser();$fields = ['NAME' => $row['name'], 'LAST_NAME' => $row['surname'], 'EMAIL' => $row['email'], 'XML_ID' => $row['code'], 'ACTIVE' => 'Y'];$id = $user ? ($cuser->Update($user['ID'], $fields) ? $user['ID'] : 0) : $cuser->Add($fields + ['LOGIN' => $row['code'], 'PASSWORD' => randString(16)]);if (!$id) { $log[] = $cuser->LAST_ERROR; } // текст ошибки нужен в журналеОшибку записи обязательно кладут в журнал обмена. Молчаливый пропуск строки превращается в вопрос «почему у половины отдела нет доступа» через неделю после запуска.
Меняем группы, не теряя своих:
$current = \CUser::GetUserGroup($id); // что есть сейчас$manual = array_intersect($current, [7, 12]); // роли, выданные руками$cuser->Update($id, ['GROUP_ID' => array_unique(array_merge($manual, $fromSource))]);// запись групп заменяет набор целиком, поэтому свои роли добавляют явноСвои роли перечисляют списком в самом коде обмена. Так права, выданные администратором сайта, переживают каждую синхронизацию и не требуют повторной выдачи.
Выключаем ушедших сотрудников:
$seen = array_column($rows, 'code'); // коды из этой выгрузки$rs = \Bitrix\Main\UserTable::getList(['filter' => ['=ACTIVE' => 'Y', '!=XML_ID' => false], 'select' => ['ID', 'XML_ID']]);foreach ($rs as $u) { if (!in_array($u['XML_ID'], $seen, true)) { $cuser->Update($u['ID'], ['ACTIVE' => 'N']); }}Выключение вместо удаления сохраняет заказы, заявки и историю действий человека. Оно же обратимо: вернувшийся сотрудник получает прежнюю учётную запись, а не новую с нуля.
Обрабатываем выгрузку порциями:
foreach (array_chunk($rows, 200) as $i => $chunk) { processChunk($chunk); \Bitrix\Main\Diag\Debug::writeToFile(['порция' => $i], date('H:i:s'), 'users-sync.log');}Типичные проблемы
После обмена в списке появились дубли сотрудников.
Сопоставление идёт по адресу почты, а он у людей меняется. Ключом синхронизации делают внешний код системы-источника и сохраняют его при создании.
У менеджеров пропали права после ночного обмена.
Запись групп заменила весь набор групп пользователя данными из выгрузки. Роли, выданные вручную, добавляют к внешним списком прямо в коде обмена.
Заказы потеряли покупателя после чистки уволенных.
Учётные записи удалялись, а не выключались, и связи с заказами оборвались. Отсутствующих в выгрузке переводят в неактивные и оставляют в базе.
Обмен падает по времени на середине выгрузки.
Все записи обрабатываются одним проходом без порций и без сохранения места. Выгрузку режут на порции по паре сотен строк и ведут журнал прохода.
Каждый обмен рассылает сотрудникам письма о смене данных.
Запись выполняется для всех строк подряд, включая неизменившиеся. Перед записью сверяют поля и обновляют только тех, у кого данные действительно изменились.
Частые вопросы
Что брать ключом сопоставления?
Внешний код из системы-источника, сохранённый в поле внешнего кода пользователя. Почта и логин меняются, а код остаётся прежним всю жизнь записи.
Как быть с паролями при создании?
Генерировать случайный пароль и отправлять человеку ссылку на его смену. Пароль из выгрузки нельзя ни хранить, ни пересылать письмом.
Почему обмен стал долгим со временем?
Обновляются все записи подряд, включая неизменившиеся, и на каждой срабатывают события. Сверка перед записью убирает большую часть работы.
Удалять ли учётные записи уволенных?
Нет, их выключают: удаление рвёт связи с заказами и историей. Полное удаление делают только по отдельному запросу на удаление персональных данных.
Куда девать сотрудников без внешнего кода?
Оставлять как есть и не трогать обменом: это ручные учётные записи. Фильтр по непустому внешнему коду отделяет их от синхронизируемых.
Смежное
-
Импорт пользователей - оглавление подтемы
-
Импорт пользователей из файла: связь, пароли, группы - разовая заливка из файла
-
Выгрузка пользователей: отбор, поля, персональные данные - обратное направление обмена
-
Синхронизация с Active Directory: подключение, отбор, группы - тот же обмен через каталог домена
-
Роли менеджеров: что видит и что может в админке - какие группы выдают руками
-
Долгая операция шагами: порции, состояние, прогресс - обработка больших выгрузок
-
Пользователи, группы и права доступа - устройство учётных записей целиком
-
Пользователь не создался при импорте: разбор причин - когда обмен не заводит учётную запись
-
Чистка учётных записей: неактивные, дубли, обезличивание - что делать с накопленным мусором
-
Учётная запись изнутри - что меняется в записи помимо строки таблицы