Как правильно использовать и заимствовать общие модули в расширениях 1С:Предприятие 8.3

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

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

Нужно ли заимствовать общий модуль для обращения к его методам?

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

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

Ситуация меняется, если вы планируете расширить логику самого метода в общем модуле (использовать аннотации &Перед, &После или &Вместо). В этом случае модуль обязательно должен быть добавлен в расширение (заимствован).

Зависимость от объектов конфигурации при заимствовании

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

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

Контекст исполнения: Клиент, Сервер и Толстый клиент

Одной из самых частых проблем при работе с расширениями является ошибка Переменная не определена при обращении к общему модулю. Рассмотрим причины этой ситуации:

  1. Направление вызова: Помните золотое правило платформы — из клиентского контекста (&НаКлиенте) можно вызвать серверный метод, но из серверного контекста (&НаСервере) вызвать клиентский метод нельзя.
  2. Флаги общего модуля: Если вы вызываете метод из формы документа &НаКлиенте, а у общего модуля в основной конфигурации не стоит флаг Клиент (управляемое приложение), то вы получите ошибку.
  3. Вызов сервера: Если вы находитесь на клиенте и пытаетесь обратиться к серверному общему модулю, у него обязательно должен быть установлен флаг Вызов сервера.

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


#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
    // Код, который должен выполняться на стороне сервера или в толстом клиенте
    ИмяОбщегоМодуля.ВыполнитьДействие();
#КонецЕсли

Использование аннотаций для изменения логики

Рассмотрим подробнее механизмы перехвата управления &Перед, &После и &Вместо. Это наиболее безопасный способ доработки системы, так как он минимизирует конфликты при обновлении конфигурации.

Аннотация &Вместо: Полностью замещает типовой код. Если вы хотите сохранить выполнение оригинальной процедуры, обязательно используйте команду ПродолжитьВызов(). Посмотрим на пример:


&Вместо("РассчитатьНалоги")
Процедура Расш1_РассчитатьНалоги(Параметры)
    // Свой код до выполнения основной логики
    Сообщить("Начинаем расчет...");
    
    // Вызов оригинального метода из основной конфигурации
    ПродолжитьВызов(Параметры);
    
    // Свой код после выполнения основной логики
    Сообщить("Расчет окончен.");
КонецПроцедуры

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

Безопасный режим и права доступа

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

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

Работа с глобальными общими модулями

Если в основной конфигурации общий модуль помечен как Глобальный, его экспортные методы доступны в расширении без указания префикса (имени модуля). Однако мы рекомендуем соблюдать осторожность: если вы добавите в расширение свой глобальный модуль с процедурой, имя которой совпадает с именем процедуры в глобальном модуле конфигурации, возникнет конфликт имен. Платформа отдаст приоритет тому или иному методу в зависимости от настроек, что может привести к непредсказуемому поведению системы.

Порядок применения расширений

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

← На главную