Как сохранить сформированный отчет СКД с фиксацией данных и работающими расшифровками?

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

При работе с аналитическими отчетами на базе Системы компоновки данных (СКД) часто возникает бизнес-требование: зафиксировать («заморозить») показатели отчета на определенный момент времени. Это критически важно для снабженцев, плановиков и сотрудников отдела материально-технического обеспечения (МТО). Зафиксированный отчет служит подтверждением того, на основании каких цифр (потребностей, остатков, заказов) принимались решения о закупках или производстве в конкретный день.

Стандартное сохранение отчета в формате табличного документа (.mxl) решает задачу фиксации цифр, но полностью ломает интерактивность: двойной клик по ячейке больше не открывает карточку номенклатуры, не показывает документы-регистраторы и не позволяет расшифровать показатель. С другой стороны, повторное формирование отчета за прошлую дату может выдать совершенно другие цифры из-за изменения исторических данных в базе (например, при проведении документов задним числом).

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

Выясняем причину: почему не работают стандартные расшифровки

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

Если мы просто сохраняем табличный документ в справочнике или файле, объект данных расшифровки теряется. Идентификаторы в ячейках становятся «пустышками», ссылающимися в никуда. Кроме того, важно помнить о важном техническом ограничении: объект ПроцессорКомпоновкиДанных не поддерживает сериализацию. Попытка напрямую записать его в базу данных или поместить в ХранилищеЗначения вызовет критическую ошибку платформы.

Давайте рассмотрим три практических способа решения этой задачи: от простого сохранения расшифровок до полноценной заморозки данных с помощью внешних наборов.

Решение 1: Сохранение связки «Табличный документ + Данные расшифровки»

Если пользователям достаточно базовой интерактивности (например, чтобы при двойном клике на номенклатуру открывалась ее карточка, а при клике на заказ — сам документ), мы можем сохранять данные расшифровки вместе с табличным документом.

Рассмотрим алгоритм реализации этого механизма шаг за шагом:

  1. При формировании отчета перехватываем объект ДанныеРасшифровки.
  2. Упаковываем сформированный табличный документ и объект расшифровки в одну структуру.
  3. Сериализуем эту структуру и записываем ее в реквизит справочника с типом ХранилищеЗначения.
  4. При восстановлении отчета извлекаем структуру, помещаем данные расшифровки во временное хранилище и связываем их с полем табличного документа на форме.

Проанализируем пример кода для сохранения сформированного отчета:


// Код выполняется на сервере при сохранении отчета
ДанныеДляСохранения = Новый Структура;
ДанныеДляСохранения.Вставить("ТабличныйДокумент", ЭтотОбъект.Результат);
ДанныеДляСохранения.Вставить("ДанныеРасшифровки", ПолучитьИзВременногоХранилища(ЭтотОбъект.ДанныеРасшифровки));

НовыйАрхив = Справочники.АрхивныеОтчеты.СоздатьЭлемент();
НовыйАрхив.Наименование = "Расчет потребности от " + Формат(ТекущаяДата(), "ДФ=dd.MM.yyyy");
НовыйАрхив.ДанныеОтчета = Новый ХранилищеЗначения(ДанныеДляСохранения, Новый СжатиеДанных(9));
НовыйАрхив.Записать();

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


// Код выполняется на сервере при открытии архивного элемента
СтруктураДанных = СсылкаНаАрхив.ДанныеОтчета.Получить();
Если ТипЗнч(СтруктураДанных) = Тип("Структура") Тогда
    
    // Восстанавливаем табличный документ на форме
    ЭтотОбъект.Результат.Вывести(СтруктураДанных.ТабличныйДокумент);
    
    // Помещаем сохраненные данные расшифровки во временное хранилище формы
    АдресРасшифровки = ПоместитьВоВременноеХранилище(СтруктураДанных.ДанныеРасшифровки, ЭтотОбъект.УникальныйИдентификатор);
    ЭтотОбъект.ДанныеРасшифровки = АдресРасшифровки;
    
КонецЕсли;

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

Решение 2: Использование СКД на основе внешнего набора данных (Идеальный вариант)

Чтобы гарантировать абсолютную неизменяемость данных при любых манипуляциях пользователя (группировка, фильтрация, детальная расшифровка по любым полям), необходимо перевести отчет на использование Набора данных - Объект (внешний источник данных в виде ТаблицыЗначений).

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

Рассмотрим пример настройки и формирования такого отчета:

  1. В схеме компоновки данных вместо стандартного набора данных "Запрос" создаем набор данных "Объект" с именем ТаблицаДанных.
  2. Описываем поля набора данных (например, Номенклатура, Склад, КоличествоПотребность).
  3. При первичном формировании заполняем эту таблицу запросом, сохраняем в базу данных, а при выводе передаем ее в процессор компоновки.

Проанализируем программный код вывода отчета через внешний набор данных:


// Пример формирования отчета по сохраненной таблице значений
Процедура ВывестиОтчетПоВнешнемуИсточнику(ТаблицаИсточник)

    СхемаКомпоновкиДанных = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
    Настройки = КомпоновщикНастроек.ПолучитьНастройки();
    
    ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
    
    // Передаем нашу зафиксированную таблицу значений во внешний набор данных
    ВнешниеНаборыДанных = Новый Структура;
    ВнешниеНаборыДанных.Вставить("ТаблицаДанных", ТаблицаИсточник);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки, Истина);
    
    РезультатТабличныйДокумент = Новый ТабличныйДокумент;
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(РезультатТабличныйДокумент);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
    // Выводим результат на форму
    Результат.Вывести(РезультатТабличныйДокумент);
    ЭтотОбъект.ДанныеРасшифровки = ПоместитьВоВременноеХранилище(ДанныеРасшифровки, УникальныйИдентификатор);

КонецПроцедуры

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

Решение 3: Архитектурный паттерн «Документ» вместо отчета

Давайте посмотрим на ситуацию с точки зрения архитектуры крупных ERP-систем. Если отчет по расчету потребности имеет юридическую силу, на его основе подписываются спецификации и закупаются материалы на миллионы рублей, использование отчетов для хранения этих состояний считается антипаттерном.

Вместо этого рекомендуется использовать объект конфигурации Документ (например, «Расчет потребности в запасах»):

Этот подход сложнее в реализации, но он обеспечивает максимальную надежность хранения данных, учет истории изменений и интеграцию с другими бизнес-процессами компании.

Резюме

Мы проанализировали проблему сохранения отчетов СКД с фиксацией данных и рассмотрели три варианта решения задачи. Для простых отчетов с минимальными требованиями к интерактивности подойдет Решение 1 с сохранением связки табличного документа и структуры расшифровки. Если пользователям необходим полноценный интерактивный анализ зафиксированных данных без риска их искажения, лучшим выбором будет Решение 2 с использованием СКД на базе внешних наборов данных. Для ответственных бизнес-процессов оптимальным решением является переход на полноценный объект конфигурации Документ.

← На главную