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