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