При работе в программе 1С:Зарплата и управление персоналом (ЗУП) 3.1 пользователи и разработчики часто сталкиваются с ситуацией, когда отчет Фактические отпуска по конкретному сотруднику оказывается пустым, хотя данные в системе заведены. Разберем ситуацию, когда это происходит при наличии двух и более исправлений одного и того же отпуска (цепочка исправлений). Проанализируем причину такого поведения системы и рассмотрим способы исправления этой программной ошибки.
Проблема кроется в логике формирования временных таблиц при инициализации отчета. Проанализируем фрагмент типового кода запроса, который отвечает за исключение сторнированных записей. Система пытается найти пары «прямая запись — сторно-запись» и исключить их из итоговой выборки. Рассмотрим, как это выглядит в коде:
|ВЫБОР
| КОГДА НЕ ФактическиеОтпускаСторно.Сотрудник ЕСТЬ NULL
| И ФактическиеОтпуска.Количество > 0
| ТОГДА ИСТИНА
| ИНАЧЕ ЛОЖЬ
|КОНЕЦ КАК СторнируемаяЗапись,
|ВЫБОР
| КОГДА НЕ ФактическиеОтпускаСторно.Сотрудник ЕСТЬ NULL
| И ФактическиеОтпуска.Количество < 0
| ТОГДА ИСТИНА
| ИНАЧЕ ЛОЖЬ
|КОНЕЦ КАК СторноЗапись
|ПОМЕСТИТЬ ВТФактическиеОтпускаСоСторноПризнаками
|ИЗ
| ВТФактическиеОтпуска КАК ФактическиеОтпуска
| ЛЕВОЕ СОЕДИНЕНИЕ ВТФактическиеОтпуска КАК ФактическиеОтпускаСторно
| ПО ФактическиеОтпуска.Сотрудник = ФактическиеОтпускаСторно.Сотрудник
| И ФактическиеОтпуска.ВидЕжегодногоОтпуска = ФактическиеОтпускаСторно.ВидЕжегодногоОтпуска
| И ФактическиеОтпуска.ДатаНачала = ФактическиеОтпускаСторно.ДатаНачала
| И ФактическиеОтпуска.ДатаОкончания = ФактическиеОтпускаСторно.ДатаОкончания
| И (ФактическиеОтпуска.Количество = -ФактическиеОтпускаСторно.Количество)
| И ФактическиеОтпуска.Регистратор <> ФактическиеОтпускаСторно.Регистратор
Затем в финальном запросе записи, помеченные как СторнируемаяЗапись или СторноЗапись, отсекаются простым фильтром ГДЕ НЕ СторнируемаяЗапись И НЕ СторноЗапись. Эта логика идеально работает для схемы «один первичный документ — одно исправление», но полностью ломается при возникновении цепочки исправлений.
Рассмотрим на конкретном примере, что происходит в регистре накопления ФактическиеОтпуска, когда документ исправляется дважды (например, из-за пересчета среднего заработка после начисления годовой премии):
Когда выполняется ЛЕВОЕ СОЕДИНЕНИЕ таблицы самой с собой по условию Количество = -Количество, для записи из Документа №2 (+12 дней) находится пара в Документе №3 (-12 дней). Обе записи получают флаги сторно и исключаются. Однако, если количество дней в цепочке совпадает (например, в обоих исправлениях было по 12 дней), то из-за множественного соединения «всех со всеми» по датам и количеству, под исключение может попасть даже финальная, актуальная запись. В результате отчет по сотруднику становится абсолютно пустым.
Самым надежным способом решения проблемы является отказ от попыток найти «пару» для каждой записи. Вместо этого проанализируем возможность свертки данных по ключевым полям. Выясним, какие поля определяют уникальность отпуска: это Сотрудник, ВидЕжегодногоОтпуска, ДатаНачала, ДатаОкончания и РабочийПериод.
Перепишем узел запроса, заменив соединение на группировку:
ВЫБРАТЬ
ФактическиеОтпуска.Сотрудник КАК Сотрудник,
ФактическиеОтпуска.ВидЕжегодногоОтпуска КАК ВидЕжегодногоОтпуска,
ФактическиеОтпуска.ДатаНачала КАК ДатаНачала,
ФактическиеОтпуска.ДатаОкончания КАК ДатаОкончания,
СУММА(ФактическиеОтпуска.Количество) КАК КоличествоДней,
ФактическиеОтпуска.РабочийПериодС КАК РабочийПериодС,
ФактическиеОтпуска.РабочийПериодПо КАК РабочийПериодПо
ИЗ
ВТФактическиеОтпуска КАК ФактическиеОтпуска
СГРУППИРОВАТЬ ПО
ФактическиеОтпуска.Сотрудник,
ФактическиеОтпуска.ВидЕжегодногоОтпуска,
ФактическиеОтпуска.ДатаНачала,
ФактическиеОтпуска.ДатаОкончания,
ФактическиеОтпуска.РабочийПериодС,
ФактическиеОтпуска.РабочийПериодПо
ИМЕЮЩИЕ
СУММА(ФактическиеОтпуска.Количество) <> 0
Такой подход автоматически «схлопывает» все промежуточные исправления и сторно-записи, оставляя только итоговый остаток дней по конкретному периоду отпуска. Важно: при суммировании мы теряем прямую ссылку на Регистратор, если он выводится в детальных записях. Для отчетов, где важна ссылка на документ, потребуется дополнительное соединение для получения актуального (последнего по времени) регистратора.
В регистре накопления Фактические отпуска существует поле Основание. При создании цепочки исправлений это поле зачастую ссылается на самый первый, исходный документ отпуска. Рассмотрим алгоритм фильтрации с учетом этого поля:
Основание.МоментомВремени или максимальным периодом регистрации.Если вы столкнулись с отсутствием данных в отчете, выполните следующие действия для проверки:
Фактические отпуска.Активность. Убедитесь, что все записи активны.Таким образом, для корректного отображения фактических отпусков в условиях частых пересчетов (например, при выплате квартальных или годовых премий, влияющих на средний заработок прошлых периодов), типовой запрос отчета требует модификации в части обработки сторно-записей. Использование агрегатной функции СУММА с группировкой по измерениям является наиболее стабильным программным решением данной проблемы.