Разберем актуальную задачу: создание консолидированного отчета «Продажи», который должен в режиме реального времени собирать, агрегировать и выводить данные из нескольких территориально распределенных информационных баз. При этом решение должно быть универсальным (работать в толстом, тонком и веб-клиенте) и оформлено в виде внешнего отчета .erf.
Проанализируем ситуацию. Основная сложность заключается не в самом тексте запроса, а в архитектуре получения данных, обеспечении производительности на низкоскоростных каналах связи и правильной передаче результатов в систему компоновки данных (СКД).
Рассмотрим наиболее классический вариант для внешнего отчета — использование механизма COM. Этот метод позволяет подключиться к удаленной базе напрямую, выполнить там запрос и забрать результат. Однако важно помнить, что этот метод плохо подходит для веб-клиента и серверов на базе Linux.
Выясним алгоритм действий для реализации этого метода в модуле отчета:
V83.COMConnector.Посмотрим на пример кода для установки соединения и получения данных:
// Функция получения данных из одной удаленной базы
Функция ПолучитьДанныеИзУдаленнойБазы(СтрокаПодключения, ПараметрыОтчета)
COMСоединитель = Новый COMОбъект("V83.COMConnector");
Попытка
УдаленнаяБаза = COMСоединитель.Connect(СтрокаПодключения);
Исключение
ЗаписатьЛогОшибок("Не удалось подключиться к базе: " + ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
Запрос = УдаленнаяБаза.NewObject("Запрос");
Запрос.Текст =
"ВЫБРАТЬ
| ВыручкаИПродажи.Номенклатура.Наименование КАК Номенклатура,
| СУММА(ВыручкаИПродажи.Количество) КАК Количество,
| СУММА(ВыручкаИПродажи.СуммаВыручки) КАК Сумма
|ИЗ
| РегистрНакопления.ВыручкаИПродажи КАК ВыручкаИПродажи
|ГДЕ
| ВыручкаИПродажи.Период МЕЖДУ &НачалоПериода И &КонецПериода
|СГРУППИРОВАТЬ ПО
| ВыручкаИПродажи.Номенклатура.Наименование";
Запрос.УстановитьПараметр("НачалоПериода", ПараметрыОтчета.НачалоПериода);
Запрос.УстановитьПараметр("КонецПериода", ПараметрыОтчета.КонецПериода);
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
// Преобразование COM-таблицы в локальную таблицу значений 1С
ЛокальнаяТЗ = ПреобразоватьComТЗвЛокальную(РезультатЗапроса);
Возврат ЛокальнаяТЗ;
КонецФункции
Важный нюанс: при использовании COM данные возвращаются в виде специфических объектов. Чтобы передать их в СКД центральной базы, их необходимо перегнать в обычную ТаблицаЗначений.
Проанализируем современный подход. Если в задании указано требование работы в веб-клиенте и наличие низкоскоростных соединений, то HTTP-сервисы — лучший выбор. В каждой региональной базе публикуется HTTP-сервис, который принимает параметры (период, отборы), выполняет запрос на месте и возвращает сжатый JSON.
Разберем преимущества этого способа:
В тексте внешнего отчета выполнение запроса будет выглядеть так:
HTTPСоединение = Новый HTTPСоединение("region-server.com", , "user", "password");
HTTPЗапрос = Новый HTTPЗапрос("/v1/sales_report?start=" + ФорматДаты(НачалоПериода));
Ответ = HTTPСоединение.Получить(HTTPЗапрос);
Если Ответ.КодСостояния = 200 Тогда
ДанныеJSON = Ответ.ПолучитьТелоКакСтроку();
ТаблицаРегиона = ПрочитатьJSONВТаблицу(ДанныеJSON);
КонецЕсли;
Как сделать так, чтобы полученная таблица значений отобразилась в стандартном отчете с пользовательскими настройками? Выясним, как использовать Систему Компоновки Данных (СКД) с внешним источником.
Рассмотрим шаги настройки схемы компоновки:
ВнешниеДанныеПродаж.ПриКомпоновкеРезультата, передадим нашу собранную таблицу в процессор компоновки.Пример программного вывода отчета с внешним набором данных:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь; // Отключаем стандартный вывод
// 1. Собираем данные из всех источников в одну ТЗ
ОбщаяТаблицаДанных = СобратьДанныеСоВсехБаз();
// 2. Инициализируем настройки
СхемаКомпоновкиДанных = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
// 3. Передаем внешнюю таблицу в СКД
ВнешниеНаборыДанных = Новый Структура;
ВнешниеНаборыДанных.Вставить("ВнешниеДанныеПродаж", ОбщаяТаблицаДанных);
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры
Выясним причину медленной работы подобных отчетов. Чаще всего программисты пытаются выгрузить детальные записи регистра из удаленной базы в центральную. Это в корне неверно.
Золотое правило агрегации: Суммируйте и группируйте данные на стороне «источника». Если пользователю нужен отчет по месяцам в разрезе складов, удаленная база должна вернуть ровно столько строк, сколько комбинаций «Месяц + Склад» существует, а не тысячи строк отдельных документов продажи.
Дополнительно рекомендуется:
Таким образом, мы проанализировали два основных способа реализации. Для быстрого решения «здесь и сейчас» в рамках одного офиса подойдет COM-соединение. Для профессиональной промышленной эксплуатации в распределенной сети с веб-доступом единственным верным решением будет использование HTTP-сервисов и передача агрегированных данных во Внешний набор данных СКД.