При разработке сложных отчетов в системе компоновки данных (СКД) часто возникает задача дополнить результат информацией, которой нет в текущей базе 1С. Например, нам нужно вывести данные о водителях из 1С и сопоставить их с временем прихода из сторонней системы контроля доступа или логистического сервиса. В этой статье мы подробно разберем, как реализовать программное наполнение отчета данными из внешних источников.
Для решения этой задачи мы воспользуемся механизмом Набор данных - объект. Основная идея заключается в том, чтобы перехватить процесс формирования отчета, самостоятельно собрать все необходимые данные в таблицу значений (ТЗ) и передать эту таблицу в СКД. Рассмотрим пошаговый алгоритм реализации.
НаборДанныхОбъект и укажем имя его переменной (например, "АналитикаВремени").ПриКомпоновкеРезультата в модуле объекта отчета.Проанализируем программный код, который позволяет полностью контролировать процесс компоновки. Нам необходимо отключить стандартную обработку, чтобы платформа не пыталась сформировать отчет автоматически, так как на момент старта внешние данные еще не получены.
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// 1. Отключаем стандартный вывод отчета
СтандартнаяОбработка = Ложь;
// 2. Получаем основные данные из текущей базы запросом
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Водители.Ссылка КАК Водитель,
| Водители.НомерПропуска КАК НомерПропуска
|ИЗ
| Справочник.Водители КАК Водители";
РезультатЗапроса = Запрос.Выполнить();
ТаблицаРезультат = РезультатЗапроса.Выгрузить();
// 3. Добавляем колонку для внешних данных
ТаблицаРезультат.Колонки.Добавить("ВремяПрихода", Новый ОписаниеТипов("Дата"));
// 4. Опрашиваем внешнюю БД и заполняем таблицу
Для Каждого СтрокаТаблицы Из ТаблицаРезультат Цикл
Если ЗначениеЗаполнено(СтрокаТаблицы.НомерПропуска) Тогда
// Вызываем функцию общего модуля, которая идет во внешнюю базу (SQL, API, COM)
СтрокаТаблицы.ВремяПрихода = ОбщийМодульСервер.ПолучитьВремяИзВнешнейБД(СтрокаТаблицы.НомерПропуска);
КонецЕсли;
КонецЦикла;
// 5. Инициализируем схему и настройки
СхемаКомпоновкиДанных = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
// 6. Подготавливаем внешние наборы данных
ВнешнийНаборДанных = Новый Структура("АналитикаВремени", ТаблицаРезультат);
// 7. Компоновка макета
ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
// 8. Инициализация процессора компоновки с передачей внешних данных
ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
// КРИТИЧЕСКИ ВАЖНО: Разрешаем использование внешних функций, если они есть в СКД
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, ВнешнийНаборДанных, ДанныеРасшифровки, Истина);
// 9. Вывод результата в табличный документ
ДокументРезультат.Очистить();
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);
КонецПроцедуры
Проблема внешних функций: При программном формировании отчета часто возникает ошибка "Синтаксическая ошибка" при попытке вызвать функцию общего модуля из вычисляемых полей СКД. Выясним причину: в стандартном механизме 1С флаг использования внешних функций установлен в Истина по умолчанию. Однако при вызове метода Инициализировать() процессора компоновки вручную, этот флаг по умолчанию равен Ложь. Чтобы функции заработали, мы передали четвертый параметр Истина в метод Инициализировать.
Оптимизация получения данных: В приведенном примере мы используем цикл Для каждого для обращения к внешней БД. Если в отчете 1000 строк, система сделает 1000 отдельных запросов к сторонней базе, что крайне неэффективно. Рассмотрим более производительный подход:
ТаблицаРезультат в массив.WHERE TicketNumber IN (...) в SQL).Типизация колонок: При программном создании колонок в ТаблицаЗначений обязательно указывайте ОписаниеТипов. Если колонка будет без типа (содержать Произвольный), СКД может некорректно обрабатывать итоги, группировки или форматирование дат и чисел.
Существует еще один изящный способ. Мы можем оставить в СКД основной Набор данных - запрос (который берет водителей), а внешние данные передавать через второй Набор данных - объект, содержащий только "Номер пропуска" и "Время прихода".
Проанализируем преимущества такого подхода: нам не нужно вручную соединять таблицы в коде. Достаточно на закладке Связи наборов данных в конструкторе СКД указать связь по полю НомерПропуска. В этом случае СКД сама сопоставит строки, а программный код в ПриКомпоновкеРезультата станет значительно проще — достаточно будет только подготовить ТЗ с "приходами" и передать ее в структуру ВнешниеНаборыДанных.
Важно помнить, что современные отчеты в конфигурациях на базе БСП часто формируются в фоновом задании на сервере. Если ваша внешняя база доступна через специфический драйвер (например, ODBC) или COM-соединение, убедитесь, что соответствующие компоненты установлены именно на сервере 1С, а у пользователя, под которым запущен сервис 1С:Предприятия, есть права доступа к этим ресурсам. В противном случае отчет, успешно работающий у программиста на локальной машине (в файловом режиме), выдаст ошибку при работе в клиент-серверном варианте.