При разработке отчетов на базе Системы компоновки данных (СКД) разработчики часто сталкиваются с необходимостью выполнить специфическую логику, которая уже реализована в какой-либо форме. Возникает вопрос: можно ли напрямую обратиться к процедуре или функции, объявленной в модуле общей формы, непосредственно из выражений СКД? В этой статье мы подробно разберем, почему прямой вызов невозможен, и рассмотрим все существующие способы обхода этого ограничения.
Для начала проанализируем архитектурную ситуацию. Система компоновки данных — это мощный механизм, который выполняет основную работу (выборку данных, расчет итогов, агрегацию) на стороне сервера. Модуль формы, напротив, является объектом интерфейса. Даже если мы говорим о серверных процедурах модуля формы, они существуют только в контексте активного (созданного) экземпляра формы.
Разберем основные причины ограничения:
ПолучитьФорму(). СКД при расчете полей не создает никаких форм.Таким образом, на вопрос «Можно ли вызвать процедуру из формы?» ответ — нет. Однако мы можем перенести логику в те места, откуда СКД сможет её «дотянуться».
Это самый правильный и рекомендуемый стандарт разработки в 1С. Если логика универсальна и может понадобиться в СКД, её следует вынести в общий модуль. Проанализируем, как это сделать правильно, чтобы СКД «увидела» вашу функцию.
Во-первых, общий модуль должен иметь установленный флаг «Сервер». Во-вторых, для использования в выражениях СКД функция обязательно должна быть экспортной. Рассмотрим пример функции, которую мы хотим вызвать в вычисляемом поле:
// В общем модуле "РаботаСОтчетами"
Функция ПолучитьКоэффициентСложности(IDОбъекта) Экспорт
// Здесь ваша логика, которая раньше была в форме
Возврат 1.25;
КонецФункции
Чтобы вызвать эту функцию в СКД (например, в поле «Выражение» на закладке «Вычисляемые поля»), нужно использовать синтаксис: ИмяОбщегоМодуля.ИмяФункции(Параметры). В нашем случае это будет выглядеть так:
РаботаСОтчетами.ПолучитьКоэффициентСложности(Ссылка)
Важный нюанс: Если вы используете конфигурацию на управляемых формах, убедитесь, что у модуля не стоит флаг «Глобальный», иначе обращение будет идти без точки, что может вызвать путаницу в именах. Лучше всегда использовать явное указание имени модуля.
Если логика специфична только для конкретного отчета и вы не хотите загромождать общие модули, можно использовать модуль объекта самого отчета. Мало кто знает, что СКД умеет обращаться к экспортным функциям своего «родителя».
Рассмотрим порядок действий:
Экспорт.
// В модуле объекта отчета
Функция РассчитатьДополнительныйПоказатель(Сумма) Экспорт
Возврат Сумма * 0.15;
КонецФункции
В СКД в вычисляемом поле просто укажем: РассчитатьДополнительныйПоказатель(СуммаПродаж). Платформа сама найдет эту функцию в контексте выполняемого отчета.
Иногда процедура в форме настолько сложна и так сильно зависит от текущего состояния экранных форм (например, введенных пользователем данных в таблицу на форме), что перенести её в модуль невозможно. В этом случае мы используем механизм «Внешний набор данных».
Проанализируем этот алгоритм:
Пример программного формирования с внешним набором данных в модуле формы:
&НаСервере
Процедура СформироватьНаСервере()
// 1. Получаем данные из нашей процедуры формы
ТаблицаРезультат = ПолучитьДанныеИзЛогикиФормы();
// 2. Инициализируем компоненты СКД
Схема = Отчеты.МойОтчет.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Настройки = Отчет.КомпоновщикНастроек.ПолучитьНастройки();
ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки, ДанныеРасшифровки);
// 3. Передаем внешнюю таблицу
ВнешниеНаборыДанных = Новый Структура;
ВнешниеНаборыДанных.Вставить("МояТаблица", ТаблицаРезультат);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки);
// 4. Выводим результат в табличный документ
Результат = Элементы.Результат;
Результат.Очистить();
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(Результат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры
В этом сценарии СКД вообще не вызывает форму. Наоборот — форма подготавливает данные и «скармливает» их системе компоновки.
Выясним важные детали, которые могут привести к ошибкам при реализации предложенных решений:
Типы возвращаемых значений: Функции, вызываемые из СКД, должны возвращать простые типы (Число, Строка, Дата, Булево) или Ссылки. Если ваша функция в форме возвращала Структуру или Массив, то при переносе в модуль для целей СКД её придется переделать. СКД не сможет отобразить структуру в ячейке отчета и выдаст ошибку.
Веб-клиент и мобильный клиент: Если вы переносите логику из формы в общий модуль, следите за тем, чтобы там не осталось методов, доступных только на клиенте (например, Предупреждение() или Вопрос()). СКД работает на сервере, и наличие таких методов приведет к падению отчета.
Подведем итог. Напрямую вызвать процедуру из общей формы из СКД невозможно из-за разницы контекстов исполнения (Сервер vs Интерфейс). Для решения задачи выберите один из трех путей:
Наиболее чистым и поддерживаемым решением является вынос расчетной логики в неглобальный общий модуль с установленным флагом «Сервер».