Как динамически изменить имя файла печатной формы при ее сохранении в 1С?

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

При работе в 1С пользователи часто сохраняют сформированные печатные формы (документы, отчеты, претензии) на локальный диск в форматах PDF, Excel или MXL. По умолчанию платформа предлагает стандартное имя файла, совпадающее с синонимом макета печатной формы. Например, «Претензия (долг, пени, изъятие)».

Однако на практике бизнесу требуется, чтобы сохраненные файлы имели информативные названия. В имя файла часто необходимо автоматически добавлять номер и дату документа, наименование контрагента, договор или другие реквизиты. Разберем по шагам, как решить эту задачу правильно с точки зрения производительности и стандартов разработки 1С, включая использование механизмов Библиотеки стандартных подсистем (БСП).

Быстрое решение с форума: в чем его суть и недостатки

Участники обсуждения на форуме пришли к решению изменять третий параметр процедуры вывода печатной формы в модуле менеджера документа. Рассмотрим этот код:


УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(
    КоллекцияПечатныхФорм,
    "ПретензияДолгПениИзъятие",
    "Претензия (долг, пени, изъятие) " + ТекКонтрагент + " " + ТекДоговор,
    ТабличныйДокумент
);

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

  1. Проблема групповой печати. Третий параметр процедуры ВывестиТабличныйДокументВКоллекцию определяет представление печатной формы в коллекции. Если пользователь выделит в списке 10 документов разным контрагентам и нажмет кнопку «Печать», система сформирует единый пакет. Изменение представления макета приведет к тому, что все документы пакета будут пытаться сохраниться под именем первого документа или вызовут ошибку уникальности в коллекции.
  2. Грубейшая ошибка производительности (Запрос в цикле). Для получения контрагента и договора в модуле менеджера на форуме было предложено использовать конструкцию обращения через точку в цикле: ТекСсылка.Контрагент. Это классическая проблема производительности «N+1 запрос». При печати 100 документов система сделает 100 отдельных запросов к базе данных, что вызовет сильные задержки в работе сервера.
  3. Недопустимые символы операционной системы. Наименования контрагентов часто содержат кавычки (например, ООО "Рога и Копыта"), а договоры — слэши и знаки номеров (например, Договор №12/34-А). Символы \, /, :, *, ?, ", <, >, | запрещены операционной системой для использования в именах файлов. Попытка записать файл с таким именем вызовет ошибку среды выполнения или сбросит имя файла на стандартное «Таблица.mxl».

Проанализируем, как решить эту задачу правильно и обойти все вышеописанные проблемы.

Способ 1. Использование параметра «ИмяФайлаПечатнойФормы» в БСП (Рекомендуемый)

В современных конфигурациях 1С, разработанных на базе БСП, у процедуры УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию есть седьмой (необязательный) параметр — ИмяФайлаПечатнойФормы. Именно он предназначен для динамического переопределения имени файла сохранения.

Этот параметр может принимать не просто строку, а целое Соответствие, где в качестве ключа передается ссылка на конкретный объект печати (документ), а в качестве значения — индивидуально сформированное имя файла. Это полностью решает проблему групповой печати!

Разберем пример правильной реализации в процедуре Печать модуля менеджера документа:


Процедура Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт

    // 1. Сначала оптимизированно получаем все нужные реквизиты ОДНИМ запросом
    ТаблицаДанных = ПолучитьДанныеДляПечати(МассивОбъектов);
    
    // 2. Формируем табличные документы (стандартная логика вашей печатной формы)
    // ... (код формирования табличного документа ТабДок)
    
    // 3. Выводим табличный документ в коллекцию
    УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(
        КоллекцияПечатныхФорм,
        "ПретензияДолгПениИзъятие",
        "Претензия (долг, пени, изъятие)", // Статичное представление в интерфейсе 1С
        ТабДок
    );
    
    // 4. Настраиваем индивидуальные имена файлов для каждого документа при сохранении
    ПечатнаяФорма = УправлениеПечатью.СведенияОПечатнойФорме(КоллекцияПечатныхФорм, "ПретензияДолгПениИзъятие");
    Если ПечатнаяФорма <> Неопределено Тогда
        
        ИменаФайлов = Новый Соответствие;
        Для Каждого СтрокаДанных Из ТаблицаДанных Цикл
            
            // Формируем красивое и безопасное имя файла
            НомерДок = СтрокаДанных.Номер;
            ДатаДок = Формат(СтрокаДанных.Дата, "ДФ=dd.MM.yyyy");
            КонтрагентНаименование = СтрокаДанных.КонтрагентНаименование;
            ДоговорНаименование = СтрокаДанных.ДоговорНаименование;
            
            ШаблонИмени = СтрШаблон("Претензия № %1 от %2 (%3, %4)", НомерДок, ДатаДок, КонтрагентНаименование, ДоговорНаименование);
            
            // Очищаем от недопустимых символов операционной системы
            БезопасноеИмяФайла = ОчиститьИмяФайлаОтЗапрещенныхСимволов(ШаблонИмени);
            
            ИменаФайлов.Вставить(СтрокаДанных.Ссылка, БезопасноеИмяФайла);
            
        КонецЦикла;
        
        // Передаем соответствие в БСП
        ПечатнаяФорма.ИмяФайлаПечатнойФормы = ИменаФайлов;
        
    КонецЕсли;

КонецПроцедуры

Способ 2. Оптимизированное получение данных без «запросов в цикле»

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


Функция ПолучитьДанныеДляПечати(МассивОбъектов)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Ссылка КАК Ссылка,
        |   Номер КАК Номер,
        |   Дата КАК Дата,
        |   Контрагент.Наименование КАК КонтрагентНаименование,
        |   ДоговорКонтрагента.Наименование КАК ДоговорНаименование
        |ИЗ
        |   Документ.Претензия КАК Претензия
        |ГДЕ
        |   Ссылка В(&МассивОбъектов)";
        
    Запрос.УстановитьПараметр("МассивОбъектов", МассивОбъектов);
    
    Возврат Запрос.Выполнить().Выгрузить();
    
КонецФункции

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


РеквизитыОбъектов = ОбщегоНазначения.ЗначенияРеквизитовОбъектов(МассивОбъектов, "Номер, Дата, Контрагент.Наименование, ДоговорКонтрагента.Наименование");

Этот метод также выполняет всего один запрос к СУБД под капотом и возвращает соответствие значений, исключая зависания системы при больших объемах данных.

Способ 3. Защита от ошибок записи: Очистка имени файла от запрещенных символов

Для предотвращения сбоев при сохранении файлов операционной системой обязательно нужно выполнять предварительную валидацию строки. Напишем функцию, которая удаляет или заменяет все недопустимые спецсимволы в имени файла на безопасные:


Функция ОчиститьИмяФайлаОтЗапрещенныхСимволов(ИсходноеИмя) Экспорт
    
    // Если в конфигурации есть БСП, можно использовать готовую функцию:
    // Возврат СтроковыеФункцииКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла(ИсходноеИмя, "_");
    
    // Если пишем универсальное решение:
    ЗапрещенныеСимволы = "/\:*?""<>|";
    Результат = ИсходноеИмя;
    
    Для Индекс = 1 По СтрДлина(ЗапрещенныеСимволы) Цикл
        Символ = Сред(ЗапрещенныеСимволы, Индекс, 1);
        Результат = СтрЗаменить(Результат, Символ, " "); // Заменяем запрещенный символ на пробел
    КонецЦикла;
    
    // Дополнительно удалим двойные пробелы, которые могли образоваться при заменах
    Пока Найти(Результат, "  ") > 0 Цикл
        Результат = СтрЗаменить(Результат, "  ", " ");
    КонецЦикла;
    
    Возврат СокрЛП(Результат);
    
КонецФункции

Способ 4. Решение для самописных конфигураций (без использования БСП)

Если вы ведете разработку в полностью самописной конфигурации или старой конфигурации 1С, где отсутствует Библиотека стандартных подсистем, управлять именем файла при сохранении можно напрямую через свойства формируемого табличного документа.

У объекта ТабличныйДокумент существует стандартное свойство ИспользуемоеИмяФайла. Если вы заполните его при формировании макета, платформа 1С автоматически подставит данное значение в диалоговое окно выбора пути сохранения файла при нажатии пользователем кнопки «Сохранить как».

Посмотрим на пример реализации данного подхода:


ТабДок = Новый ТабличныйДокумент;
// ... (Заполнение макета данными)

// Задаем имя файла напрямую в свойствах табличного документа
ИмяДляСохранения = СтрШаблон("Претензия № %1 от %2", СсылкаНаДокумент.Номер, Формат(СсылкаНаДокумент.Дата, "ДФ=dd.MM.yyyy"));
ТабДок.ИспользуемоеИмяФайла = ОчиститьИмяФайлаОтЗапрещенныхСимволов(ИмяДляСохранения);

ТабДок.Показать();

Подведем итоги

Для реализации качественного механизма кастомизации имен сохраняемых файлов в 1С придерживайтесь следующих правил:

← На главную