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