Разберем типичную, но крайне неприятную проблему, с которой часто сталкиваются разработчики при проектировании сложных отчетов на базе Системы Компоновки Данных (СКД) в 1С. Ситуация заключается в следующем: у нас есть готовая форма отчета, к которой динамически подключаются несколько различных макетов (схем компоновки). Для одних макетов отбор по периоду с формы работает идеально, а при переключении на другой макет (например, выводящий данные из самописного документа) система либо полностью игнорирует установленные даты, либо выдает критическую ошибку «Параметр с указанным именем не найден».
В этой статье мы подробно проанализируем причины возникновения этой ошибки, разберем физику работы платформы 1С с виртуальными и реальными таблицами в СКД, а также рассмотрим четыре надежных практических метода решения данной проблемы.
Для начала проанализируем архитектуру запросов в различных макетах СКД, чтобы понять первопричину сбоя:
ОстаткиИОбороты). Платформа 1С на уровне СУБД автоматически создает для таких таблиц стандартные параметры (НачалоПериода и КонецПериода). Компоновщик настроек формы без труда находит их в схеме и передает туда выбранные пользователем даты.Документ.РеализацияТоваровУслуг). В таком простом запросе к физической таблице базы данных никаких предопределенных параметров периода по умолчанию нет.Когда мы пытаемся программно или интерактивно через форму передать значения в параметры ДатаНачала и ДатаОкончания, которых физически не существует в схеме СКД для документов, платформа генерирует исключение: Ошибка при вызове метода контекста (УстановитьЗначениеПараметра): Параметр с указанным именем не найден.
Рассмотрим детально четыре метода исправления этой ситуации, от простых до максимально универсальных.
Самый логичный и простой способ решить проблему «в лоб» — сделать так, чтобы третья схема компоновки данных узнала о существовании параметров периода. Для этого нам нужно явно объявить их в тексте запроса СКД.
Разберем по шагам, как это сделать. Откроем конструктор запроса схемы компоновки данных для проблемного макета и на вкладке «Условия» добавим ограничение по дате документа. В текстовом виде запрос должен выглядеть следующим образом:
ВЫБРАТЬ
Док.Ссылка КАК Ссылка,
Док.Дата КАК Дата,
Док.Контрагент КАК Контрагент,
Док.СуммаДокумента КАК Сумма
ИЗ
Документ.СамописныйДокумент КАК Док
ГДЕ
Док.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
После сохранения этого запроса на вкладке «Параметры» в СКД автоматически появятся строки ДатаНачала и ДатаОкончания. Теперь форма отчета сможет передавать в них значения без ошибок.
Полезный совет: Если мы хотим, чтобы параметры периода были необязательными (то есть, если период на форме не заполнен, отчет должен выводиться за все время), стандартное условие ГДЕ использовать нельзя. В этом случае применим расширение языка запросов СКД, заключив наше условие в фигурные скобки:
ВЫБРАТЬ
Док.Ссылка КАК Ссылка,
Док.Дата КАК Дата
ИЗ
Документ.СамописныйДокумент КАК Док
{ГДЕ
(Док.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания)}
Вместо использования двух разрозненных параметров даты (начала и окончания) на форме отчета гораздо удобнее и профессиональнее использовать единый системный тип данных — СтандартныйПериод. Это позволит пользователю быстро выбирать предопределенные интервалы («Сегодня», «Этот месяц», «Прошлый квартал» и т.д.).
Рассмотрим подробнее настройку этого механизма в СКД:
ПериодОтчета и укажем тип данных СтандартныйПериод.ДатаНачала и ДатаОкончания (или стандартных НачалоПериода / КонецПериода) установим флаг «Ограничение доступности». Это скроет их от пользователя в настройках отчета.&ПериодОтчета.ДатаНачала&ПериодОтчета.ДатаОкончанияТеперь на форму отчета достаточно вывести всего одно поле выбора периода, связанное с параметром ПериодОтчета. Платформа будет сама автоматически раскладывать выбранный интервал на граничные даты и подставлять их во все связанные схемы компоновки.
Если параметры устанавливаются программно в модуле объекта отчета (в процедуре ПриКомпоновкеРезультата), мы должны обезопасить код от падения в тех макетах, где этих параметров может не оказаться. Для этого перед установкой значения всегда нужно делать проверку на существование элемента в коллекции параметров данных.
Проанализируем пример безопасного кода, который предотвратит появление ошибок:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// Получаем доступ к текущим настройкам компоновщика
ТекущиеНастройки = КомпоновщикНастроек.Настройки;
// Проверяем наличие параметра "ДатаНачала" в текущей схеме компоновки
ПараметрДатаНачала = ТекущиеНастройки.ПараметрыДанных.Элементы.Найти("ДатаНачала");
Если ПараметрДатаНачала <> Неопределено Тогда
КомпоновщикНастроек.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("ДатаНачала", ДатаНачала);
КонецЕсли;
// Проверяем наличие параметра "ДатаОкончания"
ПараметрДатаОкончания = ТекущиеНастройки.ПараметрыДанных.Элементы.Найти("ДатаОкончания");
Если ПараметрДатаОкончания <> Неопределено Тогда
// Обязательно используем КонецДня, чтобы захватить документы, созданные внутри последней секунды дня
КомпоновщикНастроек.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("ДатаОкончания", КонецДня(ДатаОкончания));
КонецЕсли;
КонецПроцедуры
Важное примечание: Если параметры выведены пользователем в область пользовательских настроек на форме, их значения могут храниться в другой коллекции. В таком случае поиск параметров необходимо дополнительно выполнять в коллекции пользовательских настроек:
ПараметрВПользовательских = КомпоновщикНастроек.ПользовательскиеНастройки.Элементы.Найти(ПараметрДатаНачала.ИдентификаторПользовательскойНастройки);
Если ПараметрВПользовательских <> Неопределено Тогда
ПараметрВПользовательских.Значение = ДатаНачала;
ПараметрВПользовательских.Использование = Истина;
КонецЕсли;
Если мы не хотим вручную переписывать и модифицировать многочисленные запросы в макетах СКД, можно полностью отказаться от жестких параметров в пользу универсального механизма отборов компоновки данных.
Отбор накладывается платформой автоматически на уже полученный результат запроса, поэтому нам не нужно заботиться о наличии параметров &ДатаНачала в коде СУБД. Поле Дата (или Период) присутствует практически во всех прикладных объектах 1С (и в регистрах, и в документах), что делает этот метод наиболее универсальным.
Посмотрим, как программно добавить отбор по дате на форме отчета:
// Очищаем старые отборы по полю "Дата" во избежание дублирования
ПолеКомпоновкиДата = Новый ПолеКомпоновкиДанных("Дата");
Индекс = 0;
Пока Индекс < КомпоновщикНастроек.Настройки.Отбор.Элементы.Количество() Цикл
ЭлементОтбора = КомпоновщикНастроек.Настройки.Отбор.Элементы[Индекс];
Если ЭлементОтбора.ЛевоеЗначение = ПолеКомпоновкиДата Тогда
КомпоновщикНастроек.Настройки.Отбор.Элементы.Удалить(ЭлементОтбора);
Иначе
Индекс = Индекс + 1;
EndIf;
КонецЦикла;
// Добавляем новый элемент отбора по периоду
НовыйОтбор = КомпоновщикНастроек.Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
НовыйОтбор.ЛевоеЗначение = ПолеКомпоновкиДата;
НовыйОтбор.ВидСравнения = ВидСравненияКомпоновкиДанных.ИнтервалВключаяГраницы;
НовыйОтбор.ПравоеЗначение = Новый СтандартныйПериод(ДатаНачала, КонецДня(ДатаОкончания));
НовыйОтбор.Использование = Истина;
Этот способ позволяет динамически менять макеты СКД «на лету» без опасений получить критическую ошибку выполнения, так как платформа сама наложит фильтр по полю даты на результирующий набор данных.