При работе с расширениями в системе 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда Система Компоновки Данных (СКД) в отчетах не "видит" или не предоставляет доступ к некоторым реквизитам объектов, которые, казалось бы, доступны в основной конфигурации или даже добавлены в само расширение. Рассмотрим подробно проблему, когда отчет, созданный в расширении и использующий регистр бухгалтерии, не отображает поля документа-регистратора, такие как контрагент или договор.
Представьте следующую ситуацию: мы создали расширение для типовой конфигурации, например, "Бухгалтерия КОРП МСФО". В это расширение были добавлены существующий документ "Поступление (акты, накладные)" и регистр бухгалтерии "Хозрасчетный". Для нового отчета на СКД, который выбирает данные из виртуальной таблицы оборотов регистра бухгалтерии, нам необходимо вывести и использовать в отборах реквизиты документа-регистратора, такие как "Контрагент" и "Договор". Однако, несмотря на то что документ корректно открывается в тонком клиенте и позволяет фильтровать по этим полям в списках, в конструкторе запросов СКД они оказываются недоступными. Это достаточно распространенная проблема, и мы разберем её причины и способы решения.
Давайте выясним основные причины, по которым возникает эта сложность:
Ограниченная видимость метаданных в расширениях: Конструктор запросов и СКД в конфигураторе имеют особенности при работе с метаданными, которые были добавлены или заимствованы в расширение. Объекты, внесенные в расширение конфигурации, не всегда полностью доступны во внешних отчетах или обработках на этапе разработки в конфигураторе. Это означает, что хотя объекты существуют и функционируют в режиме "1С:Предприятие", на этапе проектирования в конфигураторе их структура может быть видна не полностью.
Проблемы с заимствованием: Хотя заимствование объектов (документов, регистров, справочников, их реквизитов, табличных частей, форм) из основной конфигурации в расширение является одним из способов решения проблем с видимостью, оно не всегда срабатывает для всех связанных метаданных или их глубоких связей. Более того, заимствование большого количества объектов может значительно усложнить процесс обновления и анализа изменений в расширении, что создает дополнительные трудности.
Доступность стандартных реквизитов: Даже если сам объект заимствован, стандартные реквизиты (например, "ЭтоГруппа" у справочника или "Владелец" для подчиненного справочника) могут быть недоступны в конструкторе запросов в расширении. Для их корректного отображения иногда требуется явно указывать свойства как "контролируемые" в расширении, что требует ручной работы и внимания.
Ошибки доступа: При обращении СКД отчета из расширения к несуществующему типу объектов или к полям, которые не были правильно определены, может возникать ошибка при получении информации из набора данных. Также проблемы могут быть связаны с правами доступа или функциональными опциями, которые скрывают определенные поля от пользователя или подсистемы.
Когда мы сталкиваемся с такой проблемой, первое, что мы обычно пытаемся сделать, это убедиться, что все необходимые объекты добавлены в расширение. В нашем случае, автор уже попытался:
Добавить сам документ "Поступление (акты, накладные)" в расширение. Это базовый шаг, чтобы СКД вообще могла оперировать этим типом документа.
Добавить в расширение реквизиты документа, такие как "Контрагент", "Договор". Это должно обеспечить видимость этих конкретных полей.
Добавить связанные справочники, например, "Контрагенты" и "Договоры контрагентов", в расширение. Часто СКД требует, чтобы не только сам реквизит, но и тип данных, на который он ссылается, был виден в контексте расширения.
Однако, как показала практика автора, даже выполнение всех этих шагов не всегда приносит желаемый результат. Он подтвердил, что все эти объекты были добавлены, но СКД по-прежнему не видела поля "Контрагент" и "Договор" из регистратора. Это указывает на более глубокую проблему в работе конструктора запросов СКД в контексте расширений.
Прежде чем перейти к окончательному решению, которое нашел автор, рассмотрим несколько других методов, которые могут быть полезны в схожих ситуациях:
Разработка схемы СКД через консоль СКД в режиме "1С:Предприятие": Консоль СКД, запущенная в пользовательском режиме, способна видеть таблицы из всех активных расширений при наличии соответствующих прав. Мы можем использовать этот подход для создания или отладки запроса. Для этого:
Прямое редактирование текста запроса: Если конструктор запросов не справляется с задачей, мы можем вручную написать или скорректировать текст запроса. Этот текст затем можно вставить в схему компоновки данных напрямую, минуя конструктор. Этот метод требует хорошего знания языка запросов 1С и внимательности, поскольку ошибки в запросе не будут подсвечены конструктором.
Использование расширения языка запросов для СКД: В СКД есть возможность использовать расширения языка запросов, которые позволяют, например, подключать характеристики объектов через конструкции типа `ХАРАКТЕРИСТИКИ`. Это может быть полезно для более сложных сценариев, когда нужно получить данные, связанные с дополнительными свойствами объектов.
Виртуальные таблицы: При работе с виртуальными таблицами в запросах (как в нашем случае, таблица оборотов регистра бухгалтерии) рекомендуется передавать в параметры таблиц все относящиеся к ним условия (например, период, отбор по счету). Это помогает оптимизировать запрос и обеспечивает более точное получение данных. Следует учитывать, что СКД может автоматически вставлять дополнительные отборы в виртуальные таблицы, что иногда нежелательно и требует контроля.
В случае, когда никакие из вышеперечисленных методов не дали результата, или когда требуется особая гибкость и динамичность в формировании запроса, мы можем воспользоваться мощным механизмом — процедурой обработчика события ПриКомпоновкеРезультата. Именно этот метод помог автору решить его проблему.
Процедура ПриКомпоновкеРезультата вызывается при формировании отчета, непосредственно перед выполнением запроса, и позволяет нам переопределить или дополнить стандартное поведение генерации отчета. Это идеальное место для динамической модификации запроса, когда декларативный подход СКД не позволяет достичь нужной гибкости или обойти ограничения конфигуратора в расширении.
Разберем по шагам, как применить это решение:
Создаем "пустую" выборку в СКД с нужными колонками и типами данных: В конфигураторе, в схеме компоновки данных нашего отчета, мы создаем набор данных типа "Запрос". В нем мы можем указать простейший запрос, который служит лишь "заглушкой", чтобы СКД могла сформировать структуру полей, их типы и заголовки. Главное, чтобы имена полей соответствовали тем, которые мы хотим получить в итоговом запросе. Например:
ВЫБРАТЬ
0 КАК СуммаОборот,
NULL КАК Контрагент,
NULL КАК Договор
ИЗ
РегистрБухгалтерии.Хозрасчетный.Обороты(, , , , , , , ) КАК ХозрасчетныйОбороты
ГДЕ ЛОЖЬ
Здесь мы указываем поля, которые нам нужны, и их примерные типы данных. Условие `ГДЕ ЛОЖЬ` гарантирует, что этот "заглушечный" запрос никогда не вернет реальных данных, но позволит СКД "увидеть" метаданные.
Переопределяем текст запроса в процедуре ПриКомпоновкеРезультата: В модуле отчета мы находим или создаем обработчик события ПриКомпоновкеРезультата для нашего набора данных. В этой процедуре мы получаем доступ к объекту схемы компоновки данных и можем динамически изменить текст запроса для нашего набора данных.
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// Отключаем стандартную обработку, чтобы полностью взять контроль
СтандартнаяОбработка = Ложь;
// Получаем схему компоновки данных из макета отчета
СхемаКомпоновкиДанных = КомпоновщикМакета.Настройки.СхемаКомпоновкиДанных;
// Находим нужный набор данных по имени
НаборДанных = СхемаКомпоновкиДанных.НаборыДанных.Найти("НаборДанных1"); // "НаборДанных1" - это имя нашего набора данных в СКД
Если НаборДанных <> Неопределено И ТипЗнч(НаборДанных) = Тип("НаборДанныхЗапрос") Тогда
// Формируем корректный текст запроса, который видит все нужные поля
// Здесь мы можем использовать тот же запрос, который мы бы написали,
// если бы СКД работала без проблем, или более сложный динамический запрос.
НовыйТекстЗапроса = "
|ВЫБРАТЬ
| ХозрасчетныйОбороты.СуммаОборот КАК СуммаОборот,
| ХозрасчетныйОбороты.Регистратор.Контрагент КАК Контрагент,
| ХозрасчетныйОбороты.Регистратор.Договор КАК Договор
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Обороты(&НачалоПериода, &КонецПериода, Регистратор, , , , , ) КАК ХозрасчетныйОбороты
|ГДЕ
| ХозрасчетныйОбороты.Счет.Код = ""60.01""
|"; // Пример простого запроса
// Можно добавить параметры запроса, если они используются
// Например, ПараметрПериода = КомпоновщикНастроек.Настройки.ПараметрыДанных.Найти("Период");
// и передать их в запрос, если они не будут обрабатываться СКД.
// Устанавливаем новый текст запроса для набора данных
НаборДанных.Запрос = НовыйТекстЗапроса;
// Теперь, когда запрос изменен, выполняем стандартную компоновку,
// но уже с нашим модифицированным запросом.
// Для этого обычно создают свой собственный макет и компоновщик
// и выполняют компоновку вручную, но можно и продолжить стандартную,
// если остальные настройки СКД не требуют изменений.
// Если мы полностью взяли контроль, то дальнейшая компоновка
// должна быть выполнена нами.
// Приведем более полный пример, который включает вызов компоновщика:
// Получаем макет компоновки данных
МакетКомпоновкиДанных = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.Настройки, ДанныеРасшифровки);
// Создаем процессор компоновки данных
ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновкиДанных, , ДанныеРасшифровки);
// Создаем процессор вывода результата
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
// Выводим результат
ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);
КонецЕсли;
КонецПроцедуры
Таким образом, мы сначала создаем в СКД структуру, которая "обманывает" конфигуратор, сообщая ему о наличии нужных полей. А затем, в режиме "1С:Предприятие", в обработчике события ПриКомпоновкеРезультата, мы программно подменяем запрос на тот, который корректно обращается ко всем необходимым полям документа-регистратора. Этот подход позволяет обойти ограничения конструктора запросов в конфигураторе и использовать всю мощь СКД и языка запросов 1С.
Этот метод, а именно динамическое изменение текста запроса в процедуре ПриКомпоновкеРезультата, является признанным и эффективным для обхода ограничений СКД в сложных сценариях, особенно при работе с расширениями. Установив СтандартнаяОбработка = Ложь, мы полностью берем на себя контроль над процессом формирования отчета, включая модификацию запроса схемы компоновки данных перед его выполнением. Это позволяет нам адаптировать запрос под любые условия и получать доступ к данным, которые не видны на этапе проектирования.