При разработке произвольных отчетов по заработной плате в системе «1С:Зарплата и управление персоналом» начинающие разработчики часто совершают типичную ошибку: пытаются получить данные напрямую из документов, таких как НачислениеЗарплаты или Увольнение. Рассмотрим, почему такой подход ведет к неверным результатам, и разберем методологически верные способы получения данных через регистры.
Попытка обращения к табличным частям документов для получения сумм начислений — это путь к потере данных. Проанализируем ситуацию: начисления в 1С могут регистрироваться не только общим документом начисления зарплаты. Суммы могут проходить через документы Премия, МатериальнаяПомощь, БольничныйЛист, Отпуск, а также специфические документы увольнения. Кроме того, существуют «исправительные» документы и перерасчеты за прошлые периоды.
Если мы будем строить условие ГДЕ НачислениеЗарплаты.МесяцНачисления МЕЖДУ &ДатаНачала И &ДатаОкончания, мы неизбежно столкнемся с тем, что документ Увольнение не попадет в выборку, так как у него может быть иная структура метаданных или дата документа. Решение — всегда обращаться к Регистрам расчета или специализированным Регистрам накопления.
Основным источником данных для начислений является РегистрРасчета.Начисления. Именно здесь собираются все результаты расчетов, независимо от того, каким документом-регистратором они были сделаны. Выясним причину, по которой данные в регистре могут выглядеть «странно» на первый взгляд, например, содержать отрицательные значения.
Отрицательные суммы (Сторно) — это штатный механизм 1С. Если в текущем периоде происходит пересчет прошлого периода (например, сотруднику начислили зарплату, а потом выяснилось, что он был на больничном), система создает сторнирующую запись с минусом. Проанализируем типичную ошибку: попытку отсечь минусовые значения условием ГДЕ Результат > 0. Этого делать категорически нельзя, так как итоговая сумма за месяц окажется завышенной. Нужно всегда суммировать все записи за период регистрации.
Когда нам нужно вывести в одной строке и начисления, и удержания, мы часто используем ЛЕВОЕ СОЕДИНЕНИЕ регистра начислений с регистром удержаний по сотруднику и периоду. Посмотрим, к чему это приводит: если у сотрудника в октябре было 5 видов начислений и 2 вида удержаний, система в результате соединения создаст 10 строк (каждое начисление умножится на каждое удержание). Итоговые суммы в отчете будут завышены в несколько раз.
Разберем, как избежать этой ситуации. Вместо соединения (JOIN) следует использовать объединение (UNION ALL) с последующей группировкой.
Рассмотрим структуру запроса, который позволяет корректно собрать данные из разных источников. Мы выбираем начисления и удержания в разные блоки, дополняя каждый блок «пустыми» полями для сумм из другого блока, чтобы структуры таблиц совпали.
ВЫБРАТЬ
Начисления.Сотрудник КАК Сотрудник,
Начисления.Месяц КАК ПериодРегистрации,
Начисления.Результат КАК СуммаНачисления,
0 КАК СуммаУдержания
ИЗ
РегистрРасчета.Начисления КАК Начисления
ГДЕ
Начисления.Месяц МЕЖДУ &ДатаНачала И &ДатаОкончания
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Удержания.Сотрудник,
Удержания.ПериодРегистрации,
0,
Удержания.Результат
ИЗ
РегистрРасчета.Удержания КАК Удержания
ГДЕ
Удержания.ПериодРегистрации МЕЖДУ &ДатаНачала И &ДатаОкончания
После этого объединения мы помещаем результат во временную таблицу и делаем итоговую выборку с использованием функции СУММА и группировкой по сотруднику и периоду. Это гарантирует, что ни одна копейка не продублируется и не потеряется.
В современных версиях ЗУП 3.1 существует еще более удобный способ. Разработчики фирмы 1С создали специальный РегистрНакопления.НачисленияУдержанияПоСотрудникам. Этот регистр является «сводным» — в нем уже лежат и начисления, и удержания, и выплаты.
Проанализируем преимущества работы с этим регистром:
ОБЪЕДИНИТЬ ВСЕ или сложные соединения. Все данные уже находятся в одной таблице.ГруппаНачисленияУдержанияВыплаты позволяет легко разделять записи в запросе.Рассмотрим пример запроса к этому регистру:
ВЫБРАТЬ
ДанныеЗарплаты.Сотрудник КАК Сотрудник,
ДанныеЗарплаты.Период КАК Месяц,
СУММА(ВЫБОР
КОГДА ДанныеЗарплаты.ГруппаНачисленияУдержанияВыплаты = ЗНАЧЕНИЕ(Перечисление.ГруппыНачисленияУдержанияВыплаты.Начислено)
ТОГДА ДанныеЗарплаты.Сумма
ИНАЧЕ 0
КОНЕЦ) КАК СуммаНачисления,
СУММА(ВЫБОР
КОГДА ДанныеЗарплаты.ГруппаНачисленияУдержанияВыплаты = ЗНАЧЕНИЕ(Перечисление.ГруппыНачисленияУдержанияВыплаты.Удержано)
ТОГДА ДанныеЗарплаты.Сумма
ИНАЧЕ 0
КОНЕЦ) КАК СуммаУдержания
ИЗ
РегистрНакопления.НачисленияУдержанияПоСотрудникам.Обороты(&НачалоПериода, &КонецПериода, Месяц, ) КАК ДанныеЗарплаты
СГРУППИРОВАТЬ ПО
ДанныеЗарплаты.Сотрудник,
ДанныеЗарплаты.Период
В процессе построения отчета часто требуется рассчитать количество месяцев в выбранном периоде для вычисления средних показателей. Вместо громоздких конструкций с РАЗНОСТЬДАТ внутри запроса, рекомендуется использовать возможности Системы Компоновки Данных (СКД).
Выясним, как это сделать эффективнее: на закладке «Вычисляемые поля» или в выражениях ресурсов можно использовать функции языка выражений СКД. Это позволит избежать ошибок при расчете периодов, которые не кратны полному месяцу. Также не забывайте про регистр ТекущиеКадровыеДанныеСотрудников. Однако помните, что он содержит данные на текущий момент. Если вам нужна должность, которую сотрудник занимал именно в месяце начисления (исторические данные), необходимо использовать срез последних регистра сведений КадроваяИсторияСотрудников на каждую дату периода.
Подводя итог, отметим: для создания качественного отчета по зарплате забудьте про документы. Используйте РегистрНакопления.НачисленияУдержанияПоСотрудникам для получения сумм и ПериодРегистрации для фильтрации по датам. Это обеспечит точность данных и высокую скорость работы вашего отчета.