Почему реквизит расширения не виден во внешней обработке и как это исправить

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

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

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

Выясним причину: почему возникает конфликт контекстов

Для начала разберем ситуацию с точки зрения архитектуры платформы. Внешняя обработка (файл .epf) — это объект, который при открытии в режиме «Предприятие» компилируется и выполняется в контексте основной конфигурации. На уровне платформы (особенно это было характерно для версий 8.3.12–8.3.14) существует жесткое разграничение: код внешнего файла «не знает» о существовании метаданных, добавленных в расширениях, пока не будет принудительно помещен в их область видимости.

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

Способ 1: Программная подмена текста запроса (Метод замены)

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

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

  1. В Конструкторе запроса вместо реального поля из расширения (которого там нет в списке) выберем любое стандартное поле, которое точно существует, например, Ссылка.
  2. В тексте запроса это будет выглядеть как Товары.Ссылка КАК ПолеИзРасширения.
  3. Перед выполнением запроса программно заменим это техническое поле на имя нашего реального реквизита из расширения.

Посмотрим на пример кода:


ТекстЗапроса = 
"ВЫБРАТЬ
|	ДокументТовары.Ссылка КАК Ссылка,
|	ДокументТовары.НомерСтроки КАК НомерСтроки,
|	ДокументТовары.Ссылка КАК МойСобственныйРеквизит
|ИЗ
|	Документ.ЗаказКлиента.Товары КАК ДокументТовары
|ГДЕ
|	ДокументТовары.Ссылка = &Ссылка";

// Производим подмену текста, чтобы запрос обратился к реальному полю БД
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ДокументТовары.Ссылка КАК МойСобственныйРеквизит", "ДокументТовары.ИмяРеквизитаИзРасширения");

Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("Ссылка", ОбъектСсылка);
Результат = Запрос.Выполнить();

Этот метод работает, потому что в режиме «Предприятие» при непосредственном выполнении запроса база данных уже оперирует объединенной схемой (Конфигурация + все активные Расширения), и поле будет успешно найдено.

Способ 2: Использование общего модуля расширения как «прослойки»

Более правильным с точки зрения архитектуры решением является вынос логики получения данных непосредственно внутрь расширения. Так как код, написанный внутри расширения, имеет полный доступ ко всем своим реквизитам, мы можем создать «сервисную» функцию.

Разберем этот алгоритм:

  1. Создадим в расширении новый Общий модуль.
  2. Установим ему свойства: Сервер, Вызов сервера. Флаг Глобальный ставить не нужно.
  3. Напишем в нем экспортную функцию, которая принимает ссылку на документ и возвращает таблицу значений с нужными данными.

Пример кода в общем модуле расширения (назовем его рш_РаботаСДанными):


Функция ПолучитьДанныеДляПечати(ДокументСсылка) Экспорт
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	Товары.Номенклатура,
        |	Товары.МойРеквизитИзРасширения
        |ИЗ
        |	Документ.РеализацияТоваровУслуг.Товары КАК Товары
        |ГДЕ
        |	Товары.Ссылка = &Ссылка";
    
    Запрос.УстановитьПараметр("Ссылка", ДокументСсылка);
    Возврат Запрос.Выполнить().Выгрузить();
КонецФункции

Теперь в модуле внешней обработки мы просто вызываем эту функцию:


ТаблицаДанных = рш_РаботаСДанными.ПолучитьДанныеДляПечати(СсылкаНаОбъект);
// Далее работаем с полученной таблицей значений

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

Важные нюансы: права доступа и безопасный режим

Иногда даже после применения вышеуказанных методов поле остается «невидимым». Выясним причину, проанализировав настройки безопасности и прав:

  1. Роли в расширении. При добавлении нового реквизита в расширение, права на него по умолчанию могут отсутствовать даже у администратора. Необходимо создать в этом же расширении Роль, дать в ней права на «Чтение» и «Просмотр» этого реквизита и добавить эту роль пользователям через Профили групп доступа.
  2. Безопасный режим в БСП. Если вы регистрируете внешнюю печатную форму через справочник «Дополнительные отчеты и обработки», обратите внимание на флаг «Безопасный режим». В некоторых версиях БСП (Библиотека стандартных подсистем) работа с объектами расширений блокируется, если обработка запущена в безопасном режиме. Попробуйте отключить его для данной обработки.
  3. Кэш метаданных. На платформе 8.3.12 была замечена особенность: после добавления реквизита в расширение внешняя обработка может не видеть его до полной очистки серверного кэша или перезапуска службы 1C:Enterprise.

Резюме

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

← На главную