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