Почему возникает ошибка «СКД. Не найден внешний набор данных "ТЗ"» и как исправить неработающую расшифровку отчета?

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

При работе с Системой Компоновки Данных (СКД) в 1С:Предприятии 8 часто возникает необходимость программного формирования отчетов, используя в качестве источника данных не запросы к базе данных, а собственные таблицы значений (ТЗ). Это очень удобный и гибкий подход, позволяющий предварительно обработать данные или собрать их из разных источников перед передачей в СКД. Однако на этом пути разработчики сталкиваются с двумя частыми проблемами: ошибкой "СКД. Не найден внешний набор данных "ТЗ"" и некорректной работой расшифровки полей отчета.

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

1. Устраняем ошибку «СКД. Не найден внешний набор данных "ТЗ"»

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

1.1. Отключаем стандартную обработку в процедуре ПриКомпоновкеРезультата

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

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


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

    // *** Важный шаг: Отключаем стандартную обработку платформы ***
    СтандартнаяОбработка = Ложь;

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

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

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

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

    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    // Если отчет выводится в элемент формы, используем его
    // Если же это внешний отчет или обработка, ДокументРезультат - это переданный табличный документ
    ПроцессорВывода.УстановитьДокумент(ДокументРезультат); 
    ПроцессорВывода.Вывести(Процессор);

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

Как только вы добавите строку СтандартнаяОбработка = Ложь;, вы увидите, что ошибка "Не найден внешний набор данных" исчезнет, а отчет будет формироваться без предварительного сбоя.

1.2. Проверяем соответствие имен внешнего набора данных

Еще одной частой причиной, по которой СКД "не находит" внешний набор данных, является несоответствие имен. СКД должна четко понимать, как соотнести данные, которые вы ей передаете из кода, с тем набором данных, который описан в ее схеме.

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

  2. Ключ структуры во внешнем наборе: В вашем программном коде, когда вы создаете структуру для передачи внешних данных, вы указываете ключ, который соответствует имени объекта. Например: ВнешнийНабор = Новый Структура("ТЗ", ТЗ);. Здесь "ТЗ" является ключом структуры.

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

Пример правильного кода:


// В коде 1С:
ТЗ = Новый ТаблицаЗначений;
// ... заполнение ТЗ
ВнешнийНабор = Новый Структура("ТЗ", ТЗ); 
// Здесь ключ "ТЗ"

// В схеме СКД, для набора данных типа "Объект":
// Поле "Имя объекта, содержащего данные" должно быть установлено как "ТЗ"

2. Решаем проблему с расшифровкой полей отчета

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

2.1. Корректное описание типов колонок ТЗ и полей в СКД

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

Ваш пример кода для описания типов колонок ТЗ абсолютно верен:


ТЗ.Колонки.Добавить("Склад", Новый ОписаниеТипов("СправочникСсылка.Склады"));
ТЗ.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТЗ.Колонки.Добавить("ХарактеристикаНоменклатуры", Новый ОписаниеТипов("СправочникСсылка.ХарактеристикиНоменклатуры"));
ТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
ТЗ.Колонки.Добавить("РозничнаяЦена", Новый ОписаниеТипов("Число"));

В дополнение к этому, обязательно проверьте, что в самой схеме СКД, на вкладке "Наборы данных", для полей вашего набора данных типа "Объект" также корректно указаны типы. Имена полей в схеме СКД должны точно соответствовать именам колонок вашей таблицы значений. СКД использует эти метаданные для формирования структуры расшифровки и для правильной интерпретации данных.

Например, для колонки "Склад" в СКД должен быть указан тип "СправочникСсылка.Склады", для "Номенклатура" — "СправочникСсылка.Номенклатура" и так далее.

2.2. Передача объекта ДанныеРасшифровки

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

Объект ДанныеРасшифровки необходимо создать и передать в двух местах при программном формировании отчета:

  1. При вызове КомпоновщикМакета.Выполнить():

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

    Обратите внимание на третий параметр ДанныеРасшифровки.

  2. При вызове ПроцессорКомпоновкиДанных.Инициализировать():

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

    Здесь ДанныеРасшифровки также передается как третий параметр.

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

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

2.3. Обработка расшифровки в форме отчета

Даже при правильной передаче объекта ДанныеРасшифровки, интерактивная расшифровка может требовать дополнительной обработки. Автоматическая расшифровка (например, открытие карточки элемента справочника) может не работать "из коробки" для внешних наборов данных так же, как для запросов. Часто для ее реализации требуется доработка в процедуре ОбработкаРасшифровки табличного документа.

Эта процедура вызывается, когда пользователь кликает по ячейке с данными расшифровки. В ней вы получаете объект расшифровки, анализируете его и принимаете решение, какое действие выполнить. Например, вы можете:

Пример упрощенной процедуры ОбработкаРасшифровки (предполагая, что Результат — это имя элемента формы типа ПолеТабличногоДокумента):


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

    ЗначениеРасшифровки = Расшифровка.ПолучитьПоля()[0].Значение;

    Если ТипЗнч(ЗначениеРасшифровки) = Тип("СправочникСсылка.Склады") Тогда
        // Открываем форму элемента справочника "Склады"
        ОткрытьЗначение(ЗначениеРасшифровки);
    ИначеЕсли ТипЗнч(ЗначениеРасшифровки) = Тип("СправочникСсылка.Номенклатура") Тогда
        // Открываем форму элемента справочника "Номенклатура"
        ОткрытьЗначение(ЗначениеРасшифровки);
    // ... и так далее для других типов
    Иначе
        // Если тип не распознан, можно включить стандартную обработку или ничего не делать
        СтандартнаяОбработка = Истина; 
    КонецЕсли;

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

В этой процедуре вы самостоятельно обрабатываете полученные данные расшифровки, что позволяет вам полностью контролировать поведение отчета при интерактивном взаимодействии.

2.4. Проверка полей в настройках СКД

Убедитесь, что все необходимые поля, для которых вы ожидаете расшифровку, выведены в настройки компоновки отчета. Если поле присутствует в наборе данных СКД, имеет правильный тип, но не включено в выбранные поля или группировки на вкладках "Настройки" -> "Выбранные поля" или "Настройки" -> "Поля группировки", то СКД не будет генерировать для него данные расшифровки в отчете. Иногда, кажется, что расшифровка не работает, а на самом деле просто нет данных для расшифровки в выходном макете.

3. Альтернативный способ передачи данных: Временные таблицы

В некоторых случаях, особенно если ваша таблица значений должна быть объединена с данными из базы данных или требует более сложной обработки на стороне запроса, может быть удобнее использовать временные таблицы СКД. Этот подход позволяет передать вашу ТЗ во временную таблицу, а затем работать с ней в запросах СКД как с обычной таблицей базы данных.

Разберем шаги:

  1. Формируем запрос для создания временной таблицы: Сначала создаем запрос, который поместит вашу таблицу значений во временную таблицу.

  2. Создаем менеджер временных таблиц: Этот менеджер нужен для того, чтобы временная таблица была доступна для последующих запросов.

  3. Устанавливаем параметр и выполняем запрос: Передаем вашу ТЗ как параметр запроса.

  4. Используем временную таблицу в СКД: В схеме СКД вы теперь можете написать запрос, который обращается к этой временной таблице.

Пример кода:


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

    СтандартнаяОбработка = Ложь;

    // Ваша ТаблицаЗначений
    МояТЗ = Новый ТаблицаЗначений;
    МояТЗ.Колонки.Добавить("Склад", Новый ОписаниеТипов("СправочникСсылка.Склады"));
    МояТЗ.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
    МояТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
    
    // Заполняем МояТЗ
    МояТЗ.Добавить().Склад = Справочники.Склады.НайтиПоНаименованию("Основной склад");
    МояТЗ.Добавить().Номенклатура = Справочники.Номенклатура.НайтиПоНаименованию("Товар А");
    МояТЗ.Добавить().Количество = 100;

    // 1. Создаем менеджер временных таблиц
    МВТ = Новый МенеджерВременныхТаблиц;

    // 2. Запрос для помещения ТЗ во временную таблицу
    ЗапросПоместитьТЗ = Новый Запрос;
    ЗапросПоместитьТЗ.Текст = "ВЫБРАТЬ
                              |    Склад,
                              |    Номенклатура,
                              |    Количество
                              |ПОМЕСТИТЬ ВТ_МояТЗ
                              |ИЗ
                              |    &МояТЗ КАК МояТЗ";
    ЗапросПоместитьТЗ.МенеджерВременныхТаблиц = МВТ;
    ЗапросПоместитьТЗ.УстановитьПараметр("МояТЗ", МояТЗ);
    ЗапросПоместитьТЗ.Выполнить();

    // Теперь в схеме СКД вы можете использовать запрос:
    // "ВЫБРАТЬ Склад, Номенклатура, Количество ИЗ ВТ_МояТЗ КАК ВТ_МояТЗ"
    // Или объединять ее с другими таблицами базы данных.

    Схема = ЭтотОбъект.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
    Настройки = Схема.НастройкиПоУмолчанию;

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

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

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

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

Важно: При использовании временных таблиц, в ПроцессорКомпоновкиДанных.Инициализировать() мы больше не передаем внешний набор данных (передаем Неопределено вместо ВнешнийНабор). Вместо этого мы передаем менеджер временных таблиц с помощью метода Процессор.УстановитьМенеджерВременныхТаблиц(МВТ);.

Этот подход может быть более производительным и гибким, если ваша ТЗ очень большая или требует сложных манипуляций вместе с данными из СУБД, так как вся обработка данных происходит на стороне сервера в запросах.

Заключение

Программное формирование отчетов СКД с внешними таблицами значений — мощный инструмент для создания кастомизированных аналитических форм. Мы выяснили, что ошибка "Не найден внешний набор данных "ТЗ"" чаще всего связана с необходимостью установки СтандартнаяОбработка = Ложь; в процедуре ПриКомпоновкеРезультата и строгим соответствием имен внешних наборов данных между вашим кодом и схемой СКД.

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

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

← На главную