Почему ТабДок возвращает Неопределено при печати внешней формы и как это исправить

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При разработке внешних печатных форм в конфигурациях на базе обычного приложения (например, БГУ 1.0, УПП 1.3, КА 1.1) программисты часто сталкиваются с ситуацией, когда при попытке программного вызова печати через УниверсальныеМеханизмы.НапечататьВнешнююФорму переменная, предназначенная для хранения табличного документа, остается пустой (Неопределено). Это делает невозможным дальнейшее сохранение документа в формате PDF или отправку его по электронной почте. Рассмотрим подробно причины возникновения этой проблемы и разберем по шагам способы ее решения.

Разбор основной причины: Процедура против Функции

Первое, на что мы должны обратить внимание — это тип вызываемого метода. В языке 1С Процедура просто выполняет набор действий, в то время как Функция обязана вернуть результат. В типовых механизмах старых конфигураций многие экспортные методы печати спроектированы как процедуры, предназначенные исключительно для вывода макета на экран пользователя. Они открывают форму печати, но не передают сформированный объект ТабличныйДокумент обратно в вызывающий код.

Проанализируем ситуацию: когда вы вызываете ТабДок = УниверсальныеМеханизмы.НапечататьВнешнююФорму(...), ожидается, что внешняя обработка вернет объект. Однако, если внутри внешней обработки вместо функции Печать используется процедура, или если функция не содержит оператора Возврат, результатом выполнения всегда будет Неопределено.

Шаг 1. Модернизация модуля объекта внешней печатной формы

Для того чтобы система могла "забрать" сформированный документ, нам необходимо убедиться, что основная точка входа во внешней обработке является функцией. Рассмотрим пример правильной реализации функции Печать() в модуле объекта внешней обработки:


Функция Печать() Экспорт
    
    // Инициализируем переменные для формирования
    ИмяМакета = "УниверсальныйПередаточныйДокумент";
    КоличествоЭкземпляров = 1;
    НаПринтер = Ложь;
    НепосредственнаяПечать = Ложь;
    
    // Вызываем вспомогательную функцию, которая формирует ТабДок
    // Важно: СтандартнаяПроцедураПечать тоже должна быть функцией!
    ТабДок = СтандартнаяПроцедураПечать(ИмяМакета, КоличествоЭкземпляров, НаПринтер, НепосредственнаяПечать);
    
    // Обязательно возвращаем объект в вызывающий код
    Возврат ТабДок;
    
КонецФункции

Шаг 2. Исправление вспомогательных методов формирования макета

Часто внутри внешней обработки логика разделена на несколько этапов. Если ваша основная функция вызывает СтандартнаяПроцедураПечать, проверьте ее заголовок и завершение. Выясним причину, почему она может "терять" данные. Если этот метод определен как процедура, его нужно переделать в функцию. Посмотрим на пример кода:


Функция СтандартнаяПроцедураПечать(ИмяМакета, КоличествоЭкземпляров = 1, НаПринтер = Ложь, НепосредственнаяПечать = Ложь) Экспорт 
    
    ТабДокумент = Неопределено;
    
    Если ИмяМакета = "УниверсальныйПередаточныйДокумент" Тогда 
        ТабДокумент = ПечатьУниверсальногоПередаточногоДокумента(); 
    ИначеЕсли ИмяМакета = "ТОРГ12" Тогда 
        ТабДокумент = ПечатьТОРГ12(); 
    КонецЕсли; 

    // ВНИМАНИЕ: Если мы хотим сохранить документ программно, 
    // нам НЕ НУЖНО вызывать УниверсальныеМеханизмы.НапечататьДокумент,
    // так как он просто откроет окно на экране.
    // Нам нужно просто вернуть сформированный ТабДокумент.
    
    Возврат ТабДокумент; 

КонецФункции

Важный нюанс: метод УниверсальныеМеханизмы.НапечататьДокумент в некоторых конфигурациях (например, БГУ 1.0) является процедурой. Если в конце вашей функции вы напишете Возврат УниверсальныеМеханизмы.НапечататьДокумент(...), вы получите Неопределено, так как процедура ничего не возвращает. Проанализируйте код общего модуля перед вызовом.

Шаг 3. Программное сохранение в PDF

Когда мы успешно получили ТабДок, можно приступать к его сохранению. Выясним, почему может возникать ошибка "Значение не является значением объектного типа (Записать)". Она происходит, если ТабДок все еще равен Неопределено. Перед вызовом метода Записать всегда проверяйте состояние переменной.

Рассмотрим пример надежной функции сохранения:


Функция СохранитьВPDF(ДокументСсылка, ТабДок)
    
    Если ТабДок = Неопределено Тогда
        Сообщить("Ошибка: Табличный документ не сформирован!");
        Возврат Неопределено;
    КонецЕсли;
    
    СтруктураФайла = Новый Структура;
    
    // Формируем уникальное имя файла
    ИмяФайла = "Документ_" + СокрЛП(ДокументСсылка.Номер) + ".pdf";
    ПутьКФайлу = ПолучитьИмяВременногоФайла("pdf");
    
    Попытка
        // Метод Записать работает на платформе 8.2.13 и выше
        ТабДок.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.PDF);
        
        СтруктураФайла.Вставить("Путь", ПутьКФайлу);
        СтруктураФайла.Вставить("Имя", ИмяФайла);
        
        Возврат СтруктураФайла;
    Исключение
        Сообщить("Не удалось записать файл: " + ОписаниеОшибки());
        Возврат Неопределено;
    КонецПопытки;
    
КонецФункции

Шаг 4. Особенности работы в цикле при массовой отправке

Проанализируем ситуацию, описанную в сообщениях форума, когда при обходе массива документов сохраняется только последний файл или возникают ошибки вложений. Основная ошибка заключается в неправильной инициализации коллекции вложений внутри цикла.

Рассмотрим правильный алгоритм массовой обработки документов:

  1. Создаем соответствие для вложений ДО начала цикла.
  2. Внутри цикла формируем ТабличныйДокумент для текущего объекта.
  3. Сохраняем его во временный файл.
  4. Добавляем путь к файлу и его двоичные данные в общую коллекцию.

Пример исправленного кода для массовой обработки:


// Правильно: инициализируем вложения перед циклом
ВложенияПисьма = Новый Соответствие; 

Для Каждого СтрокаИзСписка Из МассивДокументов Цикл
    
    ДокСсылка = СтрокаИзСписка.Ссылка;
    
    // Получаем ТабДок через нашу исправленную функцию Печать()
    ТабДок = НайтиИВыполнитьПечатьВнешнейФормы(ДокСсылка); 
    
    Если ТабДок <> Неопределено Тогда
        ПутьФайла = ПолучитьИмяВременногоФайла("pdf");
        ТабДок.Записать(ПутьФайла, ТипФайлаТабличногоДокумента.PDF);
        
        // Ключ - имя файла, значение - ДвоичныеДанные
        ИмяВложения = "Счет_" + ДокСсылка.Номер + ".pdf";
        ВложенияПисьма.Вставить(ИмяВложения, Новый ДвоичныеДанные(ПутьФайла));
    КонецЕсли;
    
КонецЦикла;

// Теперь в ВложенияПисьма содержатся файлы всех обработанных документов
ПараметрыПисьма.Вставить("Вложения", ВложенияПисьма);

Резюме и важные советы

Подводя итог, можно выделить следующие ключевые моменты для стабильной работы печати внешних форм:

Соблюдение этих правил позволит вам избежать большинства "мистических" ошибок при программной работе с печатными формами в 1С.

← На главную