Как построить сводный отчет по продажам из двух информационных баз в 1С?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

Прежде чем приступать к реализации, проанализируем ограничения механизмов платформы, с которыми неизбежно придется столкнуться при объединении данных «на лету»:

  1. Ограничение СКД при работе с несколькими наборами данных: связь между набором типа «Запрос» и набором типа «Объект» в схеме СКД выполняется исключительно по принципу левого соединения. В СКД нет штатного механизма прямого объединения (аналога ОБЪЕДИНИТЬ ВСЕ) между разными наборами данных.
  2. Маршалинг и потеря производительности COM: прямое чтение ссылочных типов из удаленной базы через COMConnector приводит к отдельным межпроцессным вызовам на каждое обращение к реквизиту объекта, что делает формирование отчета крайне медленным.
  3. Разрыв ссылочной целостности: ссылки удаленной базы недействительны в контексте текущей информационной базы. При передаче объектов без преобразования интерактивная расшифровка работать не будет.

Вариант 1. Загрузка агрегированных данных через COM во временную таблицу

Наиболее контролируемый подход при формировании отчета «на лету» — выполнение запроса на стороне удаленной базы с получением уже свернутых данных, передача их в виде примитивных типов и последующее объединение в локальном запросе СКД через МенеджерВременныхТаблиц.

Разберем по шагам, как правильно реализовать этот механизм:

  1. В удаленной базе выполняем запрос, который группирует продажи до нужной детализации и преобразует ссылки в уникальные идентификаторы (GUID) или строковые представления.
  2. Полученную таблицу значений передаем в текущую базу и загружаем в локальную ТаблицаЗначений с явной типизацией колонок.
  3. В основном запросе СКД локальной базы помещаем внешнюю таблицу во временную таблицу через пакетный запрос и выполняем ОБЪЕДИНИТЬ ВСЕ с локальным регистром.
  4. По строковым GUID восстанавливаем локальные ссылки с помощью метода ПолучитьСсылку() менеджера соответствующего справочника, что возвращает отчету возможность группировок по иерархии и стандартной расшифровки.

Посмотрим на пример кода получения данных через COM-соединение:


Функция ПолучитьПродажиУдаленнойБазы(СтрокаПодключения, ДатаНач, ДатаКон)
    РезультатТЗ = Новый ТаблицаЗначений;
    РезультатТЗ.Колонки.Добавить("НоменклатураГУИД", Новый ОписаниеТипов("Строка",,,, Новый КвалификаторыСтроки(36)));
    РезультатТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
    РезультатТЗ.Колонки.Добавить("СуммаВыручки", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));

    Попытка
        V83COM = Новый COMОбъект("V83.COMConnector");
        Соединение = V83COM.Connect(СтрокаПодключения);
    Исключение
        ВызватьИсключение "Не удалось подключиться ко второй базе: " + ОписаниеОшибки();
    КонецПопытки;

    ЗапросCOM = Соединение.NewObject("Запрос");
    ЗапросCOM.Текст = 
        "ВЫБРАТЬ
        |   ПродажиОбороты.Номенклатура.УникальныйИдентификатор КАК НоменклатураГУИД,
        |   ПродажиОбороты.КоличествоОборот КАК Количество,
        |   ПродажиОбороты.СтоимостьОборот КАК СуммаВыручки
        |ИЗ
        |   РегистрНакопления.Продажи.Обороты(&ДатаНач, &ДатаКон, Авто, ) КАК ПродажиОбороты";

    ЗапросCOM.УстановитьПараметр("ДатаНач", ДатаНач);
    ЗапросCOM.УстановитьПараметр("ДатаКон", ДатаКон);

    Выборка = ЗапросCOM.Выполнить().Выбрать();
    Пока Выборка.Следующий() Цикл
        Стр = РезультатТЗ.Добавить();
        Стр.НоменклатураГУИД = Строка(Выборка.НоменклатураГУИД);
        Стр.Количество = Выборка.Количество;
        Стр.СуммаВыручки = Выборка.СуммаВыручки;
    КонецЦикла;

    Возврат РезультатТЗ;
КонецФункции

Теперь рассмотрим, как объединить эту таблицу с данными текущей информационной базы в модуле отчета перед формированием схемы компоновки:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;

    // Получаем внешние данные
    ВнешниеПродажи = ПолучитьПродажиУдаленнойБазы(ПараметрыПодключения, ПериодНачало, ПериодКонец);

    // Добавляем локальные ссылки по GUID
    ВнешниеПродажи.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
    Для Каждого Стр Из ВнешниеПродажи Цикл
        Стр.Номенклатура = Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор(Стр.НоменклатураГУИД));
    КонецЦикла;

    // Передаем таблицу параметров в запрос СКД через набор данных
    ВнешниеНаборы = Новый Структура;
    ВнешниеНаборы.Вставить("ТаблицаВнешнихПродаж", ВнешниеПродажи);

    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    Макет = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки(), ДанныеРасшифровки);

    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(Макет, ВнешниеНаборы, ДанныеРасшифровки);

    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры

В тексте запроса набора данных СКД используем временную таблицу и оператор объединения:


ВЫБРАТЬ
    ТЗ.Номенклатура КАК Номенклатура,
    ТЗ.Количество КАК Количество,
    ТЗ.СуммаВыручки КАК СуммаВыручки
ПОМЕСТИТЬ ВТ_ВнешниеПродажи
ИЗ
    &ТаблицаВнешнихПродаж КАК ТЗ
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ПродажиОбороты.Номенклатура КАК Номенклатура,
    ПродажиОбороты.КоличествоОборот КАК Количество,
    ПродажиОбороты.СтоимостьОборот КАК СуммаВыручки
ИЗ
    РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, Авто, ) КАК ПродажиОбороты

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ВТ.Номенклатура,
    ВТ.Количество,
    ВТ.СуммаВыручки
ИЗ
    ВТ_ВнешниеПродажи КАК ВТ

Вариант 2. Использование Web-сервисов или HTTP-сервисов

Если базы физически распределены, находятся в разных сегментах сети или сервер 1С работает под управлением 64-разрядной ОС (где использование 32-разрядного COMConnector требует отдельной настройки приложений COM+), COM-соединение становится ненадежным. В этом случае правильнее поднять сервис во второй базе.

Важно помнить: объект ТаблицаЗначений не поддерживается фабрикой XDTO напрямую. Для его передачи через сервис применяем один из способов:

  1. Формирование массива структур и сериализация в JSON (наиболее производительный и универсальный способ для HTTP-сервисов).
  2. Преобразование таблицы значений в XML с помощью объекта ЗаписьXML и метода СериализаторXDTO.ЗаписатьXML().
  3. Упаковка во внутренний формат платформы через ЗначениеВСтрокуВнутр() или ЗначениеВФайл() с передачей через SOAP как base64Binary.

Вариант 3. Асинхронное кэширование в регистр сведений (рекомендуемый)

Динамическое получение данных при каждом нажатии кнопки «Сформировать» имеет существенный недостаток: если удаленная база заблокирована, выполняет регламентные операции или связь нестабильна, формирование отчета завершается аварийно либо надолго блокирует сеанс пользователя.

Для стабильной работы применяем архитектуру с кэшированием:

  1. Создаем в основной базе непериодический регистр сведений (например, ПродажиУдаленнойБазы) с измерениями ПериодДень, Номенклатура, Организация и ресурсами Количество, Сумма.
  2. Настраиваем регламентное задание, которое раз в час или ночью подключается ко второй базе и обновляет движения регистра за открытый интервал дат.
  3. В СКД строим типовой отчет по двум локальным таблицам через стандартный оператор ОБЪЕДИНИТЬ ВСЕ.

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

← На главную