В процессе разработки в среде 1С программисты часто сталкиваются с необходимостью автоматизации рутинных действий пользователей. Одной из типичных задач является печать пакета документов. Например, при проведении или нажатии специальной кнопки на форме документа «Реализация товаров и услуг» система должна автоматически найти связанный с ней документ «Счет-фактура выданный» и отправить его на принтер без лишних диалоговых окон.
В этой статье мы подробно разберем, как правильно решить эту задачу в современных конфигурациях 1С, построенных на управляемых формах и Библиотеке Стандартных Подсистем (БСП). Мы выясним причину частых ошибок начинающих разработчиков, проанализируем ситуацию с изменением структуры метаданных и рассмотрим готовые шаблоны кода для быстрого внедрения.
Давайте проанализируем ситуацию, с которой столкнулся автор темы на форуме. Он попытался найти подчиненный документ простым запросом и вызвать метод Печать() напрямую у полученного объекта:
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
Объект = ВыборкаДетальныеЗаписи.Ссылка.ПолучитьОбъект();
Объект.Печать("СчетФактура", 2, Ложь);
КонецЦикла;
При выполнении этого кода система выдает ошибку «Метод объекта не обнаружен». Разберем по шагам, почему этот подход в корне неверен для современных конфигураций 1С (таких как «Бухгалтерия предприятия 3.0», «Управление торговлей 11», «ERP Управление предприятием»):
Печать() у объекта документа закономерно вызывает ошибку платформы.ПолучитьОбъект(). Получение тяжелого объекта базы данных — ресурсоемкая операция. Она считывает все данные документа в оперативную память и накладывает неявные блокировки. Для формирования печатной формы объект не нужен, достаточно иметь только ссылку на него (ДокументСсылка).ДокументОснование. Связь была жесткой — «один к одному». В современных решениях один счет-фактура может быть выписан сразу по нескольким реализациям. Поэтому связь была перенесена в табличную часть ДокументыОснования. Поиск по реквизиту в новых конфигурациях просто не сработает, так как этого реквизита больше нет в структуре метаданных.Рассмотрим подробнее два наиболее эффективных способа поиска подчиненной сущности в системе 1С: через прямой запрос к табличной части и через использование системных критериев отбора.
Этот способ является классическим и наиболее точным, когда нам известен конкретный тип подчиненного документа, который мы ищем. Мы пишем запрос к табличной части подчиненного документа, накладывая фильтр на реквизит ДокументОснование внутри этой таблицы.
Посмотрим на пример такого запроса:
&НаСервере
Функция НайтиСчетФактуруПоРеализации(СсылкаНаРеализацию) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
| СФ_Основания.Ссылка КАК Ссылка
|ИЗ
| Документ.СчетФактураВыданный.ДокументыОснования КАК СФ_Основания
|ГДЕ
| СФ_Основания.ДокументОснование = &ДокументОснование
| И НЕ СФ_Основания.Ссылка.ПометкаУдаления";
Запрос.УстановитьПараметр("ДокументОснование", СсылкаНаРеализацию);
РезультатЗапроса = Запрос.Выполнить();
Если НЕ РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
Возврат Выборка.Ссылка;
КонецЕсли;
Возврат Документы.СчетФактураВыданный.ПустаяСсылка();
КонецФункции
Важные нюансы запроса: использование ключевого слова РАЗРЕШЕННЫЕ гарантирует, что у пользователя не возникнет ошибки прав доступа (RLS) при выполнении кода. Также мы обязательно проверяем, чтобы найденный документ не был помечен на удаление (НЕ Ссылка.ПометкаУдаления).
Если структура метаданных вашей конфигурации часто меняется или вы хотите написать универсальный код, который будет работать для разных типов подчиненных документов, разберем по шагам использование системного механизма Критерии отбора.
В платформе 1С существует предопределенный критерий отбора СвязанныеДокументы. Он работает как готовый индекс связей между всеми документами в системе. Этот способ работает быстрее, так как платформа сама оптимизирует SQL-запрос к СУБД.
Пример программного получения подчиненного документа через критерий отбора:
&НаСервере
Функция НайтиСчетФактуруЧерезКритерийОтбора(СсылкаНаРеализацию) Экспорт
ТаблицаСвязей = КритерииОтбора.СвязанныеДокументы.Найти(СсылкаНаРеализацию);
// В результате мы получаем таблицу значений с колонкой "Ссылка"
Для Каждого СтрокаТаблицы Из ТаблицаСвязей Цикл
СсылкаНаДокумент = СтрокаТаблицы.Ссылка;
// Фильтруем по нужному нам типу и исключаем удаленные
Если ТипЗнч(СсылкаНаДокумент) = Тип("ДокументСсылка.СчетФактураВыданный")
И НЕ СсылкаНаДокумент.ПометкаУдаления Тогда
Возврат СсылкаНаДокумент;
КонецЕсли;
КонецЦикла;
Возврат Документы.СчетФактураВыданный.ПустаяСсылка();
КонецФункции
После того как ссылка на подчиненный документ успешно найдена, необходимо вывести его на печать. В современных конфигурациях 1С для этого используется подсистема «Печать» из состава Библиотеки Стандартных Подсистем (БСП). Рассмотрим два сценария реализации этой задачи.
Если вам нужно, чтобы перед отправкой на принтер пользователь увидел стандартное окно предпросмотра БСП (где можно изменить количество копий, выбрать принтер или сохранить документ в PDF), необходимо использовать клиентский метод общего модуля УправлениеПечатьюКлиент.ВыполнитьКомандуПечати.
Разберем пример реализации команды на форме:
&НаКлиенте
Процедура КомандаПечатьПакета(Команда)
// Получаем ссылку на подчиненный счет-фактуру (вызываем серверный метод)
СчетФактураСсылка = НайтиСчетФактуруПоРеализации(Объект.Ссылка);
Если СчетФактураСсылка.Пустая() Тогда
ПоказатьПредупреждение(, "Для данной реализации не найден проведенный счет-фактура!");
Возврат;
КонецЕсли;
// Формируем параметры для БСП
МассивОбъектов = Новый Массив;
МассивОбъектов.Добавить(СчетФактураСсылка);
ПараметрыПечати = Новый Структура;
ПараметрыПечати.Вставить("КоличествоЭкземпляров", 2); // Задаем печать двух копий
// Вызываем интерактивное окно печати БСП
УправлениеПечатьюКлиент.ВыполнитьКомандуПечати(
"Документ.СчетФактураВыданный", // Путь к менеджеру объекта печати
"СчетФактура", // Идентификатор команды печати (имя макета)
МассивОбъектов,
ЭтаФорма,
ПараметрыПечати
);
КонецПроцедуры
Иногда требуется отправить документ на принтер в фоновом режиме, без вывода каких-либо окон на экран пользователя. Для этого нам нужно программно получить табличный документ на сервере и отправить его на принтер по умолчанию.
Рассмотрим, как это сделать программно:
&НаСервере
Процедура НапечататьСчетФактуруНаСервере(СчетФактураСсылка)
МассивОбъектов = Новый Массив;
МассивОбъектов.Добавить(СчетФактураСсылка);
ПараметрыПечати = Новый Структура;
КоллекцияПечатныхФорм = Новый ТаблицаЗначений;
КоллекцияПечатныхФорм.Колонки.Добавить("ИмяМакета");
КоллекцияПечатныхФорм.Колонки.Добавить("ТабличныйДокумент");
КоллекцияПечатныхФорм.Колонки.Добавить("СинонимМакета");
// Заполняем строку коллекции для формирования нужной печатной формы
НоваяСтрока = КоллекцияПечатныхФорм.Добавить();
НоваяСтрока.ИмяМакета = "СчетФактура"; // Системное имя макета в БСП
// Вызываем серверный метод БСП для формирования табличного документа
ОбщегоНазначенияБП.СформироватьПечатныеФормы(
"Документ.СчетФактураВыданный",
"СчетФактура",
МассивОбъектов,
ПараметрыПечати,
КоллекцияПечатныхФорм,
Новый СписокЗначений,
Новый Структура
);
// Если форма успешно сформирована, отправляем ее на принтер
Если КоллекцияПечатныхФорм.Количество() > 0 Тогда
ТабДок = КоллекцияПечатныхФорм[0].ТабличныйДокумент;
// Настройки принтера
ТабДок.ИмяПринтера = "HP_LaserJet_Pro_M402"; // Опционально: указание конкретного принтера
ТабДок.КоличествоЭкземпляров = 2;
// Параметр Ложь указывает на печать без вывода диалога настроек
ТабДок.Напечатать(РежимИспользованияПринтера.Использовать);
КонецЕсли;
КонецПроцедуры
Обратите внимание: При запуске «тихой» печати непосредственно с сервера 1С, принтер должен быть установлен и доступен на самом сервере приложений 1С:Предприятие (под учетной записью, от имени которой запущена служба сервера 1С).
Подведем итог нашему разбору. Чтобы ваш код был надежным, быстрым и соответствовал стандартам разработки фирмы «1С», всегда придерживайтесь следующих правил:
ПолучитьОбъект() для задач печати или простого чтения реквизитов — работайте исключительно со ссылками.ДокументыОснования.КритерииОтбора.СвязанныеДокументы.Найти().УправлениеПечатьюКлиент.ВыполнитьКомандуПечати(). Это сохранит единый интерфейс программы для пользователей и сбережет ваше время разработки.