1С: Синхронизация пользователей – как устроен скрипт
Скрипт выбора данных — вторая половина обработки UnSpot SCIM Adapter: код на встроенном языке 1С, который выбирает из информационной базы сотрудников, подразделения и руководителей. Скрипт один, а описан в двух статьях по назначению. Эта статья — про часть, которая выбирает сотрудников и собирает их поля: блоки 1–4 и 8 встроенного скрипта для конфигурации «ЗУП 3.1 (ПРОФ/КОРП)». Организации, подразделения и руководители (блоки 0 и 5–7) разобраны в статье 1С: Синхронизация оргструктуры – как устроен скрипт; нумерация блоков в обеих статьях общая. Как подключить и настроить обмен — в статье 1С: Синхронизация пользователей – настройка интеграции, как обработка отправляет выбранные данные — в статье 1С: Синхронизация пользователей – как устроен обработчик.
Содержание
Где находится скрипт и как он запускается
Какие настройки формы видит скрипт
Какой массив данных собирает скрипт
Как собирается каждое поле сотрудника
Поле externalId: идентификатор физлица
Поля familyName, givenName, title, employeeId: данные из карточки сотрудника
Поля orgUnit и department: подразделение
Поле attendance: доля офисных дней
Как собирается итоговый массив
Кратко
- Скрипт — часть обработки UnSpot SCIM Adapter: текст на встроенном языке 1С. Он выбирает из ЗУП действующих сотрудников с email и собирает по каждому данные для UnSpot.
- Результат — массив
СотрудникиДляUnspot: одна запись на человека (физлицо), даже если у него несколько должностей. - В записи — email и подразделение, а в зависимости от режима и флажков — идентификатор физлица, фамилия и имя, должность, табельный номер, email руководителя и доля офисных дней.
- Сам скрипт ничего в UnSpot не отправляет: сравнивает и отправляет обработка.
- Ниже сначала описаны поля массива и откуда берётся каждое, затем — блоки скрипта (свёрнуты).
- Незнакомое слово — загляните в раздел Термины статьи-обзора.
Где находится скрипт и как он запускается
Скрипт — это текст в поле «Код выбора данных для синхронизации» формы настроек обработки. Если в поле «Конфигурация 1С» выбрано «ЗУП 3.1 (ПРОФ/КОРП)», поле доступно только для просмотра, а текст скрипта обновляется вместе с обработкой. Если выбрана «Нестандартная конфигурация», поле редактируется, и ваш код выполняется вместо встроенного.
В начале каждого запуска обработка выполняет текст скрипта в том сеансе 1С, где идёт синхронизация. На выходе скрипт оставляет массив СотрудникиДляUnspot — по одной структуре на сотрудника — и, если включён флажок «Оргструктура», массив ОргструктураДляUnspot — по одной структуре на подразделение. Отправкой этих массивов в UnSpot занимается сама обработка, а не скрипт: что и как она отправляет, описано в статье 1С: Синхронизация пользователей – как устроен обработчик.
Что учитывать. Скрипт выполняется без ограничений безопасного режима и с правами пользователя, от имени которого идёт синхронизация. Относитесь к правке этого поля как к правке кода конфигурации и ограничьте доступ к форме настроек администраторами.
Какие настройки формы видит скрипт
Значения полей формы настроек обработка передаёт скрипту в виде готовых переменных. Задавать их в скрипте не нужно — именно поэтому один и тот же скрипт работает во всех режимах.
| Переменная | Что это | Значения |
|---|---|---|
СинхронизацияПользователей | Режим синхронизации из формы настроек | РежимыСинхронизацииПользователей.Полная — «Полная»; РежимыСинхронизацииПользователей.Обновление — «Только обновление»; РежимыСинхронизацииПользователей.Оргструктура — «Только обновление оргструктуры» |
СинхронизироватьОргструктуру | Флажок «Оргструктура» | Истина или Ложь |
СинхронизироватьМенеджера | Флажок «Менеджер» | Истина или Ложь |
СинхронизироватьРежимРаботы | Флажок «Режим работы» | Истина или Ложь |
Схема работы скрипта
Скрипт состоит из девяти блоков. Блоки идут сверху вниз в том порядке, в котором они перечислены в таблице; часть блоков выполняется только при включённых флажках. В этой статье разобраны блоки 1–4 и 8, блоки 0 и 5–7 — в статье 1С: Синхронизация оргструктуры – как устроен скрипт.
| № | Блок | Что делает | Когда выполняется |
|---|---|---|---|
| 0 | Подготовка | Решает, включать ли название головной организации в путь подразделений | Всегда |
| 1 | Выбор сотрудников | Получает действующих сотрудников с заполненным email | Всегда |
| 2 | Одно место работы | Из нескольких позиций одного физлица оставляет одну | Всегда |
| 3 | Запись сотрудника | Собирает структуру с полями для UnSpot | Всегда |
| 4 | Режим работы | Считает долю офисных дней | Флажок «Режим работы» |
| 5 | Организации | Строит записи оргструктуры для организаций и находит их руководителей | Флажок «Оргструктура» или «Менеджер» |
| 6 | Руководители подразделений | Собирает email руководителей по подразделениям | Флажок «Оргструктура» или «Менеджер» |
| 7 | Подразделения | Строит записи оргструктуры для подразделений | Флажок «Оргструктура» или «Менеджер» |
| 8 | Руководитель сотрудника и результат | Записывает сотруднику email руководителя его подразделения, убирает служебные поля, формирует массивы | Всегда; руководитель — при флажке «Менеджер» |
Какой массив данных собирает скрипт
Результат работы скрипта — массив СотрудникиДляUnspot. Когда скрипт отработал, обработка в вашу базу уже не заглядывает: она берёт этот готовый массив, сопоставляет его с пользователями UnSpot и отправляет изменения. Поэтому от скрипта нужно одно — собрать массив так, чтобы каждого сотрудника можно было однозначно найти, создать или обновить.
Массив состоит из структур — по одной на каждого сотрудника, который должен быть в UnSpot. Структура — это набор пар «имя поля — значение»; имена полей совпадают с названиями полей SCIM-запроса, в которые обработка их потом превращает. Физлицо, которое работает сразу на нескольких позициях, представлено одной структурой: лишние позиции отсеиваются в блоке 2. Уволенные сотрудники и сотрудники без email в массив не попадают. Единственное исключение — руководитель организации, которого скрипт добавляет отдельной записью (см. поле manager).
Что обработка делает с массивом, зависит от режима синхронизации:
- «Полная» — сотрудника ищут сначала по
externalId, затем поuserName. Не найденного создают, найденного с изменившимися полями обновляют, а пользователей UnSpot, у которых естьexternalId, но которых нет в массиве, архивируют (в UnSpot такой пользователь не стирается, а уходит в архив); - «Только обновление» и «Только обновление оргструктуры» — ищут только по
userName. Создания и удаления нет: обновляются лишь те, кто уже есть в UnSpot.
Подробно, с запросами и ответами, — в статье 1С: Синхронизация пользователей – как устроен обработчик. Если включён флажок «Оргструктура», скрипт собирает ещё и второй массив — ОргструктураДляUnspot; он описан в статье 1С: Синхронизация оргструктуры – как устроен скрипт.
Поля структуры сотрудника
В таблице — все поля, которые скрипт кладёт в структуру сотрудника, и то, зачем каждое из них нужно UnSpot. Какие поля реально окажутся в структуре, зависит от режима и флажков формы: это указано в последней колонке.
| Поле | Что содержит | Зачем оно нужно UnSpot | Когда есть в структуре |
|---|---|---|---|
userName | Email сотрудника в нижнем регистре | Ключ сопоставления и адрес пользователя в UnSpot. По нему обработка находит сотрудника среди пользователей UnSpot; у нового пользователя это его email. В режимах без externalId — единственный ключ | Всегда |
externalId | Идентификатор физлица в 1С — строка из 36 символов | Привязывает пользователя UnSpot к физлицу 1С. Благодаря ему сотрудник после смены email обновляется, а не дублируется; по нему же определяют, кого из пользователей UnSpot больше нет в 1С и кого нужно удалить | Режим «Полная» |
familyName | Фамилия | Фамилия в карточке пользователя UnSpot | Кроме режима «Только обновление оргструктуры» |
givenName | Имя. Отчество не передаётся | Имя в карточке пользователя UnSpot | Кроме режима «Только обновление оргструктуры» |
title | Наименование должности | Должность в карточке пользователя UnSpot | Кроме режима «Только обновление оргструктуры» |
employeeId | Табельный номер | Табельный номер в карточке пользователя UnSpot | Кроме режима «Только обновление оргструктуры» |
orgUnit | Полный путь подразделения через / — от верхнего уровня до подразделения сотрудника | Определяет подразделение пользователя: UnSpot находит в дереве подразделение с таким путём или создаёт его вместе с недостающими родителями и помещает в него сотрудника | Флажок «Оргструктура» включён |
department | Наименование подразделения без иерархии | UnSpot воспринимает его как путь из одного уровня: находит подразделение с таким названием или создаёт его на верхнем уровне и помещает в него сотрудника. Дерево не строится, описание и руководитель подразделения не передаются | Флажок «Оргструктура» выключен |
manager | Email руководителя подразделения сотрудника; пустое значение — «руководителя нет» | UnSpot назначает сотруднику руководителя с этим email. Пустое значение снимает ранее назначенного руководителя | Флажок «Менеджер» включён |
attendance | Доля офисных дней текущего месяца — целое от 0 до 100; если данных нет — пусто | По ней UnSpot определяет режим работы сотрудника: 0 — только удалённо, 100 — только офис, от 1 до 99 — гибридный, пусто — свободный | Флажок «Режим работы» включён |
Для наглядности — одна структура целиком (условный пример для режима «Полная» при включённых флажках «Оргструктура», «Менеджер» и «Режим работы»):
| Поле | Пример значения |
|---|---|
externalId | a1b2c3d4-0000-4000-8000-0123456789ab |
userName | ivanov@company.ru |
familyName | Иванов |
givenName | Иван |
title | Менеджер по продажам |
employeeId | 00123 |
orgUnit | Продажи/Региональный отдел |
manager | petrova@company.ru |
attendance | 75 |
Служебные поля структуры
Пока скрипт работает, в структуре лежат ещё пять служебных значений. Они нужны только самому скрипту и перед формированием массива удаляются (блок 8), так что в UnSpot не уходят.
| Служебное поле | Что содержит | Для чего нужно скрипту |
|---|---|---|
typePriority | Приоритет вида занятости — число от 0 до 4 | Выбор одной позиции из нескольких у одного физлица (блок 2) |
rate | Количество ставок | Выбор позиции, если приоритеты видов занятости равны (блок 2) |
hiredAt | Дата приёма | Участвует в условии выбора позиции (блок 2), но на результат не влияет: при равных приоритетах условие по ставкам срабатывает раньше, чем дело доходит до даты |
orgUnitId | Идентификатор подразделения сотрудника | Поиск руководителя подразделения в блоке 8; кладётся только при включённом флажке «Менеджер» |
entity | Ссылка на элемент справочника «Сотрудники» | Выбор графиков работы сотрудника при расчёте attendance (блок 4) |
Как собирается каждое поле сотрудника
Почти все поля собирает один цикл по выборке сотрудников (блок 3). Исключения — attendance и manager: их значения достраиваются после цикла, в блоках 4 и 8. Ниже для каждого поля показано, откуда берётся значение, как оно вычисляется и какой фрагмент кода за это отвечает. Листинги — куски встроенного скрипта без комментариев; полные блоки — в разделе Разбор по блокам. Многоточие в листинге означает пропущенные строки.
Исходные данные цикл берёт из переменной СотрудникиКД — результата блока 1. В ней по одной строке на каждую позицию сотрудника; из реквизитов строки СотрудникКД и собираются поля структуры:
| Реквизит строки | Что это | В какое поле идёт |
|---|---|---|
Сотрудник | Ссылка на элемент справочника «Сотрудники» | Служебное entity |
ФизическоеЛицо | Ссылка на элемент справочника «Физические лица» | externalId |
Подразделение | Подразделение сотрудника | orgUnit, department, служебное orgUnitId |
Должность | Ссылка на элемент справочника «Должности» | title |
КоличествоСтавок, ВидЗанятости, ДатаПриема | Количество ставок, вид занятости, дата приёма | Служебные rate, typePriority, hiredAt |
Фамилия, Имя | Фамилия и имя из кадровых данных | familyName, givenName |
EMailПредставление | Адрес электронной почты | userName |
ТабельныйНомер | Табельный номер | employeeId |
Поле userName: email
Откуда. Реквизит EMailПредставление из кадровых данных (блок 1). Если у физлица несколько адресов, скрипт сам адрес не выбирает: он берёт то, что вернули кадровые данные.
Как вычисляется. Значение приводится к нижнему регистру функцией НРег, чтобы Ivanov@Company.ru и ivanov@company.ru считались одним адресом. Пустого email в этом поле не бывает: сотрудники без email отсекаются ещё при выборке, отбором EMailПредставление <> "".
ЗарплатаКадрыОбщиеНаборыДанных.ДобавитьВКоллекциюОтбор(ПараметрыПолучения.Отборы, "EMailПредставление", "<>", """""", Ложь);
...
ЭлементСотрудника.Вставить("userName", НРег(СотрудникКД.EMailПредставление));1СПоле externalId: идентификатор физлица
Откуда. Элемент справочника «Физические лица», на который ссылается строка выборки.
Как вычисляется. Метод УникальныйИдентификатор() возвращает идентификатор элемента справочника, функция Строка превращает его в текст из 36 символов. Идентификатор не меняется при смене фамилии, должности или email. Тот же текст служит ключом соответствия ПользователиПоИдентификатору, по которому блок 2 отсеивает дубли по физлицу. В структуру поле попадает только в режиме «Полная».
ИдФизЛица = Строка(СотрудникКД.ФизическоеЛицо.УникальныйИдентификатор());
...
Если СинхронизацияПользователей = РежимыСинхронизацииПользователей.Полная Тогда
ЭлементСотрудника.Вставить("externalId", ИдФизЛица);
КонецЕсли;1СПоля familyName, givenName, title, employeeId: данные из карточки сотрудника
Откуда. Реквизиты Фамилия, Имя, Должность и ТабельныйНомер той позиции, которую блок 2 оставил для физлица. Отчество скрипт не запрашивает, поэтому оно никогда не передаётся.
Как вычисляется. Фамилия, имя и табельный номер копируются как есть. Должность в кадровых данных — ссылка на справочник «Должности», поэтому берётся её наименование. Все четыре поля записываются одним условием: они нужны всегда, кроме режима «Только обновление оргструктуры» — там обновляется только подразделение.
Если СинхронизацияПользователей <> РежимыСинхронизацииПользователей.Оргструктура Тогда
ЭлементСотрудника.Вставить("familyName", СотрудникКД.Фамилия);
ЭлементСотрудника.Вставить("givenName", СотрудникКД.Имя);
ЭлементСотрудника.Вставить("title", СотрудникКД.Должность.Наименование);
ЭлементСотрудника.Вставить("employeeId", СотрудникКД.ТабельныйНомер);
КонецЕсли;1СПоля orgUnit и department: подразделение
Откуда. Реквизит Подразделение строки выборки. Какое из двух полей будет в структуре, решает флажок «Оргструктура»: при включённом передаётся orgUnit, при выключенном — department. Одновременно они не передаются.
Как вычисляется department. Берётся наименование подразделения — одно название, без родителей.
Как вычисляется orgUnit. Функция ПолучитьИерархиюПодразделенийВСтроке поднимается по цепочке родителей подразделения, склеивая наименования через /, а затем дописывает слева организацию-владельца — вместе с головной, если она не является корнем пути. Корень пути задаёт второй параметр: если в базе несколько головных организаций (флаг ВключитьГоловнуюОрганизациюВИерархию из блока 0), корня нет и путь начинается с головной организации; если головная одна, корнем считается она, и в путь её название не входит.
Подразделение = СотрудникКД.Подразделение;
...
Если СинхронизироватьОргструктуру Тогда
ЭлементСотрудника.Вставить(
"orgUnit",
ПолучитьИерархиюПодразделенийВСтроке(Подразделение, ?(ВключитьГоловнуюОрганизациюВИерархию, Неопределено, Подразделение.ГоловнаяОрганизация))
);
Иначе
ЭлементСотрудника.Вставить("department", Подразделение.Наименование);
КонецЕсли;1СФункция, которая строит путь, входит в состав обработки, а не в текст скрипта:
Функция ПолучитьИерархиюПодразделенийВСтроке(Знач Элемент, КорневойЭлемент=Неопределено)
Результат = Элемент.Наименование;
Пока Не Элемент.Родитель.Пустая() И Элемент.Родитель <> КорневойЭлемент Цикл
Элемент = Элемент.Родитель;
Результат = Элемент.Наименование + "/" + Результат;
КонецЦикла;
Если Элемент.Владелец <> Неопределено И Не Элемент.Владелец.Пустая() И Элемент.Владелец <> КорневойЭлемент Тогда
Результат = ПолучитьИерархиюОрганизацийВСтроке(Элемент.Владелец, КорневойЭлемент) + "/" + Результат;
КонецЕсли;
Возврат Результат;
КонецФункции1СПоле manager: руководитель
Откуда. Руководителя сотрудника скрипт не ищет в карточке сотрудника — он берёт руководителя его подразделения. Для этого значение собирается в три шага, в разных блоках:
- блок 3 запоминает в служебном поле
orgUnitIdидентификатор подразделения сотрудника; - блоки 5–7 строят соответствие
ПодразделенияПоИдентификатору, где у каждого подразделения есть полеmanager— email его руководителя (как он вычисляется, описано в статье 1С: Синхронизация оргструктуры – как устроен скрипт); - блок 8 ищет подразделение сотрудника в этом соответствии и записывает email руководителя в поле
manager.
Как вычисляется. Идентификатор подразделения сотрудника (orgUnitId) запоминается и итоговое поле manager подставляется только при включённом флажке «Менеджер». Сам же сбор руководителей по организациям и подразделениям (блоки 5–7) выполняется, если включён хотя бы один из флажков «Оргструктура» и «Менеджер». Руководитель записывается, если у подразделения он есть и это не сам сотрудник. Если руководителя нет или он совпал с сотрудником, в поле записывается пустое значение. Пустое значение — не «ничего не менять», а команда снять руководителя. Если же у сотрудника вообще нет подразделения, поле manager в структуру не попадает.
Если СинхронизироватьМенеджера И Подразделение <> Неопределено Тогда
ЭлементСотрудника.Вставить("orgUnitId", Строка(Подразделение.УникальныйИдентификатор()));
КонецЕсли;
...
Если СинхронизироватьМенеджера И ПользовательПоИдентификаторуКЗ.Значение.Свойство("orgUnitId") Тогда
ИдПодразделения = ПользовательПоИдентификаторуКЗ.Значение["orgUnitId"];
Если ИдПодразделения <> Неопределено
И ПодразделенияПоИдентификатору[ИдПодразделения] <> Неопределено
И ПодразделенияПоИдентификатору[ИдПодразделения]["manager"] <> Неопределено
И ПодразделенияПоИдентификатору[ИдПодразделения]["manager"] <> ПользовательПоИдентификаторуКЗ.Значение["userName"]
Тогда
ПользовательПоИдентификаторуКЗ.Значение.Вставить("manager", ПодразделенияПоИдентификатору[ИдПодразделения]["manager"]);
Иначе
ПользовательПоИдентификаторуКЗ.Значение.Вставить("manager", Неопределено);
КонецЕсли;
КонецЕсли;1СЧто учитывать. Email руководителя берётся из контактной информации его физлица — это первый адрес типа «Адрес электронной почты», а не обязательно тот, что стоит в EMailПредставление и попадает в userName руководителя. Если адреса различаются, обработка не найдёт среди активных пользователей UnSpot человека с таким email. Тогда поле manager в запрос не уходит вовсе: новый руководитель не назначается, а прежний, если он был, не снимается.
Поле attendance: доля офисных дней
Откуда. Графики работы сотрудников за текущий календарный месяц: общий график — по регистру сведений ГрафикиРаботыПоВидамВремени с привязкой графика к сотруднику по регистру ГрафикРаботыСотрудников, индивидуальный — по регистру накопления ДанныеИндивидуальныхГрафиковСотрудников. Поле добавляется после цикла, в блоке 4, процедурой ЗаполнитьРежимРаботыСогласноГрафикуРаботы; она входит в состав обработки, а не в текст скрипта. Скрипт лишь сообщает ей, какие буквенные коды видов учёта времени считать офисными, а какие — дистанционными.
Как вычисляется. Для каждого дня месяца определяется, офисный он или дистанционный. Вид учёта времени дня должен иметь буквенный код Я или Д — свой или, если у вида кода нет, код его основного вида. День с кодом Д — дистанционный. День с кодом Я — офисный, если только на эту дату не действует период дистанционной работы по трудовому договору: тогда он тоже дистанционный. Если внутри одного графика на одну дату приходится несколько записей, побеждает офисный день. Графики между собой не складываются: если у сотрудника в индивидуальном графике есть хотя бы один день с кодом Я или Д, этот график целиком заменяет общий для него на весь месяц, и дни общего графика не учитываются, даже на те даты, где в индивидуальном ничего нет. Затем считается доля офисных дней среди учтённых, округляется до целого, и результат записывается в поле.
Коды задаются в самом скрипте, в блоке 4:
Если СинхронизироватьРежимРаботы Тогда
БуквенныеКодыОчныхВидовУчетаВремени = Новый Массив();
БуквенныеКодыОчныхВидовУчетаВремени.Добавить("Я");
БуквенныеКодыДистанционныхВидовУчетаВремени = Новый Массив();
БуквенныеКодыДистанционныхВидовУчетаВремени.Добавить("Д");
ЗаполнитьРежимРаботыСогласноГрафикуРаботы(ПользователиПоИдентификатору, БуквенныеКодыОчныхВидовУчетаВремени, БуквенныеКодыДистанционныхВидовУчетаВремени);
КонецЕсли;1СКлассификация одного дня:
Если БуквенныеКодыДистанционныхВидовУчетаВремени.Найти(БуквенныйКодВидаУчетаВремени) <> Неопределено Тогда
СтатусВидаУчетаВремени = Ложь;
Иначе
СтатусВидаУчетаВремени = Истина;
Если ДистанционнаяПоСотруднику <> Неопределено
И ДистанционнаяПоСотруднику.Получить(ИдСотрудника) <> Неопределено
Тогда
СтатусДистанционнойРаботы = Ложь;
Для Каждого ДистанционныйПериод Из ДистанционнаяПоСотруднику.Получить(ИдСотрудника) Цикл
Если НачалоДня(ДистанционныйПериод.Период) > СтрокаТЗ.Дата Тогда
Прервать;
ИначеЕсли
Не ЗначениеЗаполнено(ДистанционныйПериод.ДатаОкончания)
Или НачалоДня(ДистанционныйПериод.ДатаОкончания) > СтрокаТЗ.Дата
Тогда
СтатусДистанционнойРаботы = ДистанционныйПериод.Статус;
КонецЕсли;
КонецЦикла;
Если СтатусДистанционнойРаботы Тогда
СтатусВидаУчетаВремени = Ложь;
КонецЕсли;
КонецЕсли;
КонецЕсли;
Если ДниПоСотруднику.Получить(ДатаФорматированная) = Неопределено Тогда
ДниПоСотруднику.Вставить(ДатаФорматированная, СтатусВидаУчетаВремени);
ИначеЕсли СтатусВидаУчетаВремени Тогда
ДниПоСотруднику.Вставить(ДатаФорматированная, СтатусВидаУчетаВремени);
КонецЕсли;1СИтоговая формула. Если ни одного учтённого дня нет, значение остаётся пустым:
Если Статусы = Неопределено Или Статусы.Количество() = 0 Тогда
Сотрудник.Значение.Вставить("attendance", Неопределено);
Продолжить;
КонецЕсли;
...
Сотрудник.Значение.Вставить("attendance", Окр(КоличествоОФисныхДней * 100 / Статусы.Количество()));1СПошаговое описание расчёта и пример — в разделе «Блок 4. Режим работы» (раздел Разбор по блокам).
Как собирается итоговый массив
Цикл блока 3 складывает структуры в соответствие ПользователиПоИдентификатору: ключ — идентификатор физлица, значение — структура сотрудника. Пока соответствие не превращено в массив, в структурах лежат служебные поля. Блок 8 для каждой структуры достраивает manager, удаляет служебные поля и добавляет структуру в массив СотрудникиДляUnspot.
СотрудникиДляUnspot = Новый Массив;
Для Каждого ПользовательПоИдентификаторуКЗ Из ПользователиПоИдентификатору Цикл
Если СинхронизироватьМенеджера И ПользовательПоИдентификаторуКЗ.Значение.Свойство("orgUnitId") Тогда
ИдПодразделения = ПользовательПоИдентификаторуКЗ.Значение["orgUnitId"];
Если ИдПодразделения <> Неопределено
И ПодразделенияПоИдентификатору[ИдПодразделения] <> Неопределено
И ПодразделенияПоИдентификатору[ИдПодразделения]["manager"] <> Неопределено
И ПодразделенияПоИдентификатору[ИдПодразделения]["manager"] <> ПользовательПоИдентификаторуКЗ.Значение["userName"]
Тогда
ПользовательПоИдентификаторуКЗ.Значение.Вставить("manager", ПодразделенияПоИдентификатору[ИдПодразделения]["manager"]);
Иначе
ПользовательПоИдентификаторуКЗ.Значение.Вставить("manager", Неопределено);
КонецЕсли;
КонецЕсли;
ПользовательПоИдентификаторуКЗ.Значение.Удалить("typePriority");
ПользовательПоИдентификаторуКЗ.Значение.Удалить("rate");
ПользовательПоИдентификаторуКЗ.Значение.Удалить("hiredAt");
ПользовательПоИдентификаторуКЗ.Значение.Удалить("orgUnitId");
ПользовательПоИдентификаторуКЗ.Значение.Удалить("entity");
СотрудникиДляUnspot.Добавить(ПользовательПоИдентификаторуКЗ.Значение);
КонецЦикла;1СРазбор по блокам
Ниже блоки 1–4 и 8 описаны и показаны так, как они выглядят в поле «Код выбора данных для синхронизации»; вспомогательные комментарии в листингах опущены.
Блоки свёрнуты, чтобы не мешать чтению: нажмите на название блока, чтобы раскрыть его описание и листинг.
Блок 1. Выбор сотрудников
Метод КадровыйУчет.СотрудникиОрганизации возвращает только действующих (не уволенных) сотрудников на текущую дату. Из кадровых данных запрашиваются: сотрудник, физлицо, подразделение, должность, количество ставок, вид занятости, фамилия, имя, email, табельный номер и дата приёма. К выборке добавлен отбор по заполненному email: сотрудники без email не синхронизируются, потому что email — ключ, по которому UnSpot сопоставляет учётные записи.
ПараметрыПолучения = КадровыйУчет.ПараметрыПолученияСотрудниковОрганизацийПоСпискуФизическихЛиц();
ПараметрыПолучения.КадровыеДанные = "Сотрудник,ФизическоеЛицо,Подразделение,Должность,КоличествоСтавок,ВидЗанятости,Фамилия,Имя,EMailПредставление,ТабельныйНомер,ДатаПриема";
ПараметрыПолучения.НачалоПериода = ТекущаяДата();
ПараметрыПолучения.ОкончаниеПериода = ТекущаяДата();
ЗарплатаКадрыОбщиеНаборыДанных.ДобавитьВКоллекциюОтбор(ПараметрыПолучения.Отборы, "EMailПредставление", "<>", """""", Ложь);
СотрудникиКД = КадровыйУчет.СотрудникиОрганизации(Истина, ПараметрыПолучения);1СБлок 2. Одно место работы на физлицо
Если физлицо работает сразу на нескольких позициях (основное место и совместительство), в UnSpot должна попасть одна учётная запись. Для выбора позиции скрипт присваивает каждому виду занятости приоритет: чем число выше, тем важнее позиция.
| Вид занятости | Приоритет |
|---|---|
| Основное место работы | 4 |
| Внутреннее совместительство | 3 |
| Совместительство | 2 |
| Подработка | 1 |
| Любой другой вид | 0 |
Побеждает позиция с более высоким приоритетом, а при равном приоритете — с большим количеством ставок. Если и приоритет, и количество ставок совпали, остаётся позиция, которая встретилась в выборке первой. Условие записано внутри цикла по сотрудникам: оно пропускает позицию, которая «слабее» уже выбранной.
ПриоритетВидовЗанятости = Новый Соответствие;
ПриоритетВидовЗанятости.Вставить(Перечисления.ВидыЗанятости.Подработка, 1);
ПриоритетВидовЗанятости.Вставить(Перечисления.ВидыЗанятости.Совместительство, 2);
ПриоритетВидовЗанятости.Вставить(Перечисления.ВидыЗанятости.ВнутреннееСовместительство, 3);
ПриоритетВидовЗанятости.Вставить(Перечисления.ВидыЗанятости.ОсновноеМестоРаботы, 4);
ПользователиПоИдентификатору = Новый Соответствие;
Для Каждого СотрудникКД Из СотрудникиКД Цикл
ИдФизЛица = Строка(СотрудникКД.ФизическоеЛицо.УникальныйИдентификатор());
ПриоритетВидаЗанятости = 0;
Если ПриоритетВидовЗанятости[СотрудникКД.ВидЗанятости] <> Неопределено Тогда
ПриоритетВидаЗанятости = ПриоритетВидовЗанятости[СотрудникКД.ВидЗанятости];
КонецЕсли;
Если
ПользователиПоИдентификатору[ИдФизЛица] <> Неопределено
И (
ПользователиПоИдентификатору[ИдФизЛица]["typePriority"] > ПриоритетВидаЗанятости
ИЛИ ПользователиПоИдентификатору[ИдФизЛица]["typePriority"] = ПриоритетВидаЗанятости
И (
ПользователиПоИдентификатору[ИдФизЛица]["rate"] >= СотрудникКД.КоличествоСтавок
ИЛИ ПользователиПоИдентификатору[ИдФизЛица]["rate"] = СотрудникКД.КоличествоСтавок
И ПользователиПоИдентификатору[ИдФизЛица]["hiredAt"] >= СотрудникКД.ДатаПриема
)
)
Тогда
Продолжить;
КонецЕсли;1СЧто учитывать. Если в вашей конфигурации есть дополнительные виды занятости, добавьте их в соответствие приоритетов — иначе они получат приоритет 0 и проиграют любой из перечисленных.
Блок 3. Запись сотрудника
Для каждой выбранной позиции собирается структура с полями для UnSpot. Состав полей зависит от режима: идентификатор физлица (externalId) добавляется только в режиме «Полная», а фамилия, имя, должность и табельный номер — во всех режимах, кроме «Только обновление оргструктуры». Вместо пути подразделения (orgUnit) при выключенном флажке «Оргструктура» передаётся только его название (department). Email записывается в нижнем регистре.
Кроме полей для UnSpot, в структуру кладутся служебные значения: приоритет вида занятости, количество ставок, дата приёма, идентификатор подразделения (при флажке «Менеджер») и ссылка на сотрудника. Они нужны скрипту для следующих блоков и удаляются перед отправкой в блоке 8.
ЭлементСотрудника = Новый Структура;
Если СинхронизацияПользователей = РежимыСинхронизацииПользователей.Полная Тогда
ЭлементСотрудника.Вставить("externalId", ИдФизЛица);
КонецЕсли;
ЭлементСотрудника.Вставить("userName", НРег(СотрудникКД.EMailПредставление));
Если СинхронизацияПользователей <> РежимыСинхронизацииПользователей.Оргструктура Тогда
ЭлементСотрудника.Вставить("familyName", СотрудникКД.Фамилия);
ЭлементСотрудника.Вставить("givenName", СотрудникКД.Имя);
ЭлементСотрудника.Вставить("title", СотрудникКД.Должность.Наименование);
ЭлементСотрудника.Вставить("employeeId", СотрудникКД.ТабельныйНомер);
КонецЕсли;
ЭлементСотрудника.Вставить("entity", СотрудникКД.Сотрудник);
Подразделение = СотрудникКД.Подразделение;
Если СинхронизироватьМенеджера И Подразделение <> Неопределено Тогда
ЭлементСотрудника.Вставить("orgUnitId", Строка(Подразделение.УникальныйИдентификатор()));
КонецЕсли;
Если СинхронизироватьОргструктуру Тогда
ЭлементСотрудника.Вставить(
"orgUnit",
ПолучитьИерархиюПодразделенийВСтроке(Подразделение, ?(ВключитьГоловнуюОрганизациюВИерархию, Неопределено, Подразделение.ГоловнаяОрганизация))
);
Иначе
ЭлементСотрудника.Вставить("department", Подразделение.Наименование);
КонецЕсли;
ЭлементСотрудника.Вставить("typePriority", ПриоритетВидаЗанятости);
ЭлементСотрудника.Вставить("rate", СотрудникКД.КоличествоСтавок);
ЭлементСотрудника.Вставить("hiredAt", СотрудникКД.ДатаПриема);
ПользователиПоИдентификатору.Вставить(ИдФизЛица, ЭлементСотрудника);1СБлок 4. Режим работы
При включённом флажке «Режим работы» скрипт задаёт два набора буквенных кодов видов учёта времени и вызывает процедуру ЗаполнитьРежимРаботыСогласноГрафикуРаботы. Процедура входит в состав обработки, а не в текст скрипта; в скрипте задаются только коды: Я — явка (работа в офисе) и Д — дистанционная работа.
Если СинхронизироватьРежимРаботы Тогда
БуквенныеКодыОчныхВидовУчетаВремени = Новый Массив();
БуквенныеКодыОчныхВидовУчетаВремени.Добавить("Я");
БуквенныеКодыДистанционныхВидовУчетаВремени = Новый Массив();
БуквенныеКодыДистанционныхВидовУчетаВремени.Добавить("Д");
ЗаполнитьРежимРаботыСогласноГрафикуРаботы(ПользователиПоИдентификатору, БуквенныеКодыОчныхВидовУчетаВремени, БуквенныеКодыДистанционныхВидовУчетаВремени);
КонецЕсли;1СПроцедура считает показатель attendance в несколько шагов:
- Период расчёта — текущий календарный месяц, с первого до последнего числа, независимо от даты запуска.
- Берутся данные графиков работы сотрудников за месяц: общий график и индивидуальный. Если по индивидуальному графику сотрудника набрались дни с кодами
ЯилиД, они полностью заменяют для него общий график. - В расчёт попадают только дни, у которых вид учёта времени имеет буквенный код
ЯилиД. Если у самого вида кода нет, берётся код его основного вида времени. Отпуск, больничный, командировка и другие виды времени не учитываются — они не считаются ни офисными, ни дистанционными. - День с кодом
Дсчитается дистанционным. День с кодомЯсчитается офисным, кроме случая, когда на эту дату действует период дистанционной работы по трудовому договору (регистр «Дистанционная работа сотрудников») — тогда день тоже дистанционный. Если на одну дату приходится несколько записей, побеждает офисный день. - Показатель равен числу офисных дней, умноженному на 100 и делённому на число учтённых дней, и округляется до целого. Если ни одного учтённого дня нет, значение не определено и передаётся пустым.
Пример. В июле у сотрудника 20 дней с кодами Я и Д, из них 15 — Я. Показатель равен 15 × 100 / 20 = 75: в UnSpot сотрудник получит гибридный режим работы.
Блоки 0 и 5–7: организации, подразделения и руководители
Эти блоки строят дерево организаций и подразделений и собирают их руководителей; построчный разбор и код — в статье 1С: Синхронизация оргструктуры – как устроен скрипт. Для сотрудника важен результат: соответствие ПодразделенияПоИдентификатору, в котором для каждой организации и подразделения лежат поля path, manager и description. Из него блок 8 берёт email руководителя. Блоки 5–7 выполняются, если включён хотя бы один из флажков «Оргструктура» или «Менеджер».
Блок 8. Руководитель сотрудника и результат
Первая половина цикла выполняется при флажке «Менеджер»: сотруднику в поле manager записывается email руководителя его подразделения. Если у подразделения руководителя нет или руководитель — сам сотрудник, в manager записывается пустое значение. Пустое значение — это не «ничего не менять», а команда снять руководителя: если в UnSpot у сотрудника был руководитель, а в 1С его больше нет, назначение будет очищено.
Затем из каждой структуры удаляются служебные поля — приоритет вида занятости, ставка, дата приёма, идентификатор подразделения и ссылка на сотрудника, — чтобы наружу ушли только поля для UnSpot. Готовые структуры собираются в массив СотрудникиДляUnspot, а при флажке «Оргструктура» подразделения из соответствия — в массив ОргструктураДляUnspot.
СотрудникиДляUnspot = Новый Массив;
Для Каждого ПользовательПоИдентификаторуКЗ Из ПользователиПоИдентификатору Цикл
Если СинхронизироватьМенеджера И ПользовательПоИдентификаторуКЗ.Значение.Свойство("orgUnitId") Тогда
ИдПодразделения = ПользовательПоИдентификаторуКЗ.Значение["orgUnitId"];
Если ИдПодразделения <> Неопределено
И ПодразделенияПоИдентификатору[ИдПодразделения] <> Неопределено
И ПодразделенияПоИдентификатору[ИдПодразделения]["manager"] <> Неопределено
И ПодразделенияПоИдентификатору[ИдПодразделения]["manager"] <> ПользовательПоИдентификаторуКЗ.Значение["userName"]
Тогда
ПользовательПоИдентификаторуКЗ.Значение.Вставить("manager", ПодразделенияПоИдентификатору[ИдПодразделения]["manager"]);
Иначе
ПользовательПоИдентификаторуКЗ.Значение.Вставить("manager", Неопределено);
КонецЕсли;
КонецЕсли;
ПользовательПоИдентификаторуКЗ.Значение.Удалить("typePriority");
ПользовательПоИдентификаторуКЗ.Значение.Удалить("rate");
ПользовательПоИдентификаторуКЗ.Значение.Удалить("hiredAt");
ПользовательПоИдентификаторуКЗ.Значение.Удалить("orgUnitId");
ПользовательПоИдентификаторуКЗ.Значение.Удалить("entity");
СотрудникиДляUnspot.Добавить(ПользовательПоИдентификаторуКЗ.Значение);
КонецЦикла;
Если СинхронизироватьОргструктуру Тогда
ОргструктураДляUnspot = Новый Массив;
Для Каждого ПодразделениеПоИдентификаторуКЗ Из ПодразделенияПоИдентификатору Цикл
ОргструктураДляUnspot.Добавить(ПодразделениеПоИдентификаторуКЗ.Значение);
КонецЦикла;
КонецЕсли;1СЧто можно менять в нестандартной конфигурации
Для нестандартной конфигурации за основу берётся копия встроенного скрипта: всё, что вы не меняли, продолжает работать как описано выше. Требования к собственному скрипту — обязательные поля и вспомогательные функции — описаны в статье 1С: Собственный скрипт – настройка интеграции.
| Что менять | Где | На что обратить внимание |
|---|---|---|
| Список реквизитов сотрудника и отбор | Блок 1 | Названия реквизитов должны существовать в вашей конфигурации; email остаётся обязательным |
| Приоритеты видов занятости | Блок 2 | Добавьте новые виды занятости, иначе они получат приоритет 0 |
| Поля сотрудника | Блок 3 | Не убирайте обязательные поля: userName всегда, для режима «Полная» также externalId, familyName и givenName |
| Коды видов учёта времени | Блок 4 | Коды Я и Д должны совпадать с буквенными кодами видов времени в вашей конфигурации |
| Служебные поля | Блок 8 | Если вы добавили служебные поля для собственных расчётов, удалите их перед формированием массивов |
После любой правки нажмите «Сохранить и проверить»: обработка выполнит пробную выборку и покажет, сколько сотрудников выбрано. Если число отличается от ожидаемого, проверьте email сотрудников и условия отбора в блоке 1. Что менять в части скрипта про подразделения — в статье 1С: Синхронизация оргструктуры – как устроен скрипт.
Чего скрипт не делает
- Не отправляет данные в UnSpot и не читает данные UnSpot — это делает код обработки.
- Не записывает ничего в информационную базу: он только читает данные.
- Не передаёт отчество, телефон, дату рождения, паспортные данные, сведения о зарплате и причины отсутствий — их нет в списке запрашиваемых реквизитов.
- Не удаляет пользователей и подразделения напрямую: он лишь отдаёт актуальный список, а удаление пропавших выполняет обработка по правилам режима синхронизации.
Связанные статьи
- 1С: Синхронизация пользователей – настройка интеграции — требования, подключение, поля формы, регулярный запуск и диагностика.
- 1С: Синхронизация пользователей – как устроен обработчик — протокол, отправляемые данные, создание, обновление и удаление пользователей.
- 1С: Синхронизация оргструктуры – как устроен скрипт — разбор блоков про организации, подразделения и руководителей.
- 1С: Собственный скрипт – настройка интеграции — как написать скрипт для нестандартной конфигурации.
- 1С: Обзор интеграции — какие бывают интеграции с 1С и с чего начать.