Почему внешний отчет на СКД работает интерактивно, но не формируется в рассылке отчетов (ошибка обращения к свойствам даты)?

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

При разработке внешних отчетов на Системе Компоновки Данных (СКД) мы часто сталкиваемся с задачей программного изменения параметров перед формированием. Типичный сценарий: отчет должен запускаться по расписанию (через подсистему «Рассылка отчетов» из БСП) и автоматически сдвигать период формирования, если, например, рассылка выпадает на понедельник, а данные нужны за пятницу.

В этой статье мы разберем неочевидную ошибку, из-за которой отчет прекрасно работает при ручном запуске пользователем, но в журнале регистрации при рассылке появляется запись: «Рассылка отчетов не выполнена, так как отчеты пустые или не сформированы из-за ошибок».

Суть проблемы и симптомы

Рассмотрим ситуацию, с которой столкнулся разработчик. Имеется внешний отчет, в модуле объекта которого переопределена процедура ПриКомпоновкеРезультата. Цель кода — проверить день недели и, если условия совпадают, изменить параметры НачалоПериода и КонецПериода.

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

Вот исходный (проблемный) фрагмент кода:


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

При интерактивном запуске отчет формируется корректно. Однако при запуске через регламентное задание рассылки возникает ошибка, и отчет приходит пустым или не приходит вовсе. В Журнале регистрации можно увидеть сообщение об ошибке выполнения, но часто оно малоинформативно.

Анализ ошибки: Типы данных в параметрах СКД

Давайте разберем, что именно происходит в строке изменения параметров. Мы пытаемся выполнить математическую операцию вычитания секунд из даты: НачалоПериода.Дата - (2*60*60*24).

Ключевой вопрос: какой тип данных хранится в переменной НачалоПериода?

  1. Если параметр в СКД имеет тип СтандартныйПериод, то обращаться к нему нужно через свойства .ДатаНачала и .ДатаОкончания.
  2. Если параметр имеет тип Дата (как это часто бывает с полями «НачалоПериода» и «КонецПериода» в простых схемах), то переменная НачалоПериода уже содержит само значение даты.

У типа Дата в платформе 1С:Предприятие нет свойства .Дата. Написание МояПеременнаяДата.Дата является синтаксической ошибкой.

Почему это работало интерактивно?
В некоторых случаях (в зависимости от настроек платформы и режима совместимости) или если переменная получалась неявно типизированной, ошибка могла маскироваться или не приводить к падению формирования формы. Однако в строгом контексте фонового задания сервера (где выполняется рассылка) любое необработанное исключение приводит к прерыванию формирования отчета.

Решение проблемы

Чтобы исправить ошибку, необходимо убрать лишнее обращение к несуществующему свойству. Давайте скорректируем код, предполагая, что параметры в СКД имеют тип Дата.

Правильный вариант кода


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

Рекомендации по отладке рассылок

Если вы сталкиваетесь с ситуацией, когда отчет не формируется в фоне, используйте следующие приемы:

  1. Запись в Журнал регистрации. В фоновом задании отладка затруднена. Добавляйте запись в ЖР всех ключевых параметров (типы данных, значения) перед выполнением алгоритма.
    
    ЗаписьЖурналаРегистрации("ОтладкаОтчета", УровеньЖурналаРегистрации.Информация, , , 
        "Тип НачалоПериода: " + ТипЗнч(ЗначениеНачала));
    
  2. Обработка исключений. Оборачивайте критические участки кода в Попытка ... Исключение с обязательной записью ошибки в Журнал регистрации. Это покажет, на какой строке падает код.
  3. Проверка заполнения результата. Убедитесь, что в конце процедуры ДокументРезультат действительно содержит данные (например, проверьте ДокументРезультат.ВысотаТаблицы). Рассылка отчетов БСП имеет защиту: если отчет пустой (или содержит только шапку), письмо может не отправиться.

Важное дополнение про тип "СтандартныйПериод"

Если бы в вашей СКД использовался один параметр Период с типом СтандартныйПериод, код выглядел бы иначе. В этом случае свойство .Значение вернуло бы объект типа СтандартныйПериод, и тогда обращение к датам выглядело бы так:


ПараметрПериод = НастройкиКД.ПараметрыДанных.Элементы.Найти("Период").Значение;
// ПараметрПериод.ДатаНачала
// ПараметрПериод.ДатаОкончания

Всегда проверяйте типы данных параметров с помощью отладчика или функции ТипЗнч(), чтобы избежать подобных ошибок при переходе от интерактивной работы к фоновым заданиям.

← На главную