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