При разработке расширений для конфигураций на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с необходимостью переиспользовать существующий код или модифицировать логику типовых процедур, расположенных в общих модулях. Рассмотрим подробно, как организовать взаимодействие расширения с основной конфигурацией, разберем правила заимствования объектов и выясним, почему возникают ошибки компиляции в различных контекстах.
Проанализируем первую ситуацию: вам необходимо добавить в расширение новую команду на форму, которая вызывает функцию из существующего общего модуля основной конфигурации. Нужно ли в этом случае добавлять сам модуль в расширение? Нет, не обязательно.
Если вы просто вызываете экспортный метод общего модуля «со стороны» (из кода своей формы или своего модуля в расширении), платформа позволяет обращаться к нему напрямую. Достаточно написать стандартный вызов: ИмяОбщегоМодуля.ИмяПроцедуры(). Однако здесь есть важное условие: метод должен иметь признак Экспорт, а свойства самого модуля должны позволять его вызов из того контекста, где находится ваш код.
Ситуация меняется, если вы планируете расширить логику самого метода в общем модуле (использовать аннотации &Перед, &После или &Вместо). В этом случае модуль обязательно должен быть добавлен в расширение (заимствован).
Разберем вопрос о необходимости добавления в расширение всех справочников, документов и регистров, которые упоминаются в коде заимствованного модуля. На современных версиях платформы (начиная с 8.3.10 и выше) полное заимствование всех зависимых объектов не требуется. Процедурам и функциям, добавленным в расширение, доступны все объекты основной конфигурации «по умолчанию».
Если вы заимствуете форму из основной конфигурации, платформа автоматически предложит добавить связанные объекты, необходимые для работы этой формы. Но если вы работаете только с кодом в общем модуле, вы можете оперировать типами данных основной конфигурации без их явного переноса в расширение. Исключение составляют случаи, когда вы хотите программно обращаться к новым реквизитам, которые создали непосредственно в расширении — тогда эти реквизиты и их владельцы должны присутствовать в составе расширения.
Одной из самых частых проблем при работе с расширениями является ошибка Переменная не определена при обращении к общему модулю. Рассмотрим причины этой ситуации:
&НаКлиенте) можно вызвать серверный метод, но из серверного контекста (&НаСервере) вызвать клиентский метод нельзя.&НаКлиенте, а у общего модуля в основной конфигурации не стоит флаг Клиент (управляемое приложение), то вы получите ошибку.Проанализируем ситуацию с Толстым клиентом. Если ваша система запускается в режиме толстого клиента и расширение не «видит» модуль, проверьте наличие флага Клиент (обычное приложение). Также полезно использовать директивы препроцессора для разделения кода:
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
// Код, который должен выполняться на стороне сервера или в толстом клиенте
ИмяОбщегоМодуля.ВыполнитьДействие();
#КонецЕсли
Рассмотрим подробнее механизмы перехвата управления &Перед, &После и &Вместо. Это наиболее безопасный способ доработки системы, так как он минимизирует конфликты при обновлении конфигурации.
Аннотация &Вместо: Полностью замещает типовой код. Если вы хотите сохранить выполнение оригинальной процедуры, обязательно используйте команду ПродолжитьВызов(). Посмотрим на пример:
&Вместо("РассчитатьНалоги")
Процедура Расш1_РассчитатьНалоги(Параметры)
// Свой код до выполнения основной логики
Сообщить("Начинаем расчет...");
// Вызов оригинального метода из основной конфигурации
ПродолжитьВызов(Параметры);
// Свой код после выполнения основной логики
Сообщить("Расчет окончен.");
КонецПроцедуры
Важный нюанс: при заимствовании метода через &Вместо, параметры процедуры в расширении должны в точности соответствовать параметрам в основной конфигурации.
Выясним причину, по которой код в расширении может выдавать ошибки прав доступа при обращении к общим модулям. По умолчанию все расширения подключаются в безопасном режиме. В этом режиме блокируются:
Если общий модуль в основной конфигурации выполняет любое из этих действий, вызов из расширения завершится аварией. Чтобы решить эту проблему, необходимо в свойствах расширения в конфигураторе снять флажок Безопасный режим. Обратите внимание, что в пользовательском режиме (в справочнике "Дополнительные отчеты и обработки" или через "Управление расширениями") также может потребоваться подтверждение того, что расширение является доверенным.
Если в основной конфигурации общий модуль помечен как Глобальный, его экспортные методы доступны в расширении без указания префикса (имени модуля). Однако мы рекомендуем соблюдать осторожность: если вы добавите в расширение свой глобальный модуль с процедурой, имя которой совпадает с именем процедуры в глобальном модуле конфигурации, возникнет конфликт имен. Платформа отдаст приоритет тому или иному методу в зависимости от настроек, что может привести к непредсказуемому поведению системы.
В завершение рассмотрим ситуацию, когда в базе установлено несколько расширений, затрагивающих один и тот же общий модуль. Платформа применяет их последовательно в соответствии с установленным приоритетом. Если одно расширение использует &Вместо и не вызывает ПродолжитьВызов(), то все последующие расширения (и основной код конфигурации) просто не получат управления. Поэтому всегда анализируйте цепочку вызовов, если ваша доработка «вдруг» перестала работать после установки другого расширения.