В процессе работы торгового предприятия часто возникает необходимость контроля за тем, сколько раз была распечатана накладная или любой другой первичный документ. Это критически важно для предотвращения дублирования продаж "мимо кассы" или изменения данных в уже выданных клиенту документах. В конфигурации 1С:Управление торговлей 10.3 (на платформе 8.2/8.3 с обычными формами) стандартного счетчика печати нет, поэтому разберем подробно, как реализовать этот функционал самостоятельно.
Рассмотрим комплексный подход к решению задачи: от создания структуры хранения данных до вывода информации в форму списка и защиты от махинаций.
Просто добавлять реквизит в сам документ — не самое лучшее решение с точки зрения производительности и чистоты архитектуры. Проанализируем ситуацию: нам нужно знать не только количество, но, желательно, и кто именно печатал документ. Поэтому создадим новый Регистр сведений.
ИсторияПечатиДокументов.Объект (Тип: ДокументСсылка.РеализацияТоваровУслуг).Пользователь (Тип: СправочникСсылка.Пользователи).Количество (Тип: Число(10, 0)).ДатаПоследнейПечати (Тип: Дата).Такая структура позволит нам не только выводить общее число копий, но и видеть историю в разрезе сотрудников.
Выясним причину, по которой стандартные методы могут не подойти. В 1С 8.2 печать обычно инициируется из модуля менеджера или модуля объекта в процедуре Печать(). Нам необходимо вклиниться в этот процесс. Разберем код, который будет увеличивать счетчик при каждом вызове команды печати.
В модуле объекта или менеджера документа (в зависимости от того, где описана процедура формирования печатной формы) добавим следующий фрагмент:
Процедура ЗафиксироватьПечать(ТекущийДокумент)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ИсторияПечатиДокументов.Количество
|ИЗ
| РегистрСведений.ИсторияПечатиДокументов КАК ИсторияПечатиДокументов
|ГДЕ
| ИсторияПечатиДокументов.Объект = &Объект";
Запрос.УстановитьПараметр("Объект", ТекущийДокумент);
Выборка = Запрос.Выполнить().Выбрать();
МенеджерЗаписи = РегистрыСведений.ИсторияПечатиДокументов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Объект = ТекущийДокумент;
МенеджерЗаписи.Пользователь = ПараметрыСеанса.ТекущийПользователь;
Если Выборка.Следующий() Тогда
МенеджерЗаписи.Количество = Выборка.Количество + 1;
Иначе
МенеджерЗаписи.Количество = 1;
КонецЕсли;
МенеджерЗаписи.ДатаПоследнейПечати = ТекущаяДата();
МенеджерЗаписи.Записать();
КонецПроцедуры
Эту процедуру следует вызывать в основном цикле формирования печатных форм. Важный момент: вызывайте фиксацию только тогда, когда табличный документ успешно сформирован и отправлен пользователю.
Теперь разберем, как вывести эти данные в форму списка документа "Реализация товаров и услуг". Поскольку мы используем обычные формы, нам понадобится событие ПриВыводеСтроки или ПриПолученииДанных. Использование ПриПолученииДанных предпочтительнее для производительности, так как оно позволяет получить данные сразу для всех видимых строк одним запросом.
Проанализируем пример реализации в модуле формы списка:
Процедура СписокПриПолученииДанных(Элемент, ОформленияСтрок)
// Подготовим список ссылок на документы в текущей видимости
СписокСсылок = Новый СписокЗначений;
Для Каждого ОформлениеИз ОформленияСтрок Цикл
СписокСсылок.Добавить(ОформлениеИз.ДанныеСтроки.Ссылка);
КонецЦикла;
// Получаем данные из нашего регистра
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ИсторияПечати.Объект КАК Ссылка,
| СУММА(ИсторияПечати.Количество) КАК ВсегоПечатей
|ИЗ
| РегистрСведений.ИсторияПечатиДокументов КАК ИсторияПечати
|ГДЕ
| ИсторияПечати.Объект В(&СписокСсылок)
|СГРУППИРОВАТЬ ПО
| ИсторияПечати.Объект";
Запрос.УстановитьПараметр("СписокСсылок", СписокСсылок);
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
// Заполняем колонку "Кол-во печатей"
Для Каждого ОформлениеИз ОформленияСтрок Цикл
СтрокаДанных = РезультатЗапроса.Найти(ОформлениеИз.ДанныеСтроки.Ссылка, "Ссылка");
Если СтрокаДанных <> Неопределено Тогда
ОформлениеИз.Ячейки.КоличествоПечатей.УстановитьТекст(СтрокаДанных.ВсегоПечатей);
// Если документ печатался более одного раза, подсветим его
Если СтрокаДанных.ВсегоПечатей > 1 Тогда
ОформлениеИз.Ячейки.КоличествоПечатей.ЦветФона = ЦветаСтиля.ЦветОсобогоТекста;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Не забудьте предварительно добавить в табличное поле формы новую колонку с именем КоличествоПечатей и отключить у нее связь с данными (DataPath), так как мы заполняем ее программно.
Как справедливо заметили участники обсуждения, сам по себе счетчик легко обмануть (например, распечатав документ из Excel или сделав ксерокопию). Посмотрим на способы защиты, которые сделают систему учета более надежной:
ID документа + Порядковый номер печати. При приемке товара на складе кладовщик сможет сразу увидеть, актуальный ли это экземпляр.Выясним, как предотвратить обход счетчика через сохранение в сторонние форматы. В коде формирования печатной формы перед выводом на экран установите следующие свойства ТабличногоДокумента:
ТабДок.ТолькоПросмотр = Истина;
ТабДок.Защита = Истина;
// Запрещаем копирование ячеек в буфер обмена
Также рекомендуется ограничить пользователям право "Вывод" в ролях, что закроет возможность использования команды "Файл - Сохранить как".
Мы рассмотрели, как реализовать механизм контроля печати в 1С 8.2. Основная сложность заключается не в создании колонки, а в обеспечении достоверности данных. Использование независимого регистра сведений в сочетании с событиями формы списка и программными защитами макета позволяет создать надежную систему аудита, которая значительно снизит риски махинаций на предприятии.