Как изменить реквизит объекта 1С именно в момент отправки документа на печать

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

В практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача автоматизации складской логистики или документооборота. Типичный пример: менеджер помечает заказ флагом «Готов к печати», а сборщик на складе должен его распечатать. После физической печати флаг должен автоматически сниматься, чтобы документ исчез из списка задач сборщика. Главная сложность здесь заключается в том, чтобы отличить предварительный просмотр документа на экране от его реальной отправки на принтер.

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

Анализ технической проблемы: Почему нельзя использовать стандартное формирование?

Проанализируем ситуацию: стандартно печатная форма формируется в модуле менеджера объекта. Если мы пропишем код изменения реквизита там, то флаг снимется в тот момент, когда пользователь нажал кнопку «Печать» в карточке документа. Но на этом этапе документ всего лишь открывается в форме предварительного просмотра. Пользователь может посмотреть на него, закрыть форму или сохранить в PDF, так и не отправив на принтер. В итоге: флаг снят, документ не напечатан, сборщик про него забыл.

Следовательно, нам нужно «поймать» событие нажатия кнопки «Печать» уже в самой форме просмотра табличных документов (ПечатьДокументов).

Решение 1: Расширение общей формы «ПечатьДокументов»

Это наиболее корректный путь для современных конфигураций (ERP, УТ 11, BAS УТ). Почти все печатные формы выводятся через общую форму ПечатьДокументов. Нам нужно перехватить команду отправки на принтер.

Разберем по шагам, как это сделать с помощью механизма расширений:

  1. Создадим расширение и добавим в него общую форму ПечатьДокументов.
  2. Найдем команду, отвечающую за печать (обычно это Печать или вызов метода Напечатать()).
  3. Используем аннотацию &После для процедуры, которая выполняет отправку на принтер.

Рассмотрим пример кода в расширении для клиентской части формы:


&НаКлиенте
Процедура Расш_ПечатьПосле(Команда)
    // Массив документов, которые были выведены на печать, 
    // обычно доступен через параметры формы или структуру печатных форм
    Для Каждого ЭлементПечати Из ОбъектыПечати Цикл
        Если ТипЗнч(ЭлементПечати.Значение) = Тип("ДокументСсылка.ЗаказКлиента") Тогда
            СнятьФлагРаспечатаноНаСервере(ЭлементПечати.Значение);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

В этом коде мы проверяем тип объекта, чтобы случайно не сбросить реквизиты у других документов (например, у накладных), которые могут печататься одновременно.

Решение 2: Перехват в общем модуле «УправлениеПечатьюКлиент»

Если задача требует глобального контроля над всеми процессами печати в системе, можно проанализировать общий модуль УправлениеПечатьюКлиент. В нем часто используется процедура РаспечататьТабличныеДокументы.

Проанализируем ситуацию подробнее: данный модуль отвечает за передачу пакета сформированных табличных документов непосредственно драйверу принтера. Метод ТабличныйДокумент.Напечатать() является точкой невозврата. Как только он выполнен, 1С передает задание в очередь печати операционной системы.

Пример модификации логики (через расширение общего модуля):


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

Решение 3: Регистрация факта печати в Регистре Сведений

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

Вместо Булевного реквизита в документе создадим непериодический регистр сведений СтатусыПечатиДокументов с измерениями Документ и ресурсом Напечатан (Булево).

Преимущества такого подхода:

Обработка групповой печати и ошибок

Выясним причину, почему важна обработка исключений. При печати 30 документов за раз один из них может быть заблокирован другим пользователем. Если ваш код прервется ошибкой на 5-м документе, остальные не обработаются.

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


&НаСервере
Процедура СнятьФлагРаспечатаноНаСервере(СсылкаНаЗаказ)
    ОбъектЗаказ = СсылкаНаЗаказ.ПолучитьОбъект();
    Если ОбъектЗаказ = Неопределено Тогда
        Возврат; // Документ мог быть удален
    КонецЕсли;
    
    Попытка
        Блокировка = Новый БлокировкаДанных;
        ЭлементБлокировки = Блокировка.Добавить("Документ.ЗаказКлиента");
        ЭлементБлокировки.УстановитьЗначение("Ссылка", СсылкаНаЗаказ);
        Блокировка.Заблокировать();
        
        ОбъектЗаказ.ДополнительныеРеквизиты.Очистить(); // Если это доп. реквизит
        // Или прямое обращение, если реквизит добавлен в конфигурацию:
        ОбъектЗаказ.Распечатан = Ложь;
        
        // Устанавливаем признак обмена данными, чтобы не срабатывали лишние проверки
        ОбъектЗаказ.ОбменДанными.Загрузка = Истина; 
        ОбъектЗаказ.Записать(РежимЗаписиДокумента.Запись);
    Исключение
        ЗаписьЖурналаРегистрации("Печать", УровеньЖурналаРегистрации.Ошибка, , , 
            "Не удалось снять флаг печати для документа: " + СсылкаНаЗаказ);
    КонецПопытки;
КонецПроцедуры

Ограничения платформы: Вышла ли бумага?

Важно понимать: 1С не получает обратной связи от принтера о том, закончилась ли там бумага или застрял ли картридж. Метод Напечатать() завершается успешно, как только данные ушли в диспетчер печати Windows. Если для бизнеса критично подтверждение факта «бумага в руках у сборщика», программными методами 1С это решить невозможно без интеграции со сторонним ПО мониторинга очередей печати.

Однако для большинства задач автоматизации склада достаточно того, что команда была отправлена. Если принтер зажует бумагу, сборщик нажмет «Печать» повторно, и система снова отработает алгоритм.

Рекомендации для разработчика

Подведем итог и выделим основные шаги для реализации качественного решения:

  1. Используйте Расширения. Это позволит сохранить конфигурацию на поддержке и легко обновляться.
  2. Если используется БСП, делайте привязку к ОбщаяФорма.ПечатьДокументов.
  3. Для массовой печати (пакетный режим) всегда используйте Попытка...Исключение, чтобы ошибка записи одного документа не останавливала весь процесс.
  4. Рассмотрите возможность использования фоновых заданий для записи объектов. Это позволит пользователю не ждать, пока система запишет все 30 заказов после закрытия диалога печати.
  5. Вместо удаления флага вручную, создайте для сборщика динамический список, где условие отбора ГДЕ НЕ Распечатан будет скрывать отработанные заказы автоматически.

Разберем последний совет подробнее. В рабочем месте сборщика настройте запрос динамического списка:


ВЫБРАТЬ
    ЗаказКлиента.Ссылка,
    ЗаказКлиента.Номер,
    ЗаказКлиента.Дата
ИЗ
    Документ.ЗаказКлиента КАК ЗаказКлиента
ГДЕ
    ЗаказКлиента.Распечатан = ИСТИНА
    И ЗаказКлиента.Проведен = ИСТИНА

Такой подход в сочетании с перехватом кнопки печати обеспечит бесшовную и быструю работу склада без лишних действий со стороны персонала.

← На главную