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