В процессе разработки в конфигурации «1С:Зарплата и управление персоналом 3.1» часто возникает задача определить список сотрудников, которые обязаны присутствовать на рабочем месте в определенную дату. На первый взгляд задача кажется простой — достаточно проверить график работы. Однако на практике необходимо учитывать множество нюансов: индивидуальные графики, документы «Табель», праздничные дни, а также фактические отсутствия сотрудников (больничные, отпуска, командировки).
В этой статье мы разберем несколько профессиональных способов решения этой задачи: от использования типовых программных интерфейсов (API) до написания прямых запросов к регистрам системы.
Наиболее корректным и современным методом в 1С:ЗУП является использование процедур общего модуля УчетРабочегоВремениРасширенный или УчетРабочегоВремени. Эти модули содержат функции, которые автоматически учитывают и плановые графики, и их корректировки, и фактически введенные документы отклонений.
Рассмотрим по шагам, как подготовить данные и получить таблицу сотрудников, работающих в конкретный период. Основная идея заключается в использовании временных таблиц, в которые система выгружает расчетные данные о времени.
Для реализации этого метода нам потребуется создать МенеджерВременныхТаблиц и подготовить структуру параметров. Разберем пример кода:
&НаСервере
Процедура ПолучитьСписокВыходящихНаРаботу(ВыбраннаяДата)
ПараметрыПолученияДанных = УчетРабочегоВремениРасширенный.ПараметрыПолученияДанныхУчетаВремени();
ПараметрыПолученияДанных.ДатаНачала = НачалоДня(ВыбраннаяДата);
ПараметрыПолученияДанных.ДатаОкончания = КонецДня(ВыбраннаяДата);
// Указываем, что нам нужен именно план по графику
ПараметрыПолученияДанных.ПолучатьПлан = Истина;
МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
// В реальной задаче здесь нужно заполнить массив сотрудников, по которым нужен анализ
// Если нужно по всем — предварительно формируем таблицу всех актуальных сотрудников
МассивСотрудников = СформироватьМассивВсехСотрудников();
// Создаем ВТ со списком сотрудников для анализа
СоздатьВТСотрудники(МенеджерВременныхТаблиц, МассивСотрудников, ВыбраннаяДата);
// Вызываем типовой метод заполнения данных
УчетРабочегоВремениРасширенный.СоздатьВТДанныеУчетаРабочегоВремениСотрудников(МенеджерВременныхТаблиц, Истина, ПараметрыПолученияДанных);
// Извлекаем результат
Запрос = Новый Запрос("ВЫБРАТЬ * ИЗ ВТДанныеУчетаРабочегоВремениСотрудников ГДЕ Явка > 0");
Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
ТаблицаРезультат = Запрос.Выполнить().Выгрузить();
КонецПроцедуры
В данном примере функция СоздатьВТДанныеУчетаРабочегоВремениСотрудников выполняет всю «тяжелую» работу: соединяет графики, учитывает индивидуальные графики и возвращает количество часов в колонке Явка. Если значение больше нуля — сотрудник должен быть на работе.
Если вам нужно решение, максимально приближенное к тому, как система заполняет документ «Табель», можно обратиться к функционалу менеджера этого документа. В модуле менеджера Документ.Табель существуют функции ВыборкаДанныхОВремени или ТаблицаДанныхДляЗаполнения.
Проанализируем преимущества этого подхода:
Однако этот способ может быть избыточным, если вам нужен простой список имен без детального разбора часов по видам учета времени.
Для случаев, когда нужно быстро получить данные по большому количеству сотрудников без вызова тяжелых процедур, мы можем написать запрос к регистру сведений ДанныеГрафикаРаботыСотрудников. Этот регистр является «разверткой» графиков и содержит информацию в разрезе сотрудников и дат.
Выясним причину, почему нельзя просто выбрать данные из этого регистра. Дело в том, что регистр хранит плановое время. Если сотрудник по графику должен выйти, но в этот день он находится в отпуске, запись в регистре ДанныеГрафикаРаботыСотрудников все равно будет содержать часы явки. Поэтому запрос нужно строить с учетом регистра СостоянияСотрудников.
Рассмотрим структуру такого запроса:
ВЫБРАТЬ
Графики.Сотрудник,
Графики.Дата,
Графики.Значение КАК ЧасыЯвки
ПОМЕСТИТЬ ВТ_План
ИЗ
РегистрСведений.ДанныеГрафикаРаботыСотрудников КАК Графики
ГДЕ
Графики.Дата = &НужнаяДата
И Графики.Значение > 0
И Графики.ВидУчетаВремени = ЗНАЧЕНИЕ(Справочник.ВидыИспользованияРабочегоВремени.Явка);
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_План.Сотрудник
ИЗ
ВТ_План КАК ВТ_План
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СостоянияСотрудников КАК Состояния
ПО ВТ_План.Сотрудник = Состояния.Сотрудник
И (&НужнаяДата МЕЖДУ Состояния.ДействуетДо И Состояния.ДатаНачала)
// Здесь требуется более сложная логика проверки пересечения периодов
ГДЕ
Состояния.Состояние ЕСТЬ NULL ИЛИ Состояния.Состояние = ЗНАЧЕНИЕ(Перечисление.СостоянияСотрудника.Работа)
Важный момент: при использовании прямых запросов к регистрам СостоянияСотрудников помните, что записи там могут перекрываться, и для корректного исключения отсутствующих лучше использовать временные таблицы, подготовленные типовым методом ЗарплатаКадрыСоставОбщегоНазначения.СоздатьВТДанныеСостоянийСотрудников.
Подведем итог. Выбор метода зависит от ваших целей:
УчетРабочегоВремениРасширенный.ДанныеГрафикаРаботыСотрудников.Не забывайте, что в ЗУП 3.1 понятия «должен выйти» и «числится в штате» — это разные вещи. Всегда проверяйте вид времени в графике, так как сотрудник может «работать» по графику, но это будет «Вахта» или «Работа в выходной», что требует отдельной обработки в коде.