Почему возникает ошибка "Не удалось сформировать отчет (пустой результат)" в клиент-серверном варианте и как её исправить?

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

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

Эта проблема часто связана не с логикой запроса, а с особенностями работы фоновых заданий, правами доступа на уровне ОС Windows Server или объемом выводимых данных (в частности, картинок). Разберем подробно основные причины и способы их решения, опираясь на опыт сообщества.

Причина 1: Недостаточно прав у пользователя сервера 1С на запись временных файлов

В клиент-серверной архитектуре тяжелые отчеты формируются в фоновом задании. Результат формирования отчета (временные файлы) сохраняется в рабочую директорию кластера серверов. Если у пользователя, от имени которого запущена служба агента сервера 1С (обычно это USR1CV8), нет прав на запись в эту папку, формирование отчета прервется, и мы получим "пустой результат".

Симптомы:

  1. Отчет формируется по одной номенклатуре, но падает при формировании по всем складам.
  2. В файловой версии ошибки нет.
  3. Ошибка возникает внезапно или после переноса сервера/обновления Windows.

Решение:

Нам необходимо проверить и настроить права доступа на уровне файловой системы сервера, а также выполнить анализ прав и ролей пользователя в самой базе — для этого есть детальный анализ прав доступа, ролей и ограничений RLS.

  1. Зайдем на сервер, где установлен сервер 1С:Предприятия.
  2. Найдем папку, в которой хранятся данные кластера. Обычно путь выглядит так: C:\Program Files\1cv8\srvinfo (или путь, указанный при установке службы).
  3. Внутри этой папки нас интересует директория реестра кластера, например reg_1541.
  4. Откроем свойства этой папки, перейдем на вкладку "Безопасность".
  5. Убедимся, что пользователь, под которым запущена служба (USR1CV8 или другой доменный пользователь), имеет права "Полный доступ" (Full Control) на эту папку и все вложенные объекты.
  6. Если права отсутствуют или ограничены, добавим пользователя и дадим полные права.

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

Причина 2: Большой объем графических данных (Картинки в отчете)

Вторая распространенная причина — наличие в отчете изображений (фотографий товаров), которые хранятся в высоком разрешении. Система компоновки данных (СКД) при попытке вывести в табличный документ большое количество картинок (или одну, но очень "тяжелую", например, более 2 Мб) может не справиться с выделением памяти или передачей данных с сервера на клиент, что приведет к пустому результату. Для этой задачи подойдёт контроль размера и массовое сжатие изображений номенклатуры.

Решение: Программный вывод и сжатие картинок

Если простое формирование отчета падает, нам придется отказаться от стандартного автоматического вывода и переопределить процедуру вывода (используя инструменты для упрощения программного создания СКД (поможет инструменты для анализа метаданных и отладки СКД)), добавив механизм сжатия картинок "на лету".

Рассмотрим код, который необходимо разместить в модуле объекта отчета (для внешнего отчета) или в модуле менеджера, перехватив событие ПриКомпоновкеРезультата.

Логика следующая:

  1. Отключаем стандартную обработку.
  2. Выполняем компоновку макета программно.
  3. В цикле выводим результат в табличный документ.
  4. Если встречаем поле с картинкой, сжимаем его перед выводом.

Разберем готовый пример кода:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    // Отключаем стандартный механизм вывода, так как будем выводить программно
    СтандартнаяОбработка = Ложь;
    
    // 1. Получаем настройки и макет
    НастройкаКомпоновки = КомпоновщикНастроек.ПолучитьНастройки();
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкаКомпоновки, ДанныеРасшифровки);
    
    // 2. Инициализируем процессор компоновки
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
    
    // 3. Выводим результат в документ
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
    // 4. Постобработка: поиск и сжатие картинок
    // Проверяем, включено ли поле "ФайлКартинки" в настройках
    ЭлементыВыбранныеПоля = НастройкаКомпоновки.Выбор.Элементы;
    ВывестиИзображение = Ложь;
    Для каждого ЭлементВыбранногоПоля Из ЭлементыВыбранныеПоля Цикл
        // Здесь "ФайлКартинки" - имя поля в вашем наборе данных, содержащего путь к файлу
        Если Строка(ЭлементВыбранногоПоля.Поле) = "ФайлКартинки" И ЭлементВыбранногоПоля.Использование Тогда
            ВывестиИзображение = Истина;
            Прервать;
        КонецЕсли;
    КонецЦикла;
    
    // Если картинки нужны, проходим по табличному документу и обрабатываем их
    Если ВывестиИзображение Тогда
        КоличествоСтрок = ДокументРезультат.ВысотаТаблицы;
        КоличествоКолонок = ДокументРезультат.ШиринаТаблицы;
        
        Для СтрокаДокумента = 1 По КоличествоСтрок Цикл
            Для КолонкаДокумента = 1 По КоличествоКолонок Цикл
                
                Область = ДокументРезультат.Область(СтрокаДокумента, КолонкаДокумента);
                Расшифровка = Область.Расшифровка;
                
                // Проверяем расшифровку, чтобы найти нужные данные
                Если ТипЗнч(Расшифровка) = Тип("ИдентификаторРасшифровкиКомпоновкиДанных") Тогда
                    ПоляРасшифровки = ДанныеРасшифровки.Элементы.Получить(Расшифровка).ПолучитьПоля();
                    НайденноеПоле = ПоляРасшифровки.Найти("ФайлКартинки");
                    
                    Если НайденноеПоле <> Неопределено Тогда
                        Если ЗначениеЗаполнено(НайденноеПоле.Значение) Тогда
                            // Предполагается, что в поле хранится структура с Томом и Путем (как в 1С:УТ/ERP)
                            // Если у вас хранилище значения, код получения данных будет иным
                            Если ЗначениеЗаполнено(НайденноеПоле.Значение.Том) И ЗначениеЗаполнено(НайденноеПоле.Значение.ПутьКФайлу) Тогда
                                ПутьККартинке = НайденноеПоле.Значение.Том.ПолныйПутьWindows + НайденноеПоле.Значение.ПутьКФайлу;
                                
                                Если ЗначениеЗаполнено(ПутьККартинке) Тогда
                                    Фото = Новый Файл(ПутьККартинке);
                                    Если Фото.Существует() Тогда
                                        Картинка = Новый Картинка(ПутьККартинке);
                                        
                                        // Создаем рисунок в ячейке
                                        Изображение = ДокументРезультат.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Картинка);
                                        
                                        // СЖАТИЕ КАРТИНКИ
                                        // Вызываем вспомогательную функцию сжатия
                                        СжатаяКартинка = ПолучитьСжатуюКартинку(Картинка, 60); 
                                        
                                        Изображение.Картинка = СжатаяКартинка;
                                        Изображение.РазмерКартинки = РазмерКартинки.АвтоРазмер;
                                        Область.АвтоВысотаСтроки = Ложь;
                                        Изображение.Расположить(Область);
                                    КонецЕсли;
                                КонецЕсли;
                            КонецЕсли;
                        КонецЕсли;
                    КонецЕсли;
                КонецЕсли;
            КонецЦикла;
        КонецЦикла;
    КонецЕсли;
    
КонецПроцедуры

Также нам понадобится вспомогательная функция для сжатия. Она проверяет размер файла или высоту картинки и при необходимости уменьшает её качество.


Функция ПолучитьСжатуюКартинку(Крт, ВысотаКартинки, РазмерФайлаПоУмолчаниюКБ = 300) Экспорт
    
    Крт_ = Крт;
    // Если файл больше заданного лимита (например, 300 КБ) или слишком высокий
    Если (Крт_.РазмерФайла() > РазмерФайлаПоУмолчаниюКБ * 1024) ИЛИ (Крт_.Высота() > ВысотаКартинки) Тогда
        Попытка
            // Используем объект ОбрабатываемаяКартинка (доступен в новых платформах)
            ОбрКрт = Новый ОбрабатываемаяКартинка(Крт, Истина); // Истина - формат сохраняется
            
            // Устанавливаем новые параметры
            ОбрКрт.УстановитьРазмер(, ВысотаКартинки); 
            ОбрКрт.УстановитьПлотность(96, 96);
            ОбрКрт.УстановитьГлубинуЦвета(ГлубинаЦвета.БитНаПиксел24);
            // Можно принудительно установить формат, например PNG или JPEG
            ОбрКрт.УстановитьФормат(ФорматКартинки.PNG); 
            
            Крт_ = ОбрКрт.ПолучитьКартинку();
            Возврат Крт_;
        Исключение
            // Если обработка не удалась, возвращаем оригинал
            Возврат Крт;
        КонецПопытки;
    Иначе
        Возврат Крт;
    КонецЕсли;
    
КонецФункции

Важные замечания по коду:

Причина 3: Ошибки в фоновых заданиях ("Тихие" исключения)

Часто бывает, что ошибка происходит внутри фонового задания, но платформа просто "проглатывает" её, выдавая пользователю пустой отчет вместо текста ошибки. Если отчёт запускает фоновое задание, в просмотре фоновых заданий можно проверить сохранившийся статус, длительность и текст ошибки. Список фоновых задач не хранит полную долговременную историю, поэтому параллельно проверьте журнал регистрации.

Как диагностировать:

  1. Запуск в режиме отладки. Попробуйте запустить клиентское приложение с ключом /DebugMode или /РежимОтладки — для этого подойдёт инструмент для пошаговой отладки кода в режиме 1С:Предприятие. В этом режиме сообщения об ошибках фоновых заданий могут отображаться более явно.
  2. Отключение фонового формирования. В настройках отчета (обычно кнопка "Еще" -> "Настройки" или "Действия") часто есть флажок "Фоновое формирование". Попробуйте снять его. Тогда отчет будет формироваться в основном потоке, и если возникнет ошибка (например, деление на ноль или нарушение прав доступа), вы увидите окно с описанием ошибки и кнопку "Подробно".
  3. Журнал регистрации. Обязательно проверьте Журнал регистрации на сервере за момент формирования отчета. Отфильтруйте события по уровню "Ошибка". Там может быть информация о нехватке памяти, тайм-ауте или исключении — поможет мониторинг журнала регистрации и уведомление об ошибках в Telegram.

Причина 4: Безопасный режим и Внешние отчеты

Если вы подключаете внешний отчет через справочник "Дополнительные отчеты и обработки", обратите внимание на настройку "Безопасный режим".

В безопасном режиме запрещены некоторые операции:

Попробуйте отключить "Безопасный режим" в карточке дополнительного отчета и сформировать его снова.

← На главную