Введение
Всем привет! Моя предыдущая статья на тему СКД вызвала отрицательную реакцию у некоторых пользователей сообщества. Но хочу отметить, что по собственному опыту большинство отчетов, которые мне попадались или доставались "по наследству", а были в них и производственные отчеты для УПП (порядка 70-80 колонок), построены именно на такой схеме (на внешнем наборе данных - объекте).
Если вы умеете разрабатывать подобные отчеты "одной связкой запросов и за один присест" - снимаю перед вам шляпу - цены вам нет!
Когда ты "пилишь" большой производственный отчет (сам заказчик не знает в итоге, что он хочет - это не редкость) сроки разработки подобных отчетов доходят по полугода! А если отчет "переходит" из рук в руки... естественно, вполне логично, что удобнее собирать отчеты "по-кусочкам", нежели начинать "все сначала".
Также, разумеется, программист, который "собирает" все отчеты на основе набора запросов в макете может иметь более высокую квалификацию в работе с запросами, либо владеет всей информацией по окончательному решению задачи.
Тем не менее, считаю, что объекты с наборами данных для системы компоновки имеют равнозначную значимость по сравнению наборами данных, построенными на основе запросов. Да, медленнее, но по собственному опыту - скорость работы отчетов - это не самая важная "характеристика" в работающем корректном отчете, особенно если в нем порядка 80 колонок (производственные отчеты). Встречал я и такие большие отчеты, которые "ложили" производственную базу при их запуске - выполнении.
Так, давайте я опишу чему будет посвящен мой "Лайфхак №2" при работе с СКД. В этой статье я опишу работу с закладкой СКД "Вычисляемые поля", а именно - применению внешних функций - как их использовать, что где нужно добавить, правильно "включить".
Начнем с раздела подготовки отчета (Я буду работать на платформе 8.3.15.1700 и конфигурации УНФ 1.6):
Подготовка отчета
Первым шагом, давайте подготовим какой-нибудь простенький отчет, так же будем использовать внешний набор данных. Для этого в модуле отчета еще раз подготовим основную процедуру ПриКомпоновкеРезультата :
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ОсновнаяТаблицаЗапроса = ПолучимТаблицуДанных();
СхемаКомпоновкиДанных = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
ВнешнийНаборДанных = Новый Структура("ДанныеОтчета", ОсновнаяТаблицаЗапроса);
ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, ВнешнийНаборДанных, ДанныеРасшифровки,);
ДокументРезультат.Очистить();
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);
КонецПроцедуры
В качестве содержимого функции ПолучимТаблицуДанных() ограничимся вот таким написанием:
&НаСервере
Функция ПолучимТаблицуДанных()
ТаблицаРезультат = Новый ТаблицаЗначений;
ТаблицаРезультат.Колонки.Добавить("Дата");
ТаблицаРезультат.Колонки.Добавить("Номер");
ТаблицаРезультат.Колонки.Добавить("Реализация");
ТаблицаРезультат.Колонки.Добавить("Организация");
ТаблицаРезультат.Колонки.Добавить("Подразделение");
ТаблицаРезультат.Колонки.Добавить("Контрагент");
ТаблицаРезультат.Колонки.Добавить("Номенклатура");
ТаблицаРезультат.Колонки.Добавить("ЕдиницаИзмерения");
ТаблицаРезультат.Колонки.Добавить("Количество");
ТаблицаРезультат.Колонки.Добавить("Сумма");
ТаблицаРезультат.Колонки.Добавить("СтавкаНДС");
ТаблицаРезультат.Колонки.Добавить("СуммаБезНДС");
ТаблицаРезультат.Колонки.Добавить("ТипНоменклатуры");
ТаблицаРезультат.Колонки.Добавить("Цена");
ТаблицаРезультат.Колонки.Добавить("ГруппаНоменклатуры");
ТаблицаРезультат.Колонки.Добавить("РаспределенияЗатрат");
ТаблицаРезультат.Колонки.Добавить("Процент");
ТаблицаРезультат.Колонки.Добавить("Склад");
ТаблицаРезультат.Колонки.Добавить("СебестоимостьБезНДС");
ТаблицаРезультат.Колонки.Добавить("НадбавкаПоГруппе");
ТаблицаРезультат.Колонки.Добавить("СебестоимостьСНадбавкой");
ТаблицаРезультат.Колонки.Добавить("ВаловаяПрибыль");
ТаблицаРезультат.Колонки.Добавить("Премия");
// == Здесь сделаем запрос к базе и заполним на ТаблицуРезультат
// == текст запроса не привожу ==
Для Каждого СтрокаПродаж ИЗ НаборПродаж Цикл
ЗаполнитьЗначенияСвойств(ТаблицаРезультат.Добавить(), СтрокаПродаж);
КонецЦикла;
Возврат ТаблицаРезультат;
КонецФункции
В вышеуказанной функции получим из запроса следующие поля: Дата, Номер, Реализация, Организация, Подразделение, Контрагент, Номенклатура, ЕдиницаИзмерения, Количество, Сумма, СтавкаНДС, СуммаБезНДС, ТипНоменклатуры, Цена, ГруппаНоменклатуры, РаспределенияЗатрат, Процент, Склад.
Оставшиеся поля получать этим запросом не будем, в СКД, будем использовать их на закладке "ВычисляемыеПоля". (СебестоимостьБезНДС, НадбавкаПоГруппе, СебестоимостьСНадбавкой, ВаловаяПрибыль, Премия).
В качестве расчета данных вышеуказанных величин, я буду использовать внешние функции для СКД в конфигурации, находящиеся в созданном мной общем модуле. Давайте рассмотрим как это сделать.
Традиционное использование внешних функций в СКД
Для использования внешних функций, я сначала должен подредактировать написанную ранее процедуру ПриКомпоновкеРезультата. Добавляем "Истину" (Возможность использовать внешние функции) в ПроцессорКомпоновкиДанных.
ВнешнийНаборДанных = Новый Структура("ДанныеОтчета", ОсновнаяТаблицаЗапроса);
ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, ВнешнийНаборДанных, ДанныеРасшифровки, Истина);
Теперь, в конфигурации создаем общий модуль. Назовем его ОбщийМодульСКД. Ставим галки Сервер, ВызовСервере, Привилегированный.
В этом модуле пишем экспортные функции
Функция НадбавкаПоГруппе(Номенклатура) Экспорт
//******
Возврат НадбавкиПоГруппе;
КонецФункции
Функция СебестоимостьБезНДС(Сумма, Номенклатура, Дата) Экспорт
//******
Возврат СебестоимостиБезНДС;
КонецФункции
Функция СебестоимостьСНадбавкой(Сумма, Номенклатура, Дата) Экспорт
//******
Возврат СебестоимостиСНадбавкой;
КонецФункции
Функция ВаловаяПрибыль(Сумма, Номенклатура, Дата) Экспорт
//******
Возврат ВаловаяПрибыль;
КонецФункции
Функция Премия(Сумма, Номенклатура, Дата) Экспорт
//******
Возврат Премии;
КонецФункции
Заходим в СКД создаваемого отчета и прописываем обращение к этим экспортным функциям в составе ОбщийМодульСКД. Как на рисунке 1. Параметры для функций - это ранее полученные поля из запроса:
Рис.1. Определение внешний функций на закладке "Вычисляемые поля".
Сохраняем, проверяем - работает. Результат считает. Еще раз обращу внимание, что в параметрах функций используем уже полученные поля по набору данных.
Так, здесь все понятно и достаточно просто.
Перенос внешних функций в расширение конфигурации
Попробуем теперь сделать такую штуку. Давайте я создадим расширение нашей конфигурации и перенесем туда наши функции.
Для этого заходим Конфигурация - Расширения конфигурации (создать новое) - тип расширения "Дополнение". См рис.2.
Рис.2. Расширение конфигурации, используемое для СКД отчетов. (Дополнение).
Создали расширение, и перетаскиваем туда наш ОбщийМодульСКД. Свойства модуля должны быть Сервер, ВызовСервера. Удаляем этот модуль из основной конфигурации. Проверяем работоспособность.
Запускаем конфигурацию с включенным расширением в режиме предприятия, открываем отчет - работает (см. рис.3).
Рис.3. Отчет на основе СКД, использующий внешние функции, перенесенные в подключаемое расширение.
В итоге, мы получили работающий отчет на основе СКД, с подключенными внешними функциями в расширении конфигурации. Это расширение я могу использовать в группе отчетов - формулы одни. Так же возможно оперативно поменять любую из формул, поставить более "глубокое условие"... используем встроенный язык 1с на "полную катушку" - вплоть до того, что я могу получать он-лайн данные из внешних интернет-источников и использовать их в отчете в реальном времени. Применений масса.
И неважно, как я буду собирать НаборДанных для компановки отчета - хоть это будет некий объект (таблица) как у меня в примере или запрос любой сложности) - здесь мы рассматриваем работу закладки "Вычисляемые поля". Порой, по своему опыту могу сказать, что корректно собрать вычисляемое поле бывает очень сложно, ввиду больших нагромождений формул с кучей параметром (производственные отчеты) - элементарно запутаешься через 10-15 минут "на вводе начальных данных".
Давайте сделаем основные выводы и напишем заключение по этой публикации.
Выводы и заключение
В данной публикации я показал вам как можно использовать "внешние функции" в отчетах СКД. Статья написана исключительно по собственному опыту созданию сложных производственных огромных отчетов в СКД.
Основное удобство этого способа, на мой взгляд, это возможность использования одного и того же алгоритма (он написан один раз и "в одном месте") для нескольких отчетов на СКД. Также, удобно перенести расчет поля в отдельную функцию, а не "городить код" и не вычислять поле в маленькой строчке закладки "Вычисляемые поля".
Это из плюсов.
Из минусов то, что "внешние функции" должны быть находится в самой конфигурации в общем модуле, или в отчете (но отчет должен быть встроен). Не всегда возможно оперативно обновлять конфигурацию. Иногда, возможно только раз в неделю....
Я попробовал обойти данный минус, поместив "внешние функции" в общий серверный модуль в расширение для конфигурации. Тип расширения поставил как "Дополнение". Как все мы убедились - сработало.
Буду рад, если вам понравилась эта статья.
Надеюсь, что для кого-то я пишу действительно полезные, понятные и удобные вещи, которые сделают ваш код более понятным, читаемым - в первую очередь для вас же самих. Ускорят вам выполнение ваших задач. Еще раз напишу, что все это я делаю исходя из своего опыта.
Всем привет! Спасибо, что дочитали этот материал до конца!
Предыдущие материалы
Так же, прошу посмотреть мои предыдущие статьи:
Лайфхак работы с СКД. Собираем отчет