В торговых компаниях часто возникает задача контроля за документооборотом. Одной из таких задач является фиксация факта печати документов, например, заказа клиента в конфигурации «1С:Управление торговлей 11» (УТ 11). Это позволяет избежать повторной печати документов менеджерами, контролировать бумажный поток и оперативно отслеживать состояние заказов.
В рамках данной статьи мы подробно разберем, как решить эту задачу. Мы начнем с простого решения, предложенного на форуме, проанализируем его критические недостатки, которые могут нарушить работу базы данных, а затем рассмотрим профессиональные и архитектурно правильные альтернативы.
Рассмотрим вариант реализации, который чаще всего первым приходит в голову начинающим разработчикам. Он заключается в том, чтобы перехватить нажатие кнопки печати непосредственно на форме документа ЗаказКлиента.
Для реализации этого метода нам потребуется создать расширение конфигурации и перехватить процедуру Подключаемый_ВыполнитьКоманду формы документа с помощью аннотации &После.
Выполним следующие шаги для настройки перехвата команды:
ФормаДокумента объекта Документ.ЗаказКлиента.Подключаемый_ВыполнитьКоманду(Команда) и добавим ее в расширение с обработчиком После.Посмотрим на пример программного кода, который реализует эту логику:
&После("Подключаемый_ВыполнитьКоманду")
Процедура Расш1_Подключаемый_ВыполнитьКоманду(Команда)
Если НЕ Команда = Неопределено И Команда.Имя = "ПодменюПечатьОбычное_ЗаказКлиента" Тогда
// Устанавливаем признак печати в объекте формы
ЭтаФорма.Объект.Напечатан = Истина;
// Для фиксации изменений в базе данных необходимо записать документ
Попытка
ЭтаФорма.Записать();
Исключение
ВызватьИсключение "Не удалось зафиксировать признак печати документа: " + ОписаниеОшибки();
КонецПопытки;
КонецЕсли;
КонецПроцедуры
Разберем, как работает данный код. При нажатии пользователем на кнопку печати срабатывает подключенная команда формы. Мы проверяем, что имя команды соответствует стандартному имени кнопки печати заказа клиента (ПодменюПечатьОбычное_ЗаказКлиента). Если условие выполняется, реквизиту Напечатан нашего документа присваивается значение Истина, после чего документ принудительно записывается в базу данных.
Хотя решение с перехватом команды на форме выглядит простым и рабочим, оно таит в себе серьезные архитектурные проблемы, с которыми столкнется любая реальная торговая организация. Проанализируем эти недостатки подробнее:
ЭтаФорма.Записать() система выдаст ошибку прав доступа. Пользователь просто не сможет распечатать документ, либо признак печати не будет сохранен.Ложь.Как же обойти эти ограничения? Рассмотрим более надежные и профессиональные подходы.
Прежде чем приступать к написанию собственного кода, выясним, нет ли готового решения в самой системе. В современных версиях УТ 11 (начиная с редакции 11.5), разработанных на базе Библиотеки стандартных подсистем (БСП), реализован мощный встроенный механизм слежения за состояниями печатных форм документов.
Для активации этого механизма не требуется программирование. Выполним следующие настройки в пользовательском режиме:
После включения данной опции система начнет автоматически фиксировать состояния документов. При выводе печатной формы на экран или отправке ее непосредственно на принтер система автоматически присвоит заказу статус «Форма напечатана». Это состояние будет наглядно отображаться в списках и журналах документов без необходимости доработки конфигурации.
Если бизнес-требования компании уникальны и стандартный механизм БСП не подходит, лучшим архитектурным решением будет фиксация факта печати в специально созданном **независимом регистре сведений**. Это позволит полностью обойти проблему даты запрета редактирования и избежать нежелательной перезаписи документов.
Разберем по шагам этот метод:
ИсторияПечатиДокументов.Документ (тип: ДокументСсылка.ЗаказКлиента).Напечатан (тип: Булево).ДатаПечати (тип: Дата).Пользователь (тип: СправочникСсылка.Пользователи).Создадим в общем модуле нашего расширения экспортную процедуру для записи факта печати в этот регистр. Для обхода даты запрета редактирования мы задействуем привилегированный режим работы:
Процедура ЗафиксироватьПечатьДокумента(СсылкаНаДокумент) Экспорт
// Включаем привилегированный режим, чтобы обойти ограничения прав и даты запрета
УстановитьПривилегированныйРежим(Истина);
МенеджерЗаписи = РегистрыСведений.ИсторияПечатиДокументов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Документ = СсылкаНаДокумент;
// Заполняем ресурсы записи
МенеджерЗаписи.Напечатан = Истина;
МенеджерЗаписи.ДатаПечати = ТекущаяДата();
МенеджерЗаписи.Пользователь = Пользователи.ТекущийПользователь();
Попытка
МенеджерЗаписи.Записать(Истина); // Параметр Истина означает замещение существующей записи
Исключение
ЗаписьЖурналаРегистрации("ПечатьДокументов.ОшибкаЗаписи",
УровеньЖурналаРегистрации.Ошибка,,,
"Не удалось записать статус печати для документа " + СсылкаНаДокумент + ": " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Теперь нам нужно отобразить этот флаг на форме документа ЗаказКлиента. Для этого добавим на форму реквизит НапечатанФлагНаФорме (тип Булево), разместим его на элементах формы в виде флажка и будем заполнять его при открытии формы:
&НаСервере
Процедура Расш1_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Проверим, что документ уже записан в базу
Если ЗначениеЗаполнено(Объект.Ссылка) Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ИсторияПечати.Напечатан КАК Напечатан
|ИЗ
| РегистрСведений.ИсторияПечатиДокументов КАК ИсторияПечати
|ГДЕ
| ИсторияПечати.Документ = &Документ";
Запрос.УстановитьПараметр("Документ", Объект.Ссылка);
РезультатЗапроса = Запрос.Выполнить();
Если НЕ РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
НапечатанФлагНаФорме = Выборка.Напечатан;
Иначе
НапечатанФлагНаФорме = Ложь;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Использование независимого регистра сведений гарантирует, что сам документ останется нетронутым, не изменится его версия, и он не будет повторно выгружен в другие информационные базы при обмене данными.
Чтобы окончательно решить проблему с групповой печатью документов из списков, логику фиксации печати необходимо перенести с уровня формы на уровень бизнес-логики формирования печатных форм — в модуль менеджера документа.
В типовых конфигурациях 1С печать документов контролируется общим модулем управления печатью БСП. Процесс генерации табличных документов происходит в процедуре Печать модуля менеджера конкретного документа. Перехватив эту процедуру в расширении, мы сможем гарантировать стопроцентное срабатывание механизма регистрации печати.
Создадим расширение для модуля менеджера документа ЗаказКлиента и перехватим процедуру Печать:
&После("Печать")
Процедура Расш1_Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода)
// Проверим, генерируется ли именно макет заказа клиента
Для Каждого СтрокаКоллекции Из КоллекцияПечатныхФорм Цикл
Если СтрокаКоллекции.ИмяМакета = "ЗаказКлиента" Тогда
// Если макет найден, фиксируем печать для всех документов из массива печати
Для Каждого ТекущийДокумент Из МассивОбъектов Цикл
// Проверяем тип на случай, если в процедуру переданы разнородные объекты
Если ТипЗнч(ТекущийДокумент) = Тип("ДокументСсылка.ЗаказКлиента") Тогда
// Вызываем процедуру записи в регистр сведений
ЗафиксироватьПечатьДокумента(ТекущийДокумент);
КонецЕсли;
КонецЦикла;
Прервать; // Выходим из цикла поиска макета
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Проанализируем преимущества этого подхода. Теперь абсолютно неважно, каким образом пользователь решил распечатать документ: открыл ли он форму заказа и нажал кнопку печати, выделил ли группу документов в списке для массовой печати или же запустил печать программным кодом. В любом случае управление передается в процедуру модуля менеджера Печать, которая корректно запишет новые сведения о факте печати в наш независимый регистр.
Подводя итоги, сопоставим рассмотренные варианты реализации задачи: