Как исправить ошибки группировки и передачи параметров в запросах к табличным частям в 1С:ЗУП 3.1

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

Наверняка каждый разработчик 1С на определенном этапе сталкивался с ситуацией, когда простой запрос к табличной части документа ведет себя непредсказуемо или возвращает ошибку времени выполнения. В этой статье мы подробно разберем практический кейс из реальной практики программирования в конфигурации «1С:Зарплата и управление персоналом 3.1» (ЗУП). Мы детально проанализируем, почему не отрабатывает запрос к табличной части документа ОтражениеЗарплатыВБухучете, разберем особенности группировки данных, научимся правильно передавать параметры, а также рассмотрим неочевидные проблемы, связанные с изменениями в законодательстве по страховым взносам.

Проблема №1: Неправильное использование группировки и агрегатных функций

Рассмотрим первую ошибку, с которой столкнулся автор темы. Ему требовалось сложить суммы по конкретному сотруднику в табличной части НачисленнаяЗарплатаИВзносы. Первоначальный запрос автора выглядел следующим образом:


ВЫБРАТЬ
    ОтражениеЗарплатыВБухучетеНачисленнаяЗарплатаИВзносы.Сумма КАК Сумма,
    ОтражениеЗарплатыВБухучетеНачисленнаяЗарплатаИВзносы.ФизическоеЛицо КАК ФизическоеЛицо
ИЗ
    Документ.ОтражениеЗарплатыВБухучете.НачисленнаяЗарплатаИВзносы КАК ОтражениеЗарплатыВБухучетеНачисленнаяЗарплатаИВзносы
ГДЕ
    ОтражениеЗарплатыВБухучетеНачисленнаяЗарплатаИВзносы.Ссылка = &Док
    И ОтражениеЗарплатыВБухучетеНачисленнаяЗарплатаИВзносы.ФизическоеЛицо = &Сотр

СГРУППИРОВАТЬ ПО
    ОтражениеЗарплатыВБухучетеНачисленнаяЗарплатаИВзносы.ФизическоеЛицо,
    ОтражениеЗарплатыВБухучетеНачисленнаяЗарплатаИВзносы.Сумма

Проанализируем этот код. Почему он возвращает строки без суммирования? Обратим внимание на секцию СГРУППИРОВАТЬ ПО. Автор включил туда как поле ФизическоеЛицо, так и поле Сумма. При такой конструкции СУБД группирует данные по уникальным комбинациям сотрудника и конкретной суммы. Если у одного сотрудника в документе есть две строки с суммами 10 000 и 5 000, система вернет две отдельные строки, поскольку их суммы различаются.

Выясним, как сделать правильно. Для суммирования числовых показателей необходимо использовать агрегатную функцию СУММА() в поле выбора, а в секции группировки оставлять только те поля, по разрезу которых мы хотим получить итог (в нашем случае — только по физическому лицу). Перепишем запрос правильно:


ВЫБРАТЬ
    ОтражениеЗарплатыВБухучетеНачисленнаяЗарплатаИВзносы.ФизическоеЛицо КАК ФизическоеЛицо,
    СУММА(ОтражениеЗарплатыВБухучетеНачисленнаяЗарплатаИВзносы.Сумма) КАК Сумма
ИЗ
    Документ.ОтражениеЗарплатыВБухучете.НачисленнаяЗарплатаИВзносы КАК ОтражениеЗарплатыВБухучетеНачисленнаяЗарплатаИВзносы
ГДЕ
    ОтражениеЗарплатыВБухучетеНачисленнаяЗарплатаИВзносы.Ссылка = &Док
    И ОтражениеЗарплатыВБухучетеНачисленнаяЗарплатаИВзносы.ФизическоеЛицо = &Сотр
СГРУППИРОВАТЬ ПО
    ОтражениеЗарплатыВБухучетеНачисленнаяЗарплатаИВзносы.ФизическоеЛицо

В таком виде запрос отработает корректно: он свернет все строки по выбранному сотруднику в одну и вернет общую сумму.

Проблема №2: Ошибка «Неверные параметры в операции сравнения» при передаче параметров

Перейдем ко второму запросу автора, в котором он попытался получить сумму ПФР по сотруднику, но столкнулся с ошибкой платформы:

«Неверные параметры в операции сравнения. Нельзя сравнивать поля неограниченной длины и поля несовместимых типов» в строке сравнения с параметром &Док.

Проанализируем причину возникновения этой ошибки. Как выяснилось в ходе обсуждения на форуме, в переменную Док передавался объект типа ДокументОбъект.ОтражениеЗарплатыВБухучете, а не ссылка. База данных физически не умеет сравнивать поле Ссылка таблицы базы данных с целым объектом конфигурации, содержащим множество реквизитов и табличных частей в оперативной памяти. Запрос всегда ожидает на вход уникальный идентификатор — ДокументСсылка.

Чтобы решить эту проблему, при установке параметров запроса всегда нужно передавать свойство Ссылка объекта. Посмотрим на правильный синтаксис:


// Вместо: Запрос.УстановитьПараметр("Док", Док);
// Используем:
Запрос.УстановитьПараметр("Док", Док.Ссылка);

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

ПФРдоБаза = ПолучитьСуммуПФРдо(ДЗБ.Ссылка, ФЛ);

Проблема №3: Ошибка логики и пропущенный параметр в секции ГДЕ

Обратим внимание на еще одну критическую ошибку во втором запросе автора из сообщения №3:


ГДЕ
    ОтражениеЗарплатыВБухучетеНачисленнаяЗарплатаИВзносы.ФизическоеЛицо = &Сотр
    И ОтражениеЗарплатыВБухучетеНачисленнаяЗарплатаИВзносы.Ссылка = &Док
    И ОтражениеЗарплатыВБухучетеНачисленнаяЗарплатаИВзносы.ПФРДоПредельнойВеличины = &ПФРдо

Здесь допущены сразу две серьезные ошибки:

  1. Логическая ошибка: Автор хочет вычислить и вернуть сумму ПФР из документа, но при этом в условиях фильтрации ГДЕ принудительно ограничивает выборку только теми строками, где ПФР равен входящему параметру &ПФРдо. Это делает расчет суммы через запрос абсолютно бессмысленным.
  2. Синтаксическая ошибка: В коде инициализации запроса автор устанавливает только два параметра (&Док и &Сотр), полностью забывая про параметр &ПФРдо. Как только будет исправлена ошибка с передачей ссылки, платформа незамедлительно выдаст новое исключение: «Параметр "ПФРдо" не установлен».

Решение: Полностью удалим ошибочную строку сравнения взносов из секции ГДЕ.

Проблема №4: Изменение законодательства (Единый тариф с 2023 года)

Даже если мы исправим все синтаксические ошибки в запросе автора, при работе с документами за периоды начиная с 1 января 2023 года этот запрос всегда будет возвращать 0 или пустой результат. Выясним, почему это происходит.

С 2023 года в Российской Федерации был осуществлен переход на Единый тариф страховых взносов. В связи с этим Пенсионный фонд (ПФР), Фонд социального страхования (ФСС) и Фонд обязательного медицинского страхования (ФОМС) были объединены в Единый социальный фонд (СФР).

В конфигурации «1С:ЗУП 3.1» это привело к следующим изменениям в документе ОтражениеЗарплатыВБухучете:

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

Оптимальный подход: расчет в оперативной памяти без обращения к СУБД

Проанализируем архитектуру вызова функции. Из сообщения №10 видно, что в функцию передается переменная ДЗБ, которая уже является полноценным объектом ДокументОбъект. Это означает, что документ со всеми его табличными частями уже полностью прочитан из базы данных и находится в оперативной памяти сервера.

Выполнение нового SQL-запроса к базе данных для получения данных из табличной части уже загруженного объекта — это крайне неоптимальная операция, создающая лишнюю нагрузку на СУБД. Кроме того, если пользователь редактирует документ на форме и еще не записал его, запрос к базе данных вернет старые данные из СУБД, проигнорировав изменения на экране.

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


// Альтернативный и наиболее эффективный вариант без обращения к базе данных
Функция ПолучитьСуммуВзносовВПамяти(ДокОбъект, Сотр) Экспорт
    
    // Создаем структуру отбора для поиска строк по нужному сотруднику
    ПараметрыОтбора = Новый Структура("ФизическоеЛицо", Сотр);
    
    // Находим все строки в ТЧ документа, соответствующие сотруднику
    СтрокиСотрудника = ДокОбъект.НачисленнаяЗарплатаИВзносы.НайтиСтроки(ПараметрыОтбора);
    
    СуммаВзносов = 0;
    
    Для Каждого СтрокаТЧ Из СтрокиСотрудника Цикл
        // Проверяем дату документа для обеспечения обратной совместимости
        Если ДокОбъект.ПериодРегистрации < '20230101' Тогда
            // Для периодов до 2023 года суммируем старую колонку ПФР
            СуммаВзносов = СуммаВзносов + СтрокаТЧ.ПФРДоПредельнойВеличины;
        Иначе
            // Для периодов с 2023 года используем колонку Единого тарифа
            СуммаВзносов = СуммаВзносов + СтрокаТЧ.ВзносыПоЕдиномуТарифу;
        КонецЕсли;
    КонецЦикла;
    
    // Возвращаем результат (если взносов нет, возвращаем Неопределено, как в исходном алгоритме)
    Возврат ?(СуммаВзносов > 0, СуммаВзносов, Неопределено);
    
КонецФункции

Этот метод обладает весомыми преимуществами:

  1. Высокая скорость работы: Данные обрабатываются мгновенно в оперативной памяти без отправки SQL-запросов.
  2. Актуальность данных: Метод корректно подсчитает сумму, даже если документ открыт на форме, изменен пользователем, но еще не сохранен в базу данных.
  3. Универсальность: Код корректно отработает как на исторических данных за прошлые годы, так и на новых документах, начиная с 2023 года.
← На главную