При разработке внешних печатных форм в конфигурациях на базе обычного приложения (например, БГУ 1.0, УПП 1.3, КА 1.1) программисты часто сталкиваются с ситуацией, когда при попытке программного вызова печати через УниверсальныеМеханизмы.НапечататьВнешнююФорму переменная, предназначенная для хранения табличного документа, остается пустой (Неопределено). Это делает невозможным дальнейшее сохранение документа в формате PDF или отправку его по электронной почте. Рассмотрим подробно причины возникновения этой проблемы и разберем по шагам способы ее решения.
Первое, на что мы должны обратить внимание — это тип вызываемого метода. В языке 1С Процедура просто выполняет набор действий, в то время как Функция обязана вернуть результат. В типовых механизмах старых конфигураций многие экспортные методы печати спроектированы как процедуры, предназначенные исключительно для вывода макета на экран пользователя. Они открывают форму печати, но не передают сформированный объект ТабличныйДокумент обратно в вызывающий код.
Проанализируем ситуацию: когда вы вызываете ТабДок = УниверсальныеМеханизмы.НапечататьВнешнююФорму(...), ожидается, что внешняя обработка вернет объект. Однако, если внутри внешней обработки вместо функции Печать используется процедура, или если функция не содержит оператора Возврат, результатом выполнения всегда будет Неопределено.
Для того чтобы система могла "забрать" сформированный документ, нам необходимо убедиться, что основная точка входа во внешней обработке является функцией. Рассмотрим пример правильной реализации функции Печать() в модуле объекта внешней обработки:
Функция Печать() Экспорт
// Инициализируем переменные для формирования
ИмяМакета = "УниверсальныйПередаточныйДокумент";
КоличествоЭкземпляров = 1;
НаПринтер = Ложь;
НепосредственнаяПечать = Ложь;
// Вызываем вспомогательную функцию, которая формирует ТабДок
// Важно: СтандартнаяПроцедураПечать тоже должна быть функцией!
ТабДок = СтандартнаяПроцедураПечать(ИмяМакета, КоличествоЭкземпляров, НаПринтер, НепосредственнаяПечать);
// Обязательно возвращаем объект в вызывающий код
Возврат ТабДок;
КонецФункции
Часто внутри внешней обработки логика разделена на несколько этапов. Если ваша основная функция вызывает СтандартнаяПроцедураПечать, проверьте ее заголовок и завершение. Выясним причину, почему она может "терять" данные. Если этот метод определен как процедура, его нужно переделать в функцию. Посмотрим на пример кода:
Функция СтандартнаяПроцедураПечать(ИмяМакета, КоличествоЭкземпляров = 1, НаПринтер = Ложь, НепосредственнаяПечать = Ложь) Экспорт
ТабДокумент = Неопределено;
Если ИмяМакета = "УниверсальныйПередаточныйДокумент" Тогда
ТабДокумент = ПечатьУниверсальногоПередаточногоДокумента();
ИначеЕсли ИмяМакета = "ТОРГ12" Тогда
ТабДокумент = ПечатьТОРГ12();
КонецЕсли;
// ВНИМАНИЕ: Если мы хотим сохранить документ программно,
// нам НЕ НУЖНО вызывать УниверсальныеМеханизмы.НапечататьДокумент,
// так как он просто откроет окно на экране.
// Нам нужно просто вернуть сформированный ТабДокумент.
Возврат ТабДокумент;
КонецФункции
Важный нюанс: метод УниверсальныеМеханизмы.НапечататьДокумент в некоторых конфигурациях (например, БГУ 1.0) является процедурой. Если в конце вашей функции вы напишете Возврат УниверсальныеМеханизмы.НапечататьДокумент(...), вы получите Неопределено, так как процедура ничего не возвращает. Проанализируйте код общего модуля перед вызовом.
Когда мы успешно получили ТабДок, можно приступать к его сохранению. Выясним, почему может возникать ошибка "Значение не является значением объектного типа (Записать)". Она происходит, если ТабДок все еще равен Неопределено. Перед вызовом метода Записать всегда проверяйте состояние переменной.
Рассмотрим пример надежной функции сохранения:
Функция СохранитьВPDF(ДокументСсылка, ТабДок)
Если ТабДок = Неопределено Тогда
Сообщить("Ошибка: Табличный документ не сформирован!");
Возврат Неопределено;
КонецЕсли;
СтруктураФайла = Новый Структура;
// Формируем уникальное имя файла
ИмяФайла = "Документ_" + СокрЛП(ДокументСсылка.Номер) + ".pdf";
ПутьКФайлу = ПолучитьИмяВременногоФайла("pdf");
Попытка
// Метод Записать работает на платформе 8.2.13 и выше
ТабДок.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.PDF);
СтруктураФайла.Вставить("Путь", ПутьКФайлу);
СтруктураФайла.Вставить("Имя", ИмяФайла);
Возврат СтруктураФайла;
Исключение
Сообщить("Не удалось записать файл: " + ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
КонецФункции
Проанализируем ситуацию, описанную в сообщениях форума, когда при обходе массива документов сохраняется только последний файл или возникают ошибки вложений. Основная ошибка заключается в неправильной инициализации коллекции вложений внутри цикла.
Рассмотрим правильный алгоритм массовой обработки документов:
ТабличныйДокумент для текущего объекта.Пример исправленного кода для массовой обработки:
// Правильно: инициализируем вложения перед циклом
ВложенияПисьма = Новый Соответствие;
Для Каждого СтрокаИзСписка Из МассивДокументов Цикл
ДокСсылка = СтрокаИзСписка.Ссылка;
// Получаем ТабДок через нашу исправленную функцию Печать()
ТабДок = НайтиИВыполнитьПечатьВнешнейФормы(ДокСсылка);
Если ТабДок <> Неопределено Тогда
ПутьФайла = ПолучитьИмяВременногоФайла("pdf");
ТабДок.Записать(ПутьФайла, ТипФайлаТабличногоДокумента.PDF);
// Ключ - имя файла, значение - ДвоичныеДанные
ИмяВложения = "Счет_" + ДокСсылка.Номер + ".pdf";
ВложенияПисьма.Вставить(ИмяВложения, Новый ДвоичныеДанные(ПутьФайла));
КонецЕсли;
КонецЦикла;
// Теперь в ВложенияПисьма содержатся файлы всех обработанных документов
ПараметрыПисьма.Вставить("Вложения", ВложенияПисьма);
Подводя итог, можно выделить следующие ключевые моменты для стабильной работы печати внешних форм:
Возврат объекта ТабличныйДокумент.ФормуПечати.ТабДок = Обработка.Печать(). Если после выполнения строки значение переменной Неопределено, значит, внутри обработки управление вышло из функции без оператора Возврат.ПолучитьИмяВременногоФайла, чтобы не засорять диск сервера или рабочей станции.Соблюдение этих правил позволит вам избежать большинства "мистических" ошибок при программной работе с печатными формами в 1С.