Top.Mail.Ru
Центр помощи / Для администратора / 4. Интеграции / Синхронизация пользователей / 1С: Синхронизация пользователей – как устроен скрипт

1С: Синхронизация пользователей – как устроен скрипт

Скрипт выбора данных — вторая половина обработки UnSpot SCIM Adapter: код на встроенном языке 1С, который выбирает из информационной базы сотрудников, подразделения и руководителей. Скрипт один, а описан в двух статьях по назначению. Эта статья — про часть, которая выбирает сотрудников и собирает их поля: блоки 1–4 и 8 встроенного скрипта для конфигурации «ЗУП 3.1 (ПРОФ/КОРП)». Организации, подразделения и руководители (блоки 0 и 5–7) разобраны в статье 1С: Синхронизация оргструктуры – как устроен скрипт; нумерация блоков в обеих статьях общая. Как подключить и настроить обмен — в статье 1С: Синхронизация пользователей – настройка интеграции, как обработка отправляет выбранные данные — в статье 1С: Синхронизация пользователей – как устроен обработчик.

Кратко

  • Скрипт — часть обработки 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Когда есть в структуре
userNameEmail сотрудника в нижнем регистреКлюч сопоставления и адрес пользователя в UnSpot. По нему обработка находит сотрудника среди пользователей UnSpot; у нового пользователя это его email. В режимах без externalId — единственный ключВсегда
externalIdИдентификатор физлица в 1С — строка из 36 символовПривязывает пользователя UnSpot к физлицу 1С. Благодаря ему сотрудник после смены email обновляется, а не дублируется; по нему же определяют, кого из пользователей UnSpot больше нет в 1С и кого нужно удалитьРежим «Полная»
familyNameФамилияФамилия в карточке пользователя UnSpotКроме режима «Только обновление оргструктуры»
givenNameИмя. Отчество не передаётсяИмя в карточке пользователя UnSpotКроме режима «Только обновление оргструктуры»
titleНаименование должностиДолжность в карточке пользователя UnSpotКроме режима «Только обновление оргструктуры»
employeeIdТабельный номерТабельный номер в карточке пользователя UnSpotКроме режима «Только обновление оргструктуры»
orgUnitПолный путь подразделения через / — от верхнего уровня до подразделения сотрудникаОпределяет подразделение пользователя: UnSpot находит в дереве подразделение с таким путём или создаёт его вместе с недостающими родителями и помещает в него сотрудникаФлажок «Оргструктура» включён
departmentНаименование подразделения без иерархииUnSpot воспринимает его как путь из одного уровня: находит подразделение с таким названием или создаёт его на верхнем уровне и помещает в него сотрудника. Дерево не строится, описание и руководитель подразделения не передаютсяФлажок «Оргструктура» выключен
managerEmail руководителя подразделения сотрудника; пустое значение — «руководителя нет»UnSpot назначает сотруднику руководителя с этим email. Пустое значение снимает ранее назначенного руководителяФлажок «Менеджер» включён
attendanceДоля офисных дней текущего месяца — целое от 0 до 100; если данных нет — пустоПо ней UnSpot определяет режим работы сотрудника: 0 — только удалённо, 100 — только офис, от 1 до 99 — гибридный, пусто — свободныйФлажок «Режим работы» включён

Для наглядности — одна структура целиком (условный пример для режима «Полная» при включённых флажках «Оргструктура», «Менеджер» и «Режим работы»):

ПолеПример значения
externalIda1b2c3d4-0000-4000-8000-0123456789ab
userNameivanov@company.ru
familyNameИванов
givenNameИван
titleМенеджер по продажам
employeeId00123
orgUnitПродажи/Региональный отдел
managerpetrova@company.ru
attendance75

Служебные поля структуры

Пока скрипт работает, в структуре лежат ещё пять служебных значений. Они нужны только самому скрипту и перед формированием массива удаляются (блок 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: руководитель

Откуда. Руководителя сотрудника скрипт не ищет в карточке сотрудника — он берёт руководителя его подразделения. Для этого значение собирается в три шага, в разных блоках:

  1. блок 3 запоминает в служебном поле orgUnitId идентификатор подразделения сотрудника;
  2. блоки 5–7 строят соответствие ПодразделенияПоИдентификатору, где у каждого подразделения есть поле manager — email его руководителя (как он вычисляется, описано в статье 1С: Синхронизация оргструктуры – как устроен скрипт);
  3. блок 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 в несколько шагов:

  1. Период расчёта — текущий календарный месяц, с первого до последнего числа, независимо от даты запуска.
  2. Берутся данные графиков работы сотрудников за месяц: общий график и индивидуальный. Если по индивидуальному графику сотрудника набрались дни с кодами Я или Д, они полностью заменяют для него общий график.
  3. В расчёт попадают только дни, у которых вид учёта времени имеет буквенный код Я или Д. Если у самого вида кода нет, берётся код его основного вида времени. Отпуск, больничный, командировка и другие виды времени не учитываются — они не считаются ни офисными, ни дистанционными.
  4. День с кодом Д считается дистанционным. День с кодом Я считается офисным, кроме случая, когда на эту дату действует период дистанционной работы по трудовому договору (регистр «Дистанционная работа сотрудников») — тогда день тоже дистанционный. Если на одну дату приходится несколько записей, побеждает офисный день.
  5. Показатель равен числу офисных дней, умноженному на 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 — это делает код обработки.
  • Не записывает ничего в информационную базу: он только читает данные.
  • Не передаёт отчество, телефон, дату рождения, паспортные данные, сведения о зарплате и причины отсутствий — их нет в списке запрашиваемых реквизитов.
  • Не удаляет пользователей и подразделения напрямую: он лишь отдаёт актуальный список, а удаление пропавших выполняет обработка по правилам режима синхронизации.

Связанные статьи

Оставьте заявку, и мы свяжемся с вами в течение 30 минут.

Loading

Как улучшить работу офиса?

Оставьте контакт - покажем на демо как уйти от таблиц, двойных бронирований и путаницы с рабочими местами.

Loading