Как в отчете СКД изменить один параметр при изменении других в типовой форме на БСП?

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

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

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

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

Решение через обработчики событий БСП

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

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

  1. Подключение обработчика в модуле объекта отчета

    Первым делом нам нужно "сообщить" стандартной форме, что наш отчет хочет использовать собственный обработчик. Это делается в процедуре ОпределитьНастройкиФормы в модуле объекта вашего отчета. Если такой процедуры нет, ее нужно создать.

    В этой процедуре мы устанавливаем специальный флаг, который активирует вызов нашего будущего обработчика.

    
    // В модуле объекта отчета
    Процедура ОпределитьНастройкиФормы(Форма, КлючВарианта, Настройки) Экспорт
        // Включаем использование события "ОбработкаОбновленияОтображения".
        // Теперь стандартная форма отчета будет искать и вызывать одноименную процедуру в этом модуле.
        Настройки.События.ОбработкаОбновленияОтображения = Истина;
    КонецПроцедуры
    
  2. Реализация самого обработчика

    Теперь создадим в том же модуле объекта отчета экспортную процедуру с именем ОбработкаОбновленияОтображения. Именно она будет содержать нашу логику по пересчету параметра.

    Внутри этой процедуры мы получим доступ к компоновщику настроек, извлечем значения нужных параметров, выполним расчет и установим новое значение для целевого параметра. Рассмотрим на примере, где нам нужно рассчитать значение параметра ИмяЦелевогоПараметра на основе ИмяПараметраИсточника1 и ИмяПараметраИсточника2.

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

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

Альтернативный метод: пересчет перед формированием отчета

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

Этот метод не требует подключения через ОпределитьНастройкиФормы. Достаточно просто создать в модуле объекта отчета процедуру с нужным именем.


// В модуле объекта отчета
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка) Экспорт
    // Получаем текущие настройки, которые будут использованы для формирования отчета
    Настройки = КомпоновщикНастроек.Настройки;

    // Читаем значения исходных параметров
    ЗначениеИсточника1 = Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("ИмяПараметраИсточника1")).Значение;
    ЗначениеИсточника2 = Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("ИмяПараметраИсточника2")).Значение;

    // Ваша логика расчета
    РассчитанноеЗначение = ЗначениеИсточника1 + ЗначениеИсточника2; // Упрощенный пример

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

    // Стандартная обработка остается Истина, чтобы отчет сформировался с измененными настройками.
КонецПроцедуры

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

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

← На главную