Как связать график отпусков и фактические отпуска в запросе 1С:ЗУП 3.1

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом IT и автоматизация бизнеса
← На главную

При разработке кадровых отчетов и доработке печатных форм (например, унифицированной формы Т-7 «График отпусков») в программе «1С:Зарплата и управление персоналом 3.1» программисты часто сталкиваются с задачей: как вывести в одной таблице плановые даты отпуска из утвержденного графика и фактические даты документов Отпуск, которые были проведены в течение года.

На первый взгляд задача кажется простой — достаточно написать запрос к табличной части документа ГрафикОтпусков.Сотрудники и связать его левым соединением с документами Отпуск. Однако на практике такой подход приводит к тому, что при малейшем сдвиге дат (если сотрудник ушел в отпуск на день раньше или позже плана, либо если отпуск был перенесен) связь разрывается, и фактические данные не выводятся. В этой статье мы подробно разберем, как правильно решить эту задачу, используя механизмы платформы 1С и регистры системы.

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

Рассмотрим типичную ошибку, которую совершают начинающие разработчики. Попытаемся связать табличную часть документа ГрафикОтпусков с документом Отпуск напрямую по полям Сотрудник и ДатаНачала. Проанализируем пример такого запроса:


ВЫБРАТЬ
    ГрафикОтпусковСотрудники.Сотрудник КАК Сотрудник,
    "План" КАК ВидОтпуска,
    ГрафикОтпусковСотрудники.ДатаНачала КАК ДатаНачалаПлан,
    КОНЕЦПЕРИОДА(ГрафикОтпусковСотрудники.ДатаОкончания, ДЕНЬ) КАК ДатаОкончанияПлан,
    ГрафикОтпусковСотрудники.КоличествоДней КАК КоличествоДнейПлан,
    Отпуск.Ссылка КАК ДокументФакта,
    Отпуск.ДатаНачалаОсновногоОтпуска КАК ДатаНачалаФакт,
    Отпуск.ДатаОкончанияОсновногоОтпуска КАК ДатаОкончанияФакт
ИЗ
    Документ.ГрафикОтпусков.Сотрудники КАК ГрафикОтпусковСотрудники
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.Отпуск КАК Отпуск
        ПО ГрафикОтпусковСотрудники.Сотрудник = Отпуск.Сотрудник
        И ГрафикОтпусковСотрудники.ДатаНачала = Отпуск.ДатаНачалаОсновногоОтпуска
ГДЕ
    ГрафикОтпусковСотрудники.Ссылка.Проведен
    И ГрафикОтпусковСотрудники.Ссылка = &Ссылка

Выясним, почему этот запрос не будет работать в реальной базе данных:

  1. Сдвиг дат. В реальной жизни сотрудники редко уходят в отпуск строго день в день по графику, утвержденному в декабре предыдущего года. Если в графике стоит дата 15 июня, а сотрудник ушел 17 июня — условие соединения ГрафикОтпусковСотрудники.ДатаНачала = Отпуск.ДатаНачалаОсновногоОтпуска вернет ложь, и фактический отпуск не сопоставится с плановым.
  2. Множественность документов. Документ Отпуск может содержать как основной, так и дополнительный отпуск, даты которых могут пересекаться или отличаться. Попытка привязаться к полям ДатаНачалаОсновногоОтпуска проигнорирует дополнительные отпуска.
  3. Переносы отпусков. Если в программе был зарегистрирован документ Перенос отпуска, плановые даты в самом графике остаются прежними (они не редактируются в проведенном документе), но фактический отпуск проводится уже по новым датам.

Архитектура учета отпусков в 1С:ЗУП 3.1

Для того чтобы построить корректный и надежный запрос, нам необходимо обратиться к архитектуре регистров «1С:ЗУП 3.1». Разработчики фирмы «1С» предусмотрели специальные регистры, в которых фиксируются плановые и фактические показатели движения отпусков. Данные в этих регистрах стандартизированы, что позволяет сопоставлять их без привязки к конкретным реквизитам шапки документов.

Проанализируем ключевые регистры системы:

Методика 1: Сопоставление по рабочему году (периоду предоставления)

Наиболее методологически верным способом связать плановые и фактические отпуска является сопоставление по рабочему периоду (рабочему году), за который предоставляется отпуск. Каждому запланированному и фактически использованному дню отпуска всегда сопутствуют реквизиты начала и окончания рабочего года.

Рассмотрим, как реализовать такое соединение в запросе по шагам:

  1. Выбираем плановые отпуска сотрудников из регистра сведений ПлановыеЕжегодныеОтпуска или табличной части конкретного графика отпусков. При этом обязательно выбираем поля НачалоРабочегоГода и КонецРабочегоГода.
  2. Выбираем фактические движения из регистра накопления ФактическиеОтпуска. В этом регистре нас интересуют измерения Сотрудник, ВидОтпуска, а также реквизиты рабочего года.
  3. Соединяем эти таблицы по равенству сотрудника, вида отпуска и границ рабочего года.

Посмотрим на пример практической реализации такого запроса:


ВЫБРАТЬ
    ПлановыеЕжегодныеОтпуска.Сотрудник КАК Сотрудник,
    ПлановыеЕжегодныеОтпуска.ВидОтпуска КАК ВидОтпуска,
    ПлановыеЕжегодныеОтпуска.ДатаНачала КАК ДатаНачалаПлан,
    ПлановыеЕжегодныеОтпуска.ДатаОкончания КАК ДатаОкончанияПлан,
    ПлановыеЕжегодныеОтпуска.КоличествоДней КАК КоличествоДнейПлан,
    ПлановыеЕжегодныеОтпуска.НачалоРабочегоГода КАК НачалоРабочегоГода,
    ПлановыеЕжегодныеОтпуска.КонецРабочегоГода КАК КонецРабочегоГода
ПОМЕСТИТЬ ВТ_План
ИЗ
    РегистрСведений.ПлановыеЕжегодныеОтпуска КАК ПлановыеЕжегодныеОтпуска
ГДЕ
    ПлановыеЕжегодныеОтпуска.ДокументОснование = &ДокументГрафикОтпусков
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ФактическиеОтпуска.Сотрудник КАК Сотрудник,
    ФактическиеОтпуска.ВидОтпуска КАК ВидОтпуска,
    ФактическиеОтпуска.Регистратор КАК ДокументФакт,
    ФактическиеОтпуска.Период КАК ДатаНачалаФакт,
    ФактическиеОтпуска.Количество КАК КоличествоДнейФакт,
    ФактическиеОтпуска.РабочийГодНачало КАК РабочийГодНачало,
    ФактическиеОтпуска.РабочийГодКонец КАК РабочийГодКонец
ПОМЕСТИТЬ ВТ_Факт
ИЗ
    РегистрНакопления.ФактическиеОтпуска КАК ФактическиеОтпуска
ГДЕ
    ФактическиеОтпуска.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Расход)
    И ФактическиеОтпуска.Сотрудник В (ВЫБРАТЬ РАЗЛИЧНЫЕ ВТ_План.Сотрудник ИЗ ВТ_План)
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_План.Сотрудник КАК Сотрудник,
    ВТ_План.ВидОтпуска КАК ВидОтпуска,
    ВТ_План.ДатаНачалаПлан КАК ДатаНачалаПлан,
    ВТ_План.ДатаОкончанияПлан КАК ДатаОкончанияПлан,
    ВТ_План.КоличествоДнейПлан КАК КоличествоДнейПлан,
    ВТ_План.НачалоРабочегоГода КАК РабочийГодНачало,
    ВТ_План.КонецРабочегоГода КАК РабочийГодКонец,
    ВТ_Факт.ДокументФакт КАК ДокументФакт,
    ВТ_Факт.ДатаНачалаФакт КАК ДатаНачалаФакт,
    ВТ_Факт.КоличествоДнейФакт КАК КоличествоДнейФакт
ИЗ
    ВТ_План КАК ВТ_План
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Факт КАК ВТ_Факт
        ПО ВТ_План.Сотрудник = ВТ_Факт.Сотрудник
        И ВТ_План.ВидОтпуска = ВТ_Факт.ВидОтпуска
        И ВТ_План.НачалоРабочегоГода = ВТ_Факт.РабочийГодНачало
        И ВТ_План.КонецРабочегоГода = ВТ_Факт.РабочийГодКонец
УПОРЯДОЧИТЬ ПО
    Сотрудник,
    ДатаНачалаПлан

Этот метод является наиболее точным с точки зрения методологии кадрового учета, так как программа жестко контролирует остатки отпусков именно в разрезе рабочих лет сотрудника.

Методика 2: Сопоставление по вхождению в интервал дат

Бывают ситуации, когда в информационной базе по каким-то причинам не ведется детальный учет в разрезе рабочих лет (например, после некорректного переноса данных), либо необходимо сопоставить план и факт исключительно по временной близости событий. В этом случае мы можем применить левое соединение по условию попадания фактической даты начала отпуска в определенный интервал относительно плановой даты начала.

Проанализируем пример такого соединения, где допускается погрешность, например, в 14 или 30 дней:


ВЫБРАТЬ
    ГрафикСотрудники.Сотрудник КАК Сотрудник,
    ГрафикСотрудники.ДатаНачала КАК ДатаНачалаПлан,
    ГрафикСотрудники.ДатаОкончания КАК ДатаОкончанияПлан,
    ГрафикСотрудники.КоличествоДней КАК КоличествоДнейПлан,
    Отпуск.Ссылка КАК ДокументФакт,
    Отпуск.ДатаНачалаОсновногоОтпуска КАК ДатаНачалаФакт,
    Отпуск.ДатаОкончанияОсновногоОтпуска КАК ДатаОкончанияФакт
ИЗ
    Документ.ГрафикОтпусков.Сотрудники КАК ГрафикСотрудники
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.Отпуск КАК Отпуск
        ПО ГрафикСотрудники.Сотрудник = Отпуск.Сотрудник
        И Отпуск.Проведен
        // Задаем интервал: фактический отпуск начался не ранее чем за 15 дней до плана
        И Отпуск.ДатаНачалаОсновногоОтпуска >= ДОБАВИТЬКДАТЕ(ГрафикСотрудники.ДатаНачала, ДЕНЬ, -15)
        // и не позднее чем через 15 дней после запланированной даты
        И Отпуск.ДатаНачалаОсновногоОтпуска <= ДОБАВИТЬКДАТЕ(GraphicSotrudniki.ДатаНачала, ДЕНЬ, 15)
ГДЕ
    ГрафикСотрудники.Ссылка = &Ссылка

Важное предупреждение: Данный способ следует использовать с осторожностью. Если сотрудник планировал сходить в отпуск дважды за год на короткие периоды (например, в мае и в июне), то при большой величине интервала фактический майский отпуск может ошибочно привязаться к плановому июньскому периоду.

Нюансы, которые необходимо учесть при разработке отчета

Для создания надежного и отказоустойчивого алгоритма вывода печатной формы «График отпусков» необходимо учитывать особенности кадрового учета в «1С:ЗУП 3.1»:

Применяя предложенные методики работы с регистрами вместо прямого связывания документов, вы сможете создавать гибкие и безотказные отчеты, которые корректно отобразят плановые и фактические данные по отпускам ваших сотрудников при любых кадровых изменениях.

← На главную