Расширение формы 1С — заимствованная в расширение типовая форма, в которую добавляют поля, команды и свои обработчики событий, не снимая конфигурацию с поддержки. Задача встречается постоянно: в заказ клиента нужны поле и кнопка, в список заказов — колонка и отбор, а модуль типовой формы трогать нельзя, иначе каждое обновление превращается в ручное сравнение. Как создать само расширение и как работают аннотации, разобрано в статье «Расширение конфигурации 1С», здесь — только формы.
Пример — УТ 11.4, документ «Заказ клиента», префикс расширения Расш1_, новый реквизит документа Расш1_ДатаПодтверждения. В форму заказа добавим поле и кнопку «Клиент подтвердил», в список — колонку, отбор и подсветку. Имена типовых элементов и процедур сверены по выгрузке УТ 11.4.
Расширение формы документа начинается с заимствования:
ФормаДокумента выберите в контекстном меню «Добавить в расширение». Документ заимствуется вместе с формой.Расш1_ДатаПодтверждения: тип «Дата», состав «Дата и время».Объект, его можно перетащить в нужную группу.Расширение хранит копию формы на момент заимствования (в XML-выгрузке — раздел BaseForm в Form.xml): по ней платформа отличает ваши изменения от изменений 1С. С версии 8.3.14 заимствуются только форма и её элементы. Реквизиты и команды типовой формы показаны серым и берутся из основной конфигурации, а чтобы менять их свойства, их заимствуют явно из контекстного меню.
Заимствуйте ту форму, которую реально открывают пользователи. Свойства документа ОсновнаяФормаОбъекта и ОсновнаяФормаСписка говорят не всё: в УТ 11.4 команда «Продажи» → «Заказы клиентов» открывает не ФормаСписка, а ФормаСпискаДокументов. В КА 2.5 продажи часто смотрят через «Документы продажи (все)» — это форма СписокДокументов обработки ЖурналДокументовПродажи. Кто открывает форму, покажет глобальный поиск по конфигурации (Ctrl+Shift+F) по строке ЗаказКлиента.Форма.
Простое поле удобно перетащить в редакторе. Если же оно встаёт внутрь типовой группы, которую 1С регулярно перекраивает, надёжнее добавлять элементы кодом. В палитре свойств заимствованной формы, в разделе событий, создайте обработчик ПриСозданииНаСервере с типом вызова «После». Конфигуратор назовёт его Расш1_ПриСозданииНаСервереПосле, в XML-выгрузке это callType="After". Команды формы в расширении добавляют на вкладке «Команды» редактора или через Команды.Добавить, как в листинге.
// Модуль заимствованной формы Документ.ЗаказКлиента.Форма.ФормаДокумента (УТ 11.4).
// В заимствованный документ добавлен реквизит Расш1_ДатаПодтверждения
// (тип Дата, состав «Дата и время»). Обработчик назначен в палитре свойств формы:
// событие ПриСозданииНаСервере, тип вызова «После».
&НаСервере
Процедура Расш1_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
Если Отказ Тогда
Возврат; // типовой код уже отказался открывать форму
КонецЕсли;
Расш1_ДобавитьЭлементыПодтверждения();
Расш1_ОбновитьЭлементыПодтверждения(ЭтотОбъект);
КонецПроцедуры
&НаСервере
Процедура Расш1_ДобавитьЭлементыПодтверждения()
// Группа уже есть, если элементы положили на форму в конфигураторе.
Если Элементы.Найти("Расш1_ГруппаПодтверждение") <> Неопределено Тогда
Возврат;
КонецЕсли;
Если Команды.Найти("Расш1_ПодтвердитьЗаказ") = Неопределено Тогда
Команда = Команды.Добавить("Расш1_ПодтвердитьЗаказ");
Команда.Заголовок = НСтр("ru = 'Клиент подтвердил'");
Команда.Подсказка = НСтр("ru = 'Отметить дату подтверждения заказа клиентом'");
Команда.Действие = "Расш1_ПодтвердитьЗаказ";
КонецЕсли;
// Якорь — типовое поле «Информация для печати» на странице «Дополнительно».
// Не станет его в новом релизе — группа встанет в конец формы, а форма откроется.
Якорь = Элементы.Найти("ДополнительнаяИнформация");
Если Якорь = Неопределено Тогда
Группа = Элементы.Добавить("Расш1_ГруппаПодтверждение", Тип("ГруппаФормы"));
Иначе
Группа = Элементы.Вставить("Расш1_ГруппаПодтверждение", Тип("ГруппаФормы"),
Якорь.Родитель, Якорь);
КонецЕсли;
Группа.Вид = ВидГруппыФормы.ОбычнаяГруппа;
Группа.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Горизонтальная;
Группа.ОтображатьЗаголовок = Ложь;
Поле = Элементы.Добавить("Расш1_ДатаПодтверждения", Тип("ПолеФормы"), Группа);
Поле.Вид = ВидПоляФормы.ПолеВвода;
Поле.ПутьКДанным = "Объект.Расш1_ДатаПодтверждения";
Поле.Заголовок = НСтр("ru = 'Подтверждён клиентом'");
Поле.ТолькоПросмотр = Истина; // дату ставит только команда
Кнопка = Элементы.Добавить("Расш1_Подтвердить", Тип("КнопкаФормы"), Группа);
Кнопка.Вид = ВидКнопкиФормы.ОбычнаяКнопка;
Кнопка.ИмяКоманды = "Расш1_ПодтвердитьЗаказ";
КонецПроцедуры
&НаКлиентеНаСервереБезКонтекста
Процедура Расш1_ОбновитьЭлементыПодтверждения(Форма)
// Вызывается и до создания элементов (см. перехватчик в следующем листинге),
// поэтому кнопку ищем через Найти, а не через точку.
Кнопка = Форма.Элементы.Найти("Расш1_Подтвердить");
Если Кнопка = Неопределено Тогда
Возврат;
КонецЕсли;
Кнопка.Доступность = Не ЗначениеЗаполнено(Форма.Объект.Расш1_ДатаПодтверждения)
И Форма.Объект.Статус <> ПредопределенноеЗначение("Перечисление.СтатусыЗаказовКлиентов.Закрыт");
КонецПроцедуры
Элементы.Найти. Не станет поля ДополнительнаяИнформация — группа уйдёт в конец формы, но форма откроется.&НаКлиентеНаСервереБезКонтекста, её вызывают и с клиента, и с сервера.Подробно о Элементы.Добавить, ИзменитьРеквизиты и УстановитьДействие — в статье «Реквизит формы программно».
Для событий формы, её элементов и действий команд тип вызова выбирают в палитре заимствованной формы. Аннотации в модуле формы перехватывают процедуру по имени, откуда бы её ни вызвали.
| Способ | Когда выполняется ваш код | Типовой код | Риск при обновлении |
|---|---|---|---|
| Палитра, «Перед» | до типового обработчика события | выполняется | минимальный |
| Палитра, «После» | после типового обработчика | выполняется | минимальный |
| Палитра, «Вместо» | вместо типового обработчика | не выполняется | исправления 1С в обработчике до пользователей не дойдут |
&Перед, &После | до или после процедуры модуля | выполняется | процедуру переименуют или удалят |
&Вместо | вместо процедуры, типовую вызывает ПродолжитьВызов() | по вашему решению | то же |
&ИзменениеИКонтроль | работает изменённая копия процедуры | ваша копия | любое изменение процедуры останавливает расширение |
Для событий берите палитру и «После»: обработчик привязан к событию, а не к имени процедуры, и сработает, даже если своего обработчика в типовой форме нет. «Вместо» на ПриСозданииНаСервере выключает типовой обработчик целиком, а в заказе УТ 11.4 он подключает механизмы БСП: дополнительные реквизиты, версионирование, команды печати. Аннотацию &После ставьте на служебные процедуры, которые типовой код вызывает из разных мест, помня цену: если 1С переименует процедуру, расширение перестанет применяться.
// Тот же модуль заимствованной формы ФормаДокумента: обработчик команды,
// перехватчик типовой процедуры и обработчики событий с типом вызова «После».
&НаКлиенте
Процедура Расш1_ПодтвердитьЗаказ(Команда)
Если ЗначениеЗаполнено(Объект.Расш1_ДатаПодтверждения) Тогда
ПоказатьПредупреждение(, НСтр("ru = 'Подтверждение уже отмечено.'"));
Возврат;
КонецЕсли;
Расш1_ПодтвердитьЗаказНаСервере();
ПоказатьОповещениеПользователя(НСтр("ru = 'Подтверждение отмечено'"), ,
НСтр("ru = 'Запишите заказ, чтобы сохранить дату.'"));
КонецПроцедуры
&НаСервере
Процедура Расш1_ПодтвердитьЗаказНаСервере()
Объект.Расш1_ДатаПодтверждения = ТекущаяДатаСеанса();
Модифицированность = Истина;
Расш1_ОбновитьЭлементыПодтверждения(ЭтотОбъект);
КонецПроцедуры
// Типовая процедура формы в УТ 11.4. Её вызывают при открытии заказа, после записи
// и при смене статуса; при открытии — раньше, чем Расш1_ПриСозданииНаСервереПосле создаст кнопку.
&НаСервере
&После("УстановитьДоступностьЭлементовПоСтатусуСервер")
Процедура Расш1_УстановитьДоступностьЭлементовПоСтатусуСервер()
Расш1_ОбновитьЭлементыПодтверждения(ЭтотОбъект);
КонецПроцедуры
// Событие ПриИзменении типового поля Партнер, тип вызова «После».
&НаКлиенте
Процедура Расш1_ПартнерПриИзмененииПосле(Элемент)
// Подтверждение получали у прежнего клиента — сбрасываем его.
Если ЗначениеЗаполнено(Объект.Расш1_ДатаПодтверждения) Тогда
Объект.Расш1_ДатаПодтверждения = Дата(1, 1, 1);
Расш1_ОбновитьЭлементыПодтверждения(ЭтотОбъект);
КонецЕсли;
КонецПроцедуры
// Событие ПередЗаписьюНаСервере, тип вызова «После»: типовой обработчик уже отработал.
&НаСервере
Процедура Расш1_ПередЗаписьюНаСервереПосле(Отказ, ТекущийОбъект, ПараметрыЗаписи)
Если Отказ Или ПараметрыЗаписи.РежимЗаписи <> РежимЗаписиДокумента.Проведение Тогда
Возврат;
КонецЕсли;
Если ТекущийОбъект.Статус = Перечисления.СтатусыЗаказовКлиентов.КОтгрузке
И Не ЗначениеЗаполнено(ТекущийОбъект.Расш1_ДатаПодтверждения) Тогда
ОбщегоНазначения.СообщитьПользователю(
НСтр("ru = 'Статус «К отгрузке» можно ставить только после подтверждения клиентом.'"),
, "Объект.Расш1_ДатаПодтверждения", , Отказ);
КонецЕсли;
КонецПроцедуры
ПриЧтенииНаСервере срабатывает раньше ПриСозданииНаСервере, а типовая УстановитьДоступностьЭлементовПоСтатусуСервер вызывается из чтения. Перехватчик выполняется, когда кнопки ещё нет, — поэтому в общей процедуре только Найти.&НаСервере у перехватчика совпадает с директивой типовой процедуры.Отказ уже содержит решение типового кода, его проверяют первым.Чтобы поправить строку внутри типовой процедуры формы, нужна &ИзменениеИКонтроль — пример есть в статье про расширение конфигурации. У типовой команды тип вызова тоже выбирают в палитре, но у обработчика команды нет параметра Отказ, и «Перед» не запретит типовое действие. Для вызова типового кода по условию нужна аннотация &Вместо с ПродолжитьВызов(), пример — в статье «Команда формы 1С».
Если динамический список построен без произвольного запроса, реквизит расширения сразу становится его полем. Так устроена ФормаСписка заказа в УТ 11.4: заимствуйте её и выведите колонку с путём Список.Расш1_ДатаПодтверждения. В ФормаСпискаДокументов запрос произвольный, и нового реквизита в нём нет. Переписывать запрос не стоит: текст, изменённый в расширении, останется вашим и после обновлений, и исправления 1С в запросе до пользователей не дойдут. Реквизит можно взять через поле Ссылка — соединение платформа добавит сама.
// Модуль заимствованной формы Документ.ЗаказКлиента.Форма.ФормаСпискаДокументов (УТ 11.4).
// Список построен произвольным запросом, реквизита расширения в нём нет:
// берём реквизит через поле Ссылка, текст типового запроса не трогаем.
// Обработчик назначен в палитре: событие ПриСозданииНаСервере, тип вызова «После».
&НаСервере
Процедура Расш1_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
Если Отказ Тогда
Возврат;
КонецЕсли;
Расш1_ДобавитьКолонкуПодтверждения();
Расш1_ДобавитьОтборНеподтвержденных();
Расш1_ВыделитьНеподтвержденные();
КонецПроцедуры
&НаСервере
Процедура Расш1_ДобавитьКолонкуПодтверждения()
// Колонку могли уже добавить в конфигураторе.
Если Элементы.Найти("Расш1_СписокДатаПодтверждения") <> Неопределено Тогда
Возврат;
КонецЕсли;
// Ставим перед колонкой «Статус», а если её нет — в конец таблицы.
Якорь = Элементы.Найти("СписокСтатус");
Если Якорь = Неопределено Тогда
Колонка = Элементы.Добавить("Расш1_СписокДатаПодтверждения", Тип("ПолеФормы"), Элементы.Список);
Иначе
Колонка = Элементы.Вставить("Расш1_СписокДатаПодтверждения", Тип("ПолеФормы"),
Якорь.Родитель, Якорь);
КонецЕсли;
Колонка.Вид = ВидПоляФормы.ПолеНадписи;
Колонка.ПутьКДанным = "Список.Ссылка.Расш1_ДатаПодтверждения";
Колонка.Заголовок = НСтр("ru = 'Подтверждён'");
Колонка.Формат = "ДФ='dd.MM.yy HH:mm'";
КонецПроцедуры
&НаСервере
Процедура Расш1_ДобавитьОтборНеподтвержденных()
Если Элементы.Найти("Расш1_ТолькоНеподтвержденные") <> Неопределено Тогда
Возврат;
КонецЕсли;
// Реквизит формы, а не документа: в базу не пишется, нужен только флажку.
НовыеРеквизиты = Новый Массив;
НовыеРеквизиты.Добавить(Новый РеквизитФормы("Расш1_ТолькоНеподтвержденные",
Новый ОписаниеТипов("Булево"), , НСтр("ru = 'Только неподтверждённые'")));
ИзменитьРеквизиты(НовыеРеквизиты);
// Флажок — к типовым быстрым отборам, а если группы нет — в конец формы.
Группа = Элементы.Найти("ГруппаБыстрыеОтборы");
Если Группа = Неопределено Тогда
Флажок = Элементы.Добавить("Расш1_ТолькоНеподтвержденные", Тип("ПолеФормы"));
Иначе
Флажок = Элементы.Добавить("Расш1_ТолькоНеподтвержденные", Тип("ПолеФормы"), Группа);
КонецЕсли;
Флажок.Вид = ВидПоляФормы.ПолеФлажка;
Флажок.ПутьКДанным = "Расш1_ТолькоНеподтвержденные";
Флажок.УстановитьДействие("ПриИзменении", "Расш1_ТолькоНеподтвержденныеПриИзменении");
КонецПроцедуры
&НаКлиенте
Процедура Расш1_ТолькоНеподтвержденныеПриИзменении(Элемент)
// БСП: добавляет элемент отбора или меняет флажок использования уже добавленного.
ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(Список,
"Ссылка.Расш1_ДатаПодтверждения", , ВидСравненияКомпоновкиДанных.НеЗаполнено, ,
ЭтотОбъект["Расш1_ТолькоНеподтвержденные"]);
КонецПроцедуры
&НаСервере
Процедура Расш1_ВыделитьНеподтвержденные()
// Оформление самого динамического списка: в колонке проведённого заказа
// без подтверждения — надпись «не подтверждён».
ОформлениеСписка = Список.КомпоновщикНастроек.Настройки.УсловноеОформление;
ЭлементОформления = ОформлениеСписка.Элементы.Добавить();
ЭлементОформления.Представление = НСтр("ru = 'Заказ не подтверждён клиентом'");
ЭлементОформления.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Недоступный;
ЭлементОформления.Поля.Элементы.Добавить().Поле = Новый ПолеКомпоновкиДанных("Ссылка.Расш1_ДатаПодтверждения");
ЭлементОтбора = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Ссылка.Расш1_ДатаПодтверждения");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.НеЗаполнено;
ЭлементОтбора = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Проведен");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = Истина;
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("Текст", НСтр("ru = 'не подтверждён'"));
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветТекста", ЦветаСтиля.ЦветТекстаВнимание);
КонецПроцедуры
Список.Ссылка.Расш1_ДатаПодтверждения работает в любой форме списка, где в запросе есть поле Ссылка, и запрос править не нужно.ПриСозданииНаСервере этой формы первым делом вызывает УстановитьУсловноеОформление(), а она очищает оформление списка. Оформление из обработчика «Перед» стёрлось бы, из «После» — остаётся.ИзменитьРеквизиты создаёт реквизит формы для флажка, в базу он не пишется. Обращаются к нему через ЭтотОбъект["…"]: при компиляции модуля такого имени ещё нет.Список., режим «Недоступный» прячет их из пользовательских настроек. ЦветТекстаВнимание — стиль типовой, в другой конфигурации подставьте свой цвет.Своя форма нужна, когда типовая не подходит совсем: упрощённая форма заказа для операторов, мастер, диалог. В дереве расширения у заимствованного документа добавьте в ветку «Формы» новую форму с префиксом, например Расш1_ФормаОператора. Это собственная форма расширения: исходной копии у неё нет, обновления типовой её не трогают. Открывают её командой: ОткрытьФорму("Документ.ЗаказКлиента.Форма.Расш1_ФормаОператора", Новый Структура("Ключ", СсылкаНаЗаказ)).
Свою форму можно сделать основной в свойствах заимствованного документа, но тогда всё, что 1С добавит в типовую форму в обновлениях, пользователи не увидят. Для «добавить поле и кнопку» заимствуйте типовую.
При применении расширения платформа собирает форму из трёх версий: исходной копии, текущей типовой и формы расширения. Если свойство элемента не меняли или его поменяла только 1С, берётся типовое значение. Если его поменяли в расширении, побеждает расширение — даже когда 1С тоже его изменила. Новые элементы типовой появляются в форме сами, а конфигуратор показывает в верхней части редактора заимствованной формы баннер с предложением обновить её.
Как не сломать форму:
Найти с запасным местом.ФормаВыбора.ПриСозданииНаСервере, а типовая процедура после записи показала его снова. Перехватите её через &После, как во втором листинге.Элементы.Расш1_Подтвердить к элементу, которого ещё нет. Обычно это перехватчик процедуры, вызванной из ПриЧтенииНаСервере. Нужен Элементы.Найти.Объект. Присваивание без него коварнее: ошибки нет, создаётся локальная переменная.Список.Расш1_… в форме с произвольным запросом. Берите поле через Список.Ссылка.Расш1_….ПриСозданииНаСервере тип вызова «Вместо». Поменяйте на «После».&После или изменила процедуру под &ИзменениеИКонтроль. Разберитесь на копии базы и поправьте перехватчик.Удалить нельзя, только спрятать — кодом в обработчике «После»: Элементы.Комментарий.Видимость = Ложь. Если типовой код показывает элемент снова, перехватите процедуру, которая это делает.
Можно: в свойствах явно заимствованного реквизита Список или кодом через Список.ТекстЗапроса. Но с этого момента запрос ваш, и правки 1С из новых релизов придётся переносить вручную.
Нет. Расширение формы в 1С 8.3 работает только с управляемыми формами. В конфигурациях на обычных формах, например УТ 10.3, форму дорабатывают в самой конфигурации.
В реквизите заимствованного документа, как Расш1_ДатаПодтверждения: реквизит формы живёт, пока форма открыта. Если поле нужно без программиста, хватит дополнительных реквизитов.
Если после обновления форма перестала открываться, расширение не применяется или доработки нужно перенести из снятой с поддержки формы в расширение, быстрее поручить это программисту, который каждый день работает с типовыми: доработка 1С. Опишите задачу на странице «Разместить задание» — оценка бесплатная, ответ в течение рабочего дня.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.