Почему не работает отбор по периоду в некоторых макетах СКД и как это исправить?

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

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

В этой статье мы подробно проанализируем причины возникновения этой ошибки, разберем физику работы платформы 1С с виртуальными и реальными таблицами в СКД, а также рассмотрим четыре надежных практических метода решения данной проблемы.

Выясняем причину: почему на регистрах работает, а на документах — нет?

Для начала проанализируем архитектуру запросов в различных макетах СКД, чтобы понять первопричину сбоя:

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

Когда мы пытаемся программно или интерактивно через форму передать значения в параметры ДатаНачала и ДатаОкончания, которых физически не существует в схеме СКД для документов, платформа генерирует исключение: Ошибка при вызове метода контекста (УстановитьЗначениеПараметра): Параметр с указанным именем не найден.

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

Вариант 1. Явное определение параметров в запросе документа

Самый логичный и простой способ решить проблему «в лоб» — сделать так, чтобы третья схема компоновки данных узнала о существовании параметров периода. Для этого нам нужно явно объявить их в тексте запроса СКД.

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


ВЫБРАТЬ
    Док.Ссылка КАК Ссылка,
    Док.Дата КАК Дата,
    Док.Контрагент КАК Контрагент,
    Док.СуммаДокумента КАК Сумма
ИЗ
    Документ.СамописныйДокумент КАК Док
ГДЕ
    Док.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания

После сохранения этого запроса на вкладке «Параметры» в СКД автоматически появятся строки ДатаНачала и ДатаОкончания. Теперь форма отчета сможет передавать в них значения без ошибок.

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


ВЫБРАТЬ
    Док.Ссылка КАК Ссылка,
    Док.Дата КАК Дата
ИЗ
    Документ.СамописныйДокумент КАК Док
{ГДЕ
    (Док.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания)}

Вариант 2. Использование стандартного объекта «СтандартныйПериод»

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

Рассмотрим подробнее настройку этого механизма в СКД:

  1. Перейдем на вкладку «Параметры» в схеме компоновки данных.
  2. Добавим новый параметр, назовем его ПериодОтчета и укажем тип данных СтандартныйПериод.
  3. Для параметров ДатаНачала и ДатаОкончания (или стандартных НачалоПериода / КонецПериода) установим флаг «Ограничение доступности». Это скроет их от пользователя в настройках отчета.
  4. В колонке «Выражение» для параметра начала периода пропишем формулу:
    &ПериодОтчета.ДатаНачала
  5. В колонке «Выражение» для параметра окончания периода пропишем формулу:
    &ПериодОтчета.ДатаОкончания

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

Вариант 3. Безопасная программная установка параметров (с проверкой)

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

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


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    // Получаем доступ к текущим настройкам компоновщика
    ТекущиеНастройки = КомпоновщикНастроек.Настройки;
    
    // Проверяем наличие параметра "ДатаНачала" в текущей схеме компоновки
    ПараметрДатаНачала = ТекущиеНастройки.ПараметрыДанных.Элементы.Найти("ДатаНачала");
    Если ПараметрДатаНачала <> Неопределено Тогда
        КомпоновщикНастроек.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("ДатаНачала", ДатаНачала);
    КонецЕсли;

    // Проверяем наличие параметра "ДатаОкончания"
    ПараметрДатаОкончания = ТекущиеНастройки.ПараметрыДанных.Элементы.Найти("ДатаОкончания");
    Если ПараметрДатаОкончания <> Неопределено Тогда
        // Обязательно используем КонецДня, чтобы захватить документы, созданные внутри последней секунды дня
        КомпоновщикНастроек.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("ДатаОкончания", КонецДня(ДатаОкончания));
    КонецЕсли;

КонецПроцедуры

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


ПараметрВПользовательских = КомпоновщикНастроек.ПользовательскиеНастройки.Элементы.Найти(ПараметрДатаНачала.ИдентификаторПользовательскойНастройки);
Если ПараметрВПользовательских <> Неопределено Тогда
    ПараметрВПользовательских.Значение = ДатаНачала;
    ПараметрВПользовательских.Использование = Истина;
КонецЕсли;

Вариант 4. Использование динамического отбора вместо параметров запроса

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

Отбор накладывается платформой автоматически на уже полученный результат запроса, поэтому нам не нужно заботиться о наличии параметров &ДатаНачала в коде СУБД. Поле Дата (или Период) присутствует практически во всех прикладных объектах 1С (и в регистрах, и в документах), что делает этот метод наиболее универсальным.

Посмотрим, как программно добавить отбор по дате на форме отчета:


// Очищаем старые отборы по полю "Дата" во избежание дублирования
ПолеКомпоновкиДата = Новый ПолеКомпоновкиДанных("Дата");
Индекс = 0;
Пока Индекс < КомпоновщикНастроек.Настройки.Отбор.Элементы.Количество() Цикл
    ЭлементОтбора = КомпоновщикНастроек.Настройки.Отбор.Элементы[Индекс];
    Если ЭлементОтбора.ЛевоеЗначение = ПолеКомпоновкиДата Тогда
        КомпоновщикНастроек.Настройки.Отбор.Элементы.Удалить(ЭлементОтбора);
    Иначе
        Индекс = Индекс + 1;
    EndIf;
КонецЦикла;

// Добавляем новый элемент отбора по периоду
НовыйОтбор = КомпоновщикНастроек.Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
НовыйОтбор.ЛевоеЗначение = ПолеКомпоновкиДата;
НовыйОтбор.ВидСравнения = ВидСравненияКомпоновкиДанных.ИнтервалВключаяГраницы;
НовыйОтбор.ПравоеЗначение = Новый СтандартныйПериод(ДатаНачала, КонецДня(ДатаОкончания));
НовыйОтбор.Использование = Истина;

Этот способ позволяет динамически менять макеты СКД «на лету» без опасений получить критическую ошибку выполнения, так как платформа сама наложит фильтр по полю даты на результирующий набор данных.

← На главную