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