Как настроить отбор по дате и заказчику во внешнем отчете на обычной форме в 1С?

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

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

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

Почему ручная привязка параметров на форме часто не работает?

Давайте выясним первопричину проблемы. Когда мы вручную пишем код в модуле формы в обработчиках событий ПриИзменении, мы пытаемся напрямую записать значения в коллекцию КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы. На первый взгляд, это логично. Но на практике такой подход часто дает сбои по следующим причинам:

  1. Влияние пользовательских настроек. В платформе 1С параметры компоновки могут дублироваться в так называемых «Пользовательских настройках» (КомпоновщикНастроек.ПользовательскиеНастройки). Если параметр СКД вынесен в пользовательские настройки, то при формировании отчета система берет значение именно оттуда, полностью игнорируя то, что мы записали в основные настройки компоновщика.
  2. Сброс настроек при формировании. При нажатии стандартной кнопки «Сформировать» платформа может выполнять инициализацию компоновщика заново, затирая программно измененные параметры значениями по умолчанию.
  3. Обращение по индексу вместо имен. Часто разработчики пишут код вида Элементы[0].Значение = ДатаНачала. Это крайне опасный подход. Стоит изменить порядок параметров в схеме СКД или добавить новый параметр, как индексы сместятся, и код начнет записывать дату начала в параметр заказчика или наоборот.

Рассмотрим пошагово три наиболее эффективных и архитектурно правильных метода решения этой задачи.

Способ 1: Использование модуля объекта и события «ПриКомпоновкеРезультата» (Рекомендуемый стандарт)

Этот способ является наиболее надежным, так как мы полностью отказываемся от обработки событий изменения полей на форме. Вместо этого мы передаем значения параметров в СКД в самый последний момент — непосредственно перед генерацией макета отчета.

Выполним следующие шаги:

  1. Перейдем в дерево метаданных нашего внешнего отчета и создадим три реквизита отчета: ДатаНачала (тип «Дата»), ДатаОкончания (тип «Дата») и Заказчик (тип, соответствующий вашему справочнику, например, «СправочникСсылка.Контрагенты»).
  2. Откроем нашу обычную форму отчета. Разместим на ней поля ввода для этих реквизитов.
  3. Важно: В свойствах каждого поля ввода в строке Данные укажем путь к реквизитам объекта, например: ОтчетОбъект.ДатаНачала, ОтчетОбъект.ДатаОкончания и ОтчетОбъект.Заказчик.
  4. Теперь перейдем в Модуль объекта внешнего отчета (не путать с модулем формы). Для этого в окне настройки отчета нажмем кнопку «Действия» -> «Открыть модуль объекта».
  5. Добавим предопределенный обработчик события ПриКомпоновкеРезультата и пропишем в нем следующий код:

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

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

Способ 2: Вывод параметров на форму через «Табличное поле» (Без написания кода)

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

Выполним настройку по шагам:

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

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

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

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

Рассмотрим, как правильно написать обработчики событий ПриИзменении, чтобы они гарантированно изменяли значения как в основной коллекции настроек, так и в пользовательских настройках СКД.

В модуле формы отчета разместим следующий универсальный код:


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

Процедура ДатаНачалаПриИзменении(Элемент)
    УстановитьПараметрСКД("ДатаНачала", НачалоДня(ДатаНачала));
КонецПроцедуры

Процедура ДатаОкончанияПриИзменении(Элемент)
    УстановитьПараметрСКД("ДатаОкончания", КонецДня(ДатаОкончания));
КонецПроцедуры

Процедура ЗаказчикПриИзменении(Элемент)
    УстановитьПараметрСКД("Заказчик", Заказчик);
КонецПроцедуры

Благодаря использованию свойства ИдентификаторПользовательскойНастройки мы находим связанный элемент в пользовательском интерфейсе и синхронизируем его. Это решает проблему, когда пользователь меняет дату на форме, но при генерации отчета СКД использует старые пустые значения из скрытых пользовательских настроек.

Реализация кнопки выбора периода «...»

Для удобства работы пользователей с датами часто добавляют кнопку выбора периода. Разберем, как правильно написать обработчик нажатия этой кнопки с использованием стандартного диалога НастройкаПериода:


Процедура КнопкаВыбораПериодаНажатие(Элемент)
    
    ДиалогВыбора = Новый НастройкаПериода;
    ДиалогВыбора.УстановитьПериод(ДатаНачала, ?(ДатаОкончания = '0001-01-01', ДатаОкончания, КонецДня(ДатаОкончания)));
    ДиалогВыбора.РедактироватьКакИнтервал = Истина;
    ДиалогВыбора.РедактироватьКакПериод = Истина;
    ДиалогВыбора.ВариантНастройки = ВариантНастройкиПериода.Период;
    
    Если ДиалогВыбора.Редактировать() Тогда
        // Получаем выбранные пользователем даты
        ДатаНачала = ДиалогВыбора.ПолучитьДатуНачала();
        ДатаОкончания = ДиалогВыбора.ПолучитьДатуОкончания();
        
        // Записываем обновленные значения в параметры компоновщика
        УстановитьПараметрСКД("ДатаНачала", НачалоДня(ДатаНачала));
        УстановитьПараметрСКД("ДатаОкончания", КонецДня(ДатаОкончания));
    КонецЕсли;
    
КонецПроцедуры

Этот код инициализирует стандартное окно выбора периода 1С (например, "Текущий месяц", "Прошлый квартал" и т.д.), корректно заполняет переменные формы ДатаНачала и ДатаОкончания, а затем транслирует их в компоновщик настроек СКД.

Выбирайте наиболее подходящий для вашего интерфейса способ. Для простых отчетов идеален Способ 2 (табличное поле без кода). Если дизайн формы жестко задан — используйте Способ 1 с переносом логики заполнения в модуль объекта в процедуру ПриКомпоновкеРезультата. Это убережет вас от трудноуловимых ошибок синхронизации настроек компоновщика.

← На главную