В процессе разработки в среде 1С:Предприятие 8.3 часто возникает задача контроля за бумажным документооборотом. Одной из таких задач является фиксация факта печати документа: кто, когда и сколько раз выводил форму на экран или принтер. Это необходимо для того, чтобы на самом печатном листе отображался номер версии (например, «Версия печати №5»), что позволяет отличить актуальный документ от устаревших копий.
В этой статье мы подробно разберем несколько подходов к реализации этой задачи — от простых манипуляций с формой до профессиональной архитектуры с использованием модулей менеджера и регистров сведений.
Рассмотрим стандартную ситуацию: в конфигурации есть документ, и нам нужно при каждом нажатии на кнопку Печать выполнять следующие действия:
Разберем, почему стандартное событие ПередЗаписью здесь не подходит. Печать может производиться многократно без изменения данных самого документа. Если мы будем пытаться записывать данные о печати только при сохранении документа, мы потеряем историю промежуточных вызовов печатных форм.
Проанализируем архитектуру современных конфигураций. Правильнее всего размещать код формирования печатной формы в модуле менеджера объекта. Это позволяет вызывать печать не только из формы документа, но и из списка документов или из внешних обработок.
Рассмотрим пример кода в модуле менеджера, где мы будем не только формировать табличный документ, но и фиксировать факт обращения к нему:
Процедура Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
Для Каждого СсылкаИзМассива Из МассивОбъектов Цикл
// 1. Фиксируем факт печати в базе данных
ЗафиксироватьВерсиюПечати(СсылкаИзМассива);
// 2. Формируем макет
ТабДок = СформироватьМакетСДанными(СсылкаИзМассива);
// 3. Добавляем результат в коллекцию
УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(КоллекцияПечатныхФорм, "НазваниеМакета", "Заголовок", ТабДок);
КонецЦикла;
КонецПроцедуры
Метод ЗафиксироватьВерсиюПечати должен быть реализован либо внутри модуля менеджера, либо в общем модуле. Выясним, где лучше хранить эти данные.
Существует два основных способа хранения истории печати:
Способ А. Табличная часть документа.
Это кажется простым решением: создать ТЧ ИсторияПечати с колонками НомерВерсии, Пользователь, Дата. Однако у этого метода есть существенный недостаток: при каждой печати объект документа будет модифицироваться и записываться. Это приведет к:
Способ Б. Регистр сведений (Профессиональный).
Создадим непериодический регистр сведений ИсторияПечатиДокументов со следующей структурой:
Объект (Тип: ДокументСсылка), НомерПорядковый (Тип: Число).Пользователь, ДатаПечати.Разберем пример процедуры записи в такой регистр:
Процедура ЗафиксироватьВерсиюПечати(СсылкаНаДокумент)
// Определяем следующий номер версии
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ МАКСИМУМ(ИсторияПечати.НомерПорядковый) КАК МаксНомер
|ИЗ РегистрСведений.ИсторияПечатиДокументов КАК ИсторияПечати
|ГДЕ ИсторияПечати.Объект = &Объект";
Запрос.УстановитьПараметр("Объект", СсылкаНаДокумент);
Результат = Запрос.Выполнить().Выгрузить();
НовыйНомер = ?(Результат.Количество() > 0, Результат[0].МаксНомер + 1, 1);
// Записываем данные
МенеджерЗаписи = РегистрыСведений.ИсторияПечатиДокументов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Объект = СсылкаНаДокумент;
МенеджерЗаписи.НомерПорядковый = НовыйНомер;
МенеджерЗаписи.Пользователь = ПараметрыСеанса.ТекущийПользователь;
МенеджерЗаписи.ДатаПечати = ТекущаяДата();
МенеджерЗаписи.Записать();
// Оповещаем систему об изменении данных объекта
ОповеститьОбИзменении(СсылкаНаДокумент);
КонецПроцедуры
Одна из проблем, с которой сталкиваются новички: после нажатия на кнопку Печать данные в базе обновились (счетчик увеличился), но на самой открытой форме документа пользователь по-прежнему видит старое значение (например, «Версия 4» вместо «Версия 5»).
Для решения этой задачи проанализируем механизм оповещений в 1С. После записи в регистр или ТЧ на сервере, клиентское приложение должно узнать, что данные изменились. Рассмотрим пошагово:
ОповеститьОбИзменении(Ссылка).ОбработкаОповещения.
&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
Если ИмяСобытия = "Запись_ИсторияПечати" И Параметр = Объект.Ссылка Тогда
// Перечитываем данные с сервера, чтобы обновить форму
Прочитать();
КонецЕсли;
КонецПроцедуры
Важно понимать техническое ограничение платформы 1С. Метод ТабДок.Показать() открывает окно предварительного просмотра. Пользователь может закрыть его, не отправляя документ на принтер, но счетчик в нашей реализации уже сработает. Платформа не предоставляет гарантированного обратного события от драйвера принтера «Документ успешно напечатан на бумаге».
Поэтому мы фиксируем именно факт формирования версии для печати. Рассмотрим, как сделать это более строго, используя Библиотеку стандартных подсистем (БСП). В БСП команда печати обычно вызывает процедуру в модуле менеджера. Чтобы интеграция была корректной, лучше всего встраивать логику логирования в момент подготовки табличного документа, непосредственно перед тем, как он будет возвращен в форму печати.
Для продвинутых систем учета рекомендуется при каждой печати генерировать уникальный идентификатор. Разберем ситуацию: вы напечатали документ дважды с интервалом в минуту. Оба листа выглядят одинаково. Как их отличить?
Проанализируем решение: в регистр сведений можно записывать GUID (уникальный идентификатор) каждой конкретной распечатки. Этот GUID выводится на макет в виде штрихкода. В будущем, сканируя штрихкод на бумаге, система точно скажет: «Это была распечатка от 12:05 пользователем Ивановым, она является 3-й по счету».
Таким образом, мы реализовали надежную систему фиксации действий пользователя, которая позволяет прозрачно контролировать выпуск печатных форм в организации.