Как исправить дублирование и затирание данных при выводе начислений в отчет 1С?

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

При разработке отчетов на платформе 1С:Предприятие 8 начинающие разработчики часто сталкиваются с ситуацией, когда данные в печатной форме или табличном документе отображаются некорректно: суммы дублируются, затираются или выводится только последнее значение из списка. Особенно часто это проявляется при работе с регистрами расчета, такими как Начисления, где в одном периоде (месяце) у одного сотрудника может быть несколько различных видов расчета (оклад, больничный, пособие).

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

Анализ проблемы: почему данные «исчезают» или перезаписываются

Рассмотрим стандартную ситуацию: мы делаем запрос к регистру расчета РегистрРасчета.Начисления. В запросе настроены итоги по периоду регистрации и виду расчета. При обходе результата запроса в цикле мы пытаемся заполнить параметры области табличного документа.

Ошибка кроется в логике работы с объектом Параметры. Когда мы пишем ОбластьТаблица.Параметры.Начисления = Выборка.Результат, программа записывает значение в конкретную ячейку макета. Если в следующем шаге цикла (для того же месяца, но другого вида расчета) мы снова пишем ОбластьТаблица.Параметры.Начисления = ..., старое значение безвозвратно затирается новым. В итоге, после выполнения метода Вывести(), в строке отчета остается только результат последней итерации цикла.

Решение №1: Использование переменных-аккумуляторов

Самый простой и понятный способ для исправления ситуации при ручном обходе выборки — это внедрение дополнительных переменных, которые будут накапливать суммы внутри цикла по группировкам, и последующий вывод накопленных данных. Разберем этот алгоритм по шагам.

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


// Инициализируем переменные перед началом цикла по видам расчета
СчБольничный = 0;
СчНачисления = 0;
СчПособия = 0;

ВыборкаВидРасчета = ВыборкаПериодРегистрации.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Пока ВыборкаВидРасчета.Следующий() Цикл
    
    // Проверяем код дохода НДФЛ для классификации начисления
    Если ЗначениеЗаполнено(ВыборкаВидРасчета.ВидРасчета.КодДоходаНДФЛ) Тогда
        Если СокрЛП(ВыборкаВидРасчета.ВидРасчета.КодДоходаНДФЛ) = "2300" Тогда
            // Накапливаем сумму больничного
            СчБольничный = СчБольничный + ВыборкаВидРасчета.Результат;
        Иначе
            // Накапливаем прочие начисления
            СчНачисления = СчНачисления + ВыборкаВидРасчета.Результат;
        КонецЕсли;
    Иначе
        // Если код НДФЛ не заполнен, относим к пособиям
        СчПособия = СчПособия + ВыборкаВидРасчета.Результат;
    КонецЕсли;
    
КонецЦикла;

// Теперь, когда данные за весь месяц собраны, заполняем параметры области
ОбластьТаблица.Параметры.НачисленияБольничный = СчБольничный;
ОбластьТаблица.Параметры.Начисления = СчНачисления;
ОбластьТаблица.Параметры.НачисленияПособия = СчПособия;

// Выводим готовую строку в табличный документ
ТабличныйДокумент.Вывести(ОбластьТаблица);

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

Решение №2: Правильная иерархия выборок (Группировки vs Детальные записи)

Второй важный аспект — понимание разницы между типами обхода результата запроса. В 1С существует два основных способа: ОбходРезультатаЗапроса.ПоГруппировкам и ОбходРезультатаЗапроса.Прямой.

Проанализируем ситуацию: если в запросе используются ИТОГИ, то при выборке данных по группировке ВидРасчета мы получаем агрегированную сумму. Однако, если мы хотим видеть подробности или если логика требует обработки каждой записи, нам необходимо использовать вложенный цикл по детальным записям.

Рассмотрим правильную структуру вложенных выборок:

  1. Выборка по периодам: получаем группировку по месяцам.
  2. Выборка детальных записей: используем метод Выбрать() без параметров (прямой обход) внутри выборки по периоду.

Пример оптимизированного обхода без лишних группировок в запросе:


Пока ВыборкаПериодРегистрации.Следующий() Цикл
    
    ОбластьТаблица.Параметры.МесяцНачисления = Формат(ВыборкаПериодРегистрации.PeriodRegistracii, "ДФ='MMMM yyyy'");
    
    // Очищаем параметры перед заполнением нового месяца
    ОбластьТаблица.Параметры.НачисленияБольничный = 0;
    ОбластьТаблица.Параметры.Начисления = 0;
    ОбластьТаблица.Параметры.НачисленияПособия = 0;
    
    // Используем прямой обход для получения всех записей внутри текущего периода
    ВыборкаДетальные = ВыборкаПериодРегистрации.Выбрать();
    
    Пока ВыборкаДетальные.Следующий() Цикл
        // Здесь применяем логику распределения сумм по колонкам
        // Важно: если колонок несколько, используем суммирование (+=)
        Если ВыборкаДетальные.ВидРасчета.КодДоходаНДФЛ = "2300" Тогда
             ОбластьТаблица.Параметры.НачисленияБольничный = ОбластьТаблица.Параметры.НачисленияБольничный + ВыборкаДетальные.Результат;
        КонецЕсли;
    КонецЦикла;
    
    ТабличныйДокумент.Вывести(ОбластьТаблица);
    
КонецЦикла;

Решение №3: Перенос логики в текст запроса (SQL-way)

Профессиональным подходом считается перенос логики классификации начислений непосредственно в текст запроса. Это позволяет избежать сложных вложенных циклов в коде 1С и значительно ускоряет формирование отчета. Для этого используется конструкция ВЫБОР.

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


ВЫБРАТЬ
    Начисления.ПериодРегистрации КАК ПериодРегистрации,
    СУММА(ВЫБОР
            КОГДА Начисления.ВидРасчета.КодДоходаНДФЛ = "2300"
                ТОГДА Начисления.Результат
            ИНАЧЕ 0
        КОНЕЦ) КАК СуммаБольничный,
    СУММА(ВЫБОР
            КОГДА Начисления.ВидРасчета.КодДоходаНДФЛ <> "2300" И Начисления.ВидРасчета.КодДоходаНДФЛ <> ""
                ТОГДА Начисления.Результат
            ИНАЧЕ 0
        КОНЕЦ) КАК СуммаНачисления,
    СУММА(ВЫБОР
            КОГДА Начисления.ВидРасчета.КодДоходаНДФЛ = ""
                ТОГДА Начисления.Результат
            ИНАЧЕ 0
        КОНЕЦ) КАК СуммаПособия
ИЗ
    РегистрРасчета.Начисления КАК Начисления
ГДЕ
    Начисления.Сотрудник = &Сотрудник
    И Начисления.ПериодРегистрации МЕЖДУ &Дата1 И &Дата2
СГРУППИРОВАТЬ ПО
    Начисления.ПериодРегистрации
ИТОГИ
    СУММА(СуммаБольничный),
    СУММА(СуммаНачисления),
    СУММА(СуммаПособия)
ПО
    ОБЩИЕ,
    ПериодРегистрации ПЕРИОДАМИ(МЕСЯЦ, , )

При таком подходе в цикле 1С нам вообще не нужно проверять условия. Мы просто получаем по одной строке на каждый месяц, где уже лежат готовые просуммированные данные по всем категориям.

Важные нюансы при работе с регистрами расчета

Разберем несколько тонкостей, которые помогут избежать ошибок в будущем:

Проанализировав вышеизложенные методы, мы видим, что проблема "дублирования" чаще всего является лишь визуальным проявлением неправильного алгоритма обхода выборки. Использование накопления в переменных или агрегация данных внутри самого запроса — наиболее надежные способы получения корректной отчетности в 1С.

← На главную