При разработке механизмов автоматического расчета в 1С программисты часто сталкиваются с ситуацией, когда запрос, написанный в консоли запросов, работает корректно, но в коде процедуры результат оказывается «пустым» или приводит к ошибкам. Рассмотрим детально, почему так происходит, на примере работы с виртуальными таблицами регистров бухгалтерии и обработкой полученных данных.
Одной из самых распространенных ошибок является попытка обратиться к результату запроса, выгруженному в таблицу значений, напрямую через имя колонки. Проанализируем фрагмент кода:
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
МенеджерЗаписи.Перерасход = РезультатЗапроса.КоличествоОборотДт / Запись.Пробег * 100;
В данном случае РезультатЗапроса — это объект типа ТаблицаЗначений. Когда мы пишем РезультатЗапроса.КоличествоОборотДт, система обращается не к конкретному числу, а к объекту КолонкаТаблицыЗначений. Попытка выполнить арифметическую операцию с колонкой (объектом) вместо числа не приведет к результату или вызовет ошибку в зависимости от контекста. Для получения суммы по всей колонке необходимо использовать метод Итог() или обращаться к конкретной строке таблицы.
Рассмотрим правильный подход к обработке выгруженной таблицы значений. Прежде чем выполнять вычисления, необходимо убедиться, что запрос вернул хотя бы одну строку, и использовать агрегатные функции таблицы. Разберем исправленный вариант кода:
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
Если РезультатЗапроса.Количество() > 0 Тогда
// Используем метод Итог для получения суммы по колонке
СуммаОборота = РезультатЗапроса.Итог("КоличествоОборотДт");
// Обязательная проверка на деление на ноль
Если Запись.Пробег <> 0 Тогда
МенеджерЗаписи.Перерасход = СуммаОборота / Запись.Пробег * 100;
Иначе
МенеджерЗаписи.Перерасход = 0;
КонецЕсли;
КонецЕсли;
Если код выше все равно не выводит результат, проблема может крыться в параметрах самого запроса. Проанализируем настройки виртуальной таблицы РегистрБухгалтерии.Хозрасчетный.Обороты.
1. Порядок и состав субконто
В запросе используется параметр &Субконто, куда передается массив видов субконто. Важно помнить, что в 1С порядок следования Субконто1, Субконто2 в запросе жестко привязан к порядку видов субконто в переданном массиве, а не к их физическому расположению на счете. Если в массиве первым идет «Номенклатура», а в запросе вы ожидаете «Склад» в Субконто1, данные не будут найдены.
2. Признак количественного учета
Выясним причину, по которой КоличествоОборотДт может быть равно нулю. В плане счетов для конкретного счета (например, счета 10 «Материалы») должен быть установлен флаг Количественный. Если флаг не установлен, система не ведет учет количества, и в виртуальных таблицах это поле всегда будет пустым (NULL или 0), даже если суммы по дебету присутствуют.
3. Соответствие типов параметров
Проанализируем условие Субконто2 В ИЕРАРХИИ (&Склады). Если параметр &Склады заполняется из поля Запись.Машина, необходимо убедиться, что тип данных справочника «Машины» совпадает с типом данных, разрешенным для Субконто2 (обычно это справочник «Склады»). Если это разные справочники, условие В ИЕРАРХИИ всегда будет ложным, и запрос вернет пустую таблицу.
Посмотрим на процедуру ПриЗаписиНаСервере. Использование МенеджерЗаписи внутри обработчика записи того же самого объекта — это опасная практика. Разберем, почему:
МенеджерЗаписи.Записать() внутри транзакции записи может привести к конфликту блокировок (Deadlock) или ошибке «Объект изменен другим пользователем», так как система пытается дважды модифицировать одни и те же данные в рамках одной транзакции.Запись (или ТекущийОбъект), который уже находится в процессе записи.Рекомендуется перенести логику расчета в событие ПередЗаписью, где можно напрямую присвоить значение полю: Для Каждого Строка Из НаборЗаписей Цикл Строка.Перерасход = ... КонецЦикла;
Рассмотрим еще несколько важных моментов, которые помогут сделать код стабильнее:
ПланыСчетов.Хозрасчетный.НайтиПоКоду("10") выполняется при каждой записи. Это замедляет работу. Лучше использовать предопределенные элементы (ПланыСчетов.Хозрасчетный.Материалы) или кэшировать ссылку.КонецДня(Запись.Период) вместо прибавления 86400 секунд. Это гарантирует, что вы не захватите лишние секунды следующего дня, если время записи не строго полночь.Итог(), правильнее сразу в запросе использовать СУММА(КоличествоОборотДт) и убрать лишние группировки по субконто, если вам нужно только общее число для расчета.Таким образом, для решения проблемы «пустого результата» необходимо не только проверить корректность обращения к объектам (ТЗ vs Число), но и убедиться в правильности настройки аналитики (субконто) и типов данных в параметрах запроса.