При разработке на платформе 1С Предприятие часто возникает дилемма. С одной стороны, внешние обработки заполнения объектов удобны: их можно подключать и обновлять «на лету» через справочник Дополнительные отчеты и обработки без внесения изменений в конфигурацию. С другой стороны, встроенные обработки гораздо удобнее для разработчика: по ним работает глобальный поиск, их код легко отслеживать в системах контроля версий (Git, EDT), и они всегда находятся в одном месте вместе с остальной конфигурацией.
В этой статье мы подробно разберем, как использовать стандартные механизмы Библиотеки стандартных подсистем (БСП), чтобы встроенная в конфигуратор обработка вела себя точно так же, как внешняя: автоматически выводилась в меню заполнения или печати нужных документов и справочников.
Начиная с ранних версий БСП 3.x, в системе присутствует мощный механизм подключаемых команд. Он позволяет связывать встроенные объекты метаданных (отчеты и обработки) с документами-потребителями без написания кода в формах этих документов. Чтобы наша встроенная обработка автоматически появилась в меню Заполнение нужного документа, нам потребуется выполнить несколько последовательных шагов.
Первое и обязательное условие для того, чтобы БСП вообще «увидела» нашу встроенную обработку — это правильное ее позиционирование в дереве метаданных. Нам необходимо включить обработку в состав подсистемы ПодключаемыеОтчетыИОбработки. Если этого не сделать, менеджер подключаемых команд проигнорирует объект при инициализации системы.
Выполним это в конфигураторе:
СтандартныеПодсистемы -> ПодключаемыеОтчетыИОбработки.Вся магия интеграции происходит в модуле менеджера встроенной обработки. Нам необходимо определить в нем экспортные процедуры, которые БСП вызывает для регистрации команд. Перейдем в модуль менеджера нашей обработки и пропишем следующий код:
#Область ПрограммныйИнтерфейс
// Определяет настройки интеграции обработки с механизмами БСП.
//
// Параметры:
// Настройки - Структура - Настройки интеграции подключаемых отчетов и обработок.
//
Процедура ПриОпределенииНастроек(Настройки) Экспорт
// Указываем, к каким объектам метаданных мы хотим подключить нашу обработку.
// Например, подключим ее к документу "Реализация товаров и услуг".
Настройки.Размещение.Добавить(Метаданные.Документы.РеализацияТоваровУслуг);
// Указываем, что наша обработка предоставляет команды заполнения.
Настройки.ДобавитьКомандыЗаполнения = Истина;
КонецПроцедуры
// Формирует список команд заполнения, которые будут добавлены в форму объекта-потребителя.
//
// Параметры:
// КомандыЗаполнения - ТаблицаЗначений - Команды, выводимые на форму.
// Параметры - Структура - Вспомогательные параметры.
//
Процедура ДобавитьКомандыЗаполнения(КомандыЗаполнения, Параметры) Экспорт
Команда = КомандыЗаполнения.Добавить();
Команда.Идентификатор = "ЗаполнитьПоШаблонуВстроенная";
Команда.Представление = НСтр("ru = 'Заполнить по шаблону (встроенная)'");
Команда.РежимЗаписи = "Записывать"; // Варианты: Записывать, НеЗаписывать, ЗаписыватьТолькоПроведенные
Команда.Очередь = 1;
КонецПроцедуры
#КонецОбласти
Рассмотрим подробнее параметры команды заполнения:
Идентификатор — уникальная строка, по которой система поймет, какую именно команду пользователь выбрал на форме.Представление — текст кнопки, который увидит пользователь в интерфейсе.РежимЗаписи — критически важный параметр для обработок заполнения. Если указать "Записывать", БСП автоматически запишет документ перед выполнением заполнения и после него, что гарантирует целостность данных и корректную работу транзакций.Теперь нам нужно написать код, который будет выполняться непосредственно при нажатии кнопки пользователем. Механизм БСП ожидает, что во встроенной обработке будет реализован экспортный метод для выполнения команды. Пропишем его также в модуле менеджера нашей обработки:
#Область ПрограммныйИнтерфейс
// Выполняет команду заполнения, вызванную из формы объекта.
//
// Параметры:
// ИдентификаторКоманды - Строка - Идентификатор запущенной команды.
// ОбъектыНазначения - Массив - Ссылки на объекты, для которых вызвана команда.
// ПараметрыВыполнения - Структура - Контекст выполнения команды.
//
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ОбъектыНазначения, ПараметрыВыполнения) Экспорт
Если ИдентификаторКоманды = "ЗаполнитьПоШаблонуВстроенная" Тогда
ВыполнитьЗаполнениеДокументов(ОбъектыНазначения, ПараметрыВыполнения);
КонецЕсли;
КонецПроцедуры
#КонецОбласти
#Область СлужебныйПрограммныйИнтерфейс
Процедура ВыполнитьЗаполнениеДокументов(ОбъектыНазначения, ПараметрыВыполнения)
Для Каждого СсылкаНаДокумент Из ОбъектыНазначения Цикл
// Получаем объект документа для изменения данных
ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();
// Пример заполнения реквизита "Комментарий"
ДокументОбъект.Комментарий = ДокументОбъект.Комментарий + " [Заполнено встроенной обработкой " + Строка(ТекущаяДата()) + "]";
Попытка
ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);
Исключение
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
НСтр("ru = 'Не удалось записать документ при заполнении: '") + ОписаниеОшибки()
);
КонецПопытки;
КонецЦикла;
// Оповещаем форму о необходимости перечитать данные
ПараметрыВыполнения.СистемныеПараметры.Вставить("ВыполнитьОповещениеОИзменении", Истина);
КонецПроцедуры
#КонецОбласти
После внесения изменений в конфигуратор и обновления конфигурации базы данных, кнопки на формах документов могут не появиться сразу. Это связано с тем, что БСП кэширует информацию о подключаемых командах в специальных регистрах сведений для ускорения работы интерфейса.
Чтобы заставить БСП перечитать метаданные и зарегистрировать нашу новую встроенную обработку, необходимо выполнить одно из следующих действий:
/ЗапускОбновленияИнформационнойБазы.После этого откроем документ «Реализация товаров и услуг» и убедимся, что на форме в меню Заполнение появилась наша новая кнопка «Заполнить по шаблону (встроенная)».
---
Рассмотрим альтернативную ситуацию. Что делать, если вам крайне важно сохранить возможность администрирования прав доступа к этой обработке штатными средствами БСП (через интерфейс справочника Дополнительные отчеты и обработки, с привязкой к конкретным пользователям или разделам интерфейса), но при этом вы не хотите постоянно перезаливать файл .epf при каждом изменении кода?
Для решения этой задачи мы можем применить крайне удобный гибридный метод:
Обработка.МоеВстроенноеЗаполнение).СведенияОВнешнейОбработке() для интеграции.Посмотрим на пример кода модуля объекта такой внешней обработки-заглушки:
Функция СведенияОВнешнейОбработке() Экспорт
ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.2.2.3");
ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиЗаполнениеОбъекта();
ПараметрыРегистрации.Наименование = "Заполнение объектов (Гибридный метод)";
ПараметрыРегистрации.Информация = "Внешняя заглушка для вызова встроенного кода";
ПараметрыРегистрации.Версия = "1.0";
ПараметрыРегистрации.БезопасныйРежим = Ложь;
НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
НоваяКоманда.Представление = "Заполнить встроенным механизмом";
НоваяКоманда.Идентификатор = "ВыполнитьИнтеграцию";
НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипЗапускаВызовСерверногоМетода();
НоваяКоманда.ПоказыватьОповещение = Истина;
Возврат ПараметрыРегистрации;
КонецФункции
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ОбъектыНазначения, ПараметрыВыполнения) Экспорт
Если ИдентификаторКоманды = "ВыполнитьИнтеграцию" Тогда
// Вызываем код напрямую из встроенной обработки конфигурации!
ВстроенныйОбъект = Обработки.МоеВстроенноеЗаполнение.Создать();
ВстроенныйОбъект.ВыполнитьЗаполнение(ОбъектыНазначения, ПараметрыВыполнения);
КонецЕсли;
КонецПроцедуры
Преимущество этого метода очевидно: мы загружаем внешнюю обработку-заглушку в базу данных всего один раз. В дальнейшем все изменения логики, исправление ошибок и оптимизацию кода мы производим в конфигураторе во встроенной обработке. Нам больше не нужно заходить в режим предприятия и перезаливать файлы обработки для сотен пользователей — код обновляется классическим динамическим обновлением конфигурации или обновлением базы данных.
---
В ходе обсуждения разработчики часто сетуют на то, что БСП по умолчанию выводит все подключаемые команды в общую командную панель формы (кнопки «Заполнить», «Печать» и т.д.), в то время как по логике UX кнопка заполнения конкретной табличной части должна находиться непосредственно в командной панели этой табличной части.
Выясним, как элегантно решить эту проблему, используя программное добавление элементов в форме документа или через расширение конфигурации.
Рассмотрим по шагам программное добавление кнопки в форму документа через расширение:
ПриСозданииНаСервере.Пропишем следующий код, который создаст команду и поместит кнопку непосредственно на командную панель табличной части:
&НаСервере
Процедура Расш1_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
// 1. Создаем команду формы для заполнения табличной части
ИмяКоманды = "ПрограммноеЗаполнениеТЧ";
НоваяКоманда = Команды.Добавить(ИмяКоманды);
НоваяКоманда.Действие = "Подключаемый_ВыполнитьПрограммноеЗаполнениеТЧ";
НоваяКоманда.Заголовок = "Заполнить строки";
// 2. Ищем командную панель нашей табличной части (например, "Товары")
РодительКнопки = Элементы.ТоварыКоманднаяПанель;
Если РодительКнопки <> Неопределено Тогда
// 3. Создаем кнопку и привязываем ее к созданной команде
НоваяКнопка = Элементы.Добавить("КнопкаЗаполнитьТоварыПрограммно", Тип("КнопкаФормы"), РодительКнопки);
НоваяКнопка.ИмяКоманды = ИмяКоманды;
НоваяКнопка.Картинка = БиблиотекаКартинок.ЗаполнитьФорму;
НоваяКнопка.Отображение = ОтображениеКнопки.КартинкаИТекст;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура Подключаемый_ВыполнитьПрограммноеЗаполнениеТЧ(Команда)
// Передаем управление на сервер для выполнения заполнения табличной части
ВыполнитьЗаполнениеТЧНаСервере();
КонецПроцедуры
&НаСервере
Процедура ВыполнитьЗаполнениеТЧНаСервере()
// Получаем объект встроенной обработки
ОбработкаЗаполнения = Обработки.МоеВстроенноеЗаполнение.Создать();
// Передаем объект текущего документа для заполнения табличной части "Товары"
ДокументОбъект = РеквизитФормыВЗначение("Объект");
ОбработкаЗаполнения.ЗаполнитьТабличнуюЧастьТовары(ДокументОбъект);
// Возвращаем измененные данные обратно на форму
ЗначениеВРеквизитФормы(ДокументОбъект, "Объект");
КонецПроцедуры
Используя этот подход, мы получаем идеальный UX: пользователь видит красивую кнопку с иконкой непосредственно над табличной частью «Товары», а вся бизнес-логика заполнения по-прежнему аккуратно инкапсулирована внутри встроенной обработки конфигурации, обеспечивая чистоту кода и простоту поддержки.