Расширение конфигурации 1С — отдельный слой доработок, который платформа накладывает на типовую конфигурацию при старте сеанса. Типовая остаётся на поддержке и обновляется штатно, а ваши реквизиты, формы и код живут в расширении и выгружаются в файл .cfe. Механизм появился в платформе 8.3.6, примеры ниже рассчитаны на актуальные релизы 8.3.
Статья построена на одном примере: расширение «Логистика» для документа «Реализация товаров и услуг» — реквизит «Логист» на форме, проверки при записи, история изменений через подписку и диагностика, когда расширение не применяется. Имена типовых объектов взяты из БП 3.0 и УТ 11, в своей конфигурации сверьте их.
Логистика, префикс Расш1_ и назначение. Префикс попадает в имена новых объектов и обработчиков и защищает от совпадения с объектами будущих релизов.РеализацияТоваровУслуг выберите «Добавить в расширение». Это заимствование: в расширении появляется ссылка на типовой объект, которую можно дополнять.Расш1_Логист типа СправочникСсылка.Пользователи с синонимом «Логист» — справочник тоже должен быть в расширении. Собственными объектами создайте константу Расш1_ЛогистПоУмолчанию и роль Расш1_Логистика.Назначение задаёт порядок применения: «Исправление», затем «Адаптация», затем «Дополнение». Доработки под конкретную компанию помечают как «Адаптация».
| Задача | Можно в расширении |
|---|---|
| Добавить реквизит или табличную часть в типовой объект | Да |
| Создать свой справочник, документ, регистр, отчёт, обработку, роль, подписку | Да |
| Добавить поле, команду или обработчик в типовую форму | Да, через заимствованную форму |
| Дополнить, заменить или поправить метод типового модуля | Да, аннотациями |
| Удалить или переименовать типовой реквизит, изменить длину кода или иерархию справочника | Нет |
Если полю не нужны код и проверки, хватит дополнительных реквизитов — их заводят без конфигуратора.
Откройте модуль объекта заимствованного документа. Перехватчик — метод расширения с аннотацией, в скобках указано имя типового метода. Параметры повторяют исходные, имя — любое, с префиксом.
// Модуль объекта документа РеализацияТоваровУслуг в расширении «Логистика»
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
&Перед("ПередЗаписью")
Процедура Расш1_ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Отменить проведение отгрузки с назначенным логистом может только логист.
Если РежимЗаписи = РежимЗаписиДокумента.ОтменаПроведения
И ЗначениеЗаполнено(Расш1_Логист)
И Не Пользователи.РолиДоступны("Расш1_Логистика") Тогда
ОбщегоНазначения.СообщитьПользователю(
НСтр("ru = 'Отменить проведение может только логист.'"), ЭтотОбъект, , , Отказ);
КонецЕсли;
КонецПроцедуры
&После("ОбработкаПроверкиЗаполнения")
Процедура Расш1_ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
// Логист обязателен для крупных отгрузок. Проверку и сообщение
// «Поле "Логист" не заполнено» платформа выполнит сама.
Если СуммаДокумента >= 100000 Тогда
ПроверяемыеРеквизиты.Добавить("Расш1_Логист");
КонецЕсли;
КонецПроцедуры
&После("ОбработкаЗаполнения")
Процедура Расш1_ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
// Типовое заполнение уже выполнено — дополняем только пустой реквизит.
Если Не ЗначениеЗаполнено(Расш1_Логист) Тогда
Расш1_Логист = Константы.Расш1_ЛогистПоУмолчанию.Получить();
КонецЕсли;
КонецПроцедуры
#КонецЕсли
&Перед("ПередЗаписью") выполняется до типового кода. Отказ = Истина цепочку не прерывает: типовой метод всё равно отработает, а запись отменится после всех обработчиков.&После("ОбработкаПроверкиЗаполнения") реквизит попадает в ПроверяемыеРеквизиты, проверку и сообщение «Поле "Логист" не заполнено» платформа сделает сама.&После("ОбработкаЗаполнения") срабатывает после типового заполнения нового документа, поэтому заполняем только пустой реквизит. Список параметров повторяет типовой метод: в УТ 11.4 и КА 2.5 у РеализацияТоваровУслуг.ОбработкаЗаполнения их два — ДанныеЗаполнения и СтандартнаяОбработка. Если в вашей конфигурации метод объявлен с ТекстЗаполнения, повторите три параметра, иначе расширение не применится.Заимствуйте основную форму документа (в БП и УТ — ФормаДокумента). Поле можно перетащить из Объект в редакторе формы, но программное добавление спокойнее переживает обновления: в заимствованной форме меняется только привязка обработчика. В палитре свойств формы у события ПриСозданииНаСервере создайте обработчик с типом вызова «После».
// Модуль заимствованной формы ФормаДокумента
&НаСервере
Процедура Расш1_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
// Поле могли уже добавить вручную в редакторе заимствованной формы.
Если Элементы.Найти("Расш1_Логист") = Неопределено Тогда
Расш1_ДобавитьПолеЛогиста();
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура Расш1_ДобавитьПолеЛогиста()
// Ставим поле перед комментарием, а если его нет — в конец формы.
ПолеКомментарий = Элементы.Найти("Комментарий");
Если ПолеКомментарий = Неопределено Тогда
Поле = Элементы.Добавить("Расш1_Логист", Тип("ПолеФормы"));
Иначе
Поле = Элементы.Вставить("Расш1_Логист", Тип("ПолеФормы"),
ПолеКомментарий.Родитель, ПолеКомментарий);
КонецЕсли;
Поле.Вид = ВидПоляФормы.ПолеВвода;
Поле.ПутьКДанным = "Объект.Расш1_Логист";
Поле.АвтоОтметкаНезаполненного = Объект.СуммаДокумента >= 100000;
// В выборе — только действующие пользователи.
ПараметрыОтбора = Новый Массив;
ПараметрыОтбора.Добавить(Новый ПараметрВыбора("Отбор.Недействителен", Ложь));
Поле.ПараметрыВыбора = Новый ФиксированныйМассив(ПараметрыОтбора);
КонецПроцедуры
ПриСозданииНаСервере. Аннотация &После("ПриСозданииНаСервере") в модуле формы тоже допустима, но требует типового метода с таким именем.Элементы.Вставить ставит поле в ту же группу перед «Комментарием», Элементы.Добавить — в конец формы.Отбор.Недействителен скрывает недействительных пользователей.&Вместо подменяет метод целиком. Исходный метод вызывается через ПродолжитьВызов() с теми же или изменёнными параметрами, а можно не вызывать его вовсе. Так меняют результат типовой функции, не копируя её код. В конфигурациях на БСП функция модуля менеджера РеквизитыРедактируемыеВГрупповойОбработке перечисляет реквизиты для группового изменения, и новый реквизит сам туда не попадёт.
// Модуль менеджера документа РеализацияТоваровУслуг в расширении
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
&Вместо("РеквизитыРедактируемыеВГрупповойОбработке")
Функция Расш1_РеквизитыРедактируемыеВГрупповойОбработке()
// Сначала получаем типовой список, затем дополняем его своим реквизитом.
Реквизиты = ПродолжитьВызов();
Реквизиты.Добавить("Расш1_Логист");
Возврат Реквизиты;
КонецФункции
#КонецЕсли
ПродолжитьВызов() выполняет типовую функцию и возвращает её результат, который можно дополнить.ПродолжитьВызов не вызвать, будущие исправления 1С в этом методе молча пропадут. Берите &Вместо, только когда &Перед и &После не подходят.Когда нужно изменить строку в середине метода, &Перед и &После не помогут, а &Вместо отрежет будущие исправления. &ИзменениеИКонтроль хранит в расширении копию метода, где правки размечены блоками #Вставка…#КонецВставки и #Удаление…#КонецУдаления. При применении платформа сверяет копию без вставок с текущим методом типовой. Если 1С изменит метод, расширение не применится, и вы узнаете об этом на тестовой базе, а не от пользователей.
Пример: типовая процедура УправлениеФормой прячет дату отгрузки, пока не выбран склад, а логисту поле нужно всегда. Исходный метод — этот же текст без блока #Вставка и строк-инструкций.
// Модуль заимствованной формы ФормаДокумента
&НаКлиентеНаСервереБезКонтекста
&ИзменениеИКонтроль("УправлениеФормой")
Процедура Расш1_УправлениеФормой(Форма)
Элементы = Форма.Элементы;
Объект = Форма.Объект;
Элементы.Контрагент.ТолькоПросмотр = Объект.Проведен;
Элементы.Склад.ТолькоПросмотр = Объект.Проведен;
#Удаление
Элементы.ДатаОтгрузки.Видимость = ЗначениеЗаполнено(Объект.Склад);
#КонецУдаления
#Вставка
// Логисту дата отгрузки нужна всегда, даже без склада.
Элементы.ДатаОтгрузки.Видимость = Истина;
ПолеЛогист = Элементы.Найти("Расш1_Логист");
Если ПолеЛогист <> Неопределено Тогда
ПолеЛогист.ТолькоПросмотр = Объект.Проведен;
КонецЕсли;
#КонецВставки
КонецПроцедуры
&НаКлиентеНаСервереБезКонтекста.#Удаление — исходный текст, в итоговом методе их нет.Подписка не зависит от методов типового модуля: если 1С перепишет ПередЗаписью документа, она продолжит работать, а одна подписка может обслуживать несколько типов объектов. Создайте в расширении общий модуль Расш1_ЛогистикаСервер с флагом «Сервер», периодический регистр сведений Расш1_ИсторияЛогистов (измерение Документ, ресурсы Логист и Автор) и две подписки на события ПередЗаписью и ПриЗаписи с источником ДокументОбъект.РеализацияТоваровУслуг.
// Общий модуль расширения Расш1_ЛогистикаСервер (флаг «Сервер»).
// Подписки с источником ДокументОбъект.РеализацияТоваровУслуг:
// Расш1_ИсторияЛогистаПередЗаписью — событие ПередЗаписью,
// Расш1_ИсторияЛогистаПриЗаписи — событие ПриЗаписи.
Процедура ИсторияЛогистаПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
Если Источник.ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
Если Источник.ЭтоНовый() Тогда
ЛогистДоЗаписи = Справочники.Пользователи.ПустаяСсылка();
Иначе
ЛогистДоЗаписи = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Источник.Ссылка, "Расш1_Логист");
КонецЕсли;
Источник.ДополнительныеСвойства.Вставить("Расш1_ЛогистДоЗаписи", ЛогистДоЗаписи);
КонецПроцедуры
Процедура ИсторияЛогистаПриЗаписи(Источник, Отказ) Экспорт
Если Отказ Или Источник.ОбменДанными.Загрузка
Или Не Источник.ДополнительныеСвойства.Свойство("Расш1_ЛогистДоЗаписи") Тогда
Возврат;
КонецЕсли;
Если Источник.ДополнительныеСвойства.Расш1_ЛогистДоЗаписи = Источник.Расш1_Логист Тогда
Возврат; // логист не менялся
КонецЕсли;
// У менеджеров нет прав на регистр истории — пишем в привилегированном режиме.
УстановитьПривилегированныйРежим(Истина);
Запись = РегистрыСведений.Расш1_ИсторияЛогистов.СоздатьМенеджерЗаписи();
Запись.Период = ТекущаяДатаСеанса();
Запись.Документ = Источник.Ссылка;
Запись.Логист = Источник.Расш1_Логист;
Запись.Автор = Пользователи.ТекущийПользователь();
Запись.Записать();
УстановитьПривилегированныйРежим(Ложь);
КонецПроцедуры
Источник, остальные параметры — как у события.ПередЗаписью и передаётся в ПриЗаписи через ДополнительныеСвойства — история пишется только при реальной смене логиста.Оба флага видны в списке расширений в конфигураторе и в форме управления расширениями в 1С:Предприятии.
| Свойство | Что делает | Когда выключать |
|---|---|---|
| Безопасный режим | Привилегированный режим игнорируется; работа с файлами, COM-объектами, внешними компонентами, запуск программ и обращения к интернет-ресурсам запрещены, если профиль безопасности их не разрешает. | Расширению нужны привилегированный режим, файлы или интеграции, а его код вы контролируете. |
| Защита от опасных действий | Если расширение работает не в безопасном режиме, пользователь с включённой защитой при входе получает предупреждение безопасности и может отказаться от подключения расширения. | Для своих проверенных расширений, чтобы предупреждение не появлялось при каждом запуске. |
Для подписки из предыдущего раздела безопасный режим нужно выключить, иначе у менеджера без прав запись в регистр завершится ошибкой.
Расширение подключается при старте сеанса: после загрузки новой версии пользователям достаточно перезайти. Загрузить .cfe можно:
/LoadCfg Логистика.cfe -Extension Логистика и /UpdateDBCfg -Extension Логистика.При обновлении типовой сначала обновите копию базы, откройте расширение и выполните синтаксический контроль и проверку возможности применения. Исправьте найденное, увеличьте свойство «Версия» и сохраните .cfe. На рабочей базе обновляется типовая, затем загружается расширение.
Почему расширение неактивно:
&ИзменениеИКонтроль;Состояние удобно проверять из внешней обработки: код внутри неактивного расширения не выполнится.
// Модуль формы внешней обработки. Запускать под пользователем с административными правами.
&НаКлиенте
Процедура Проверить(Команда)
ПроверитьРасширениеНаСервере("Логистика");
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ПроверитьРасширениеНаСервере(ИмяРасширения)
Найденные = РасширенияКонфигурации.Получить(Новый Структура("Имя", ИмяРасширения));
Если Найденные.Количество() = 0 Тогда
Сообщить(СтрШаблон("Расширение %1 не загружено в базу.", ИмяРасширения));
Возврат;
КонецЕсли;
Расширение = Найденные[0];
Сообщить(СтрШаблон("%1: активно = %2, безопасный режим = %3",
Расширение.Имя, Расширение.Активно, Расширение.БезопасныйРежим));
// Применилось ли расширение в текущем сеансе — видно по метаданным.
Если Метаданные.Документы.РеализацияТоваровУслуг.Реквизиты.Найти("Расш1_Логист") = Неопределено Тогда
Сообщить("В этом сеансе расширение не применено.");
КонецЕсли;
Если Расширение.Активно Тогда
Возврат;
КонецЕсли;
Попытка
Расширение.Активно = Истина;
Расширение.Записать();
Сообщить("Расширение включено. Пользователям нужно перезапустить сеансы.");
Исключение
// Если расширение не подходит к конфигурации, причина будет в тексте ошибки.
Сообщить(ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецПроцедуры
РасширенияКонфигурации.Получить читает список из базы, включая неактивные расширения.Метаданные показывает, применилось ли расширение именно в этом сеансе.&Перед «не срабатывает» — типовой метод всё равно выполняется, запись отменяется в конце. Если типовой код запускаться не должен, нужен &Вместо.Нет. Расширение хранится отдельно, типовая обновляется штатно, а расширение после каждого обновления проверяют на копии базы.
&ИзменениеИКонтроль — чтобы поправить несколько строк внутри типового метода: при его изменении расширение остановится, и правку перенесут осознанно. &Вместо — чтобы поменять результат функции или решить, вызывать ли типовой код.
Обычно у пользователя нет прав на объекты расширения, привилегированный режим игнорируется из-за безопасного режима или пользователь отказался от подключения в предупреждении безопасности.
Реквизиты и объекты расширения удаляются вместе с данными. Перед удалением сделайте копию базы или перенесите значения в типовые реквизиты.
Если расширение перестало применяться после обновления или доработки нужно перенести в расширение из снятой с поддержки конфигурации, быстрее поручить это программисту, который каждый день работает с типовыми: доработка 1С. Опишите задачу на странице «Разместить задание» — исполнители предложат оценку и сроки.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.