Как установить флаг «Напечатан» при печати заказа клиента в УТ 11?

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

В торговых компаниях часто возникает задача контроля за документооборотом. Одной из таких задач является фиксация факта печати документов, например, заказа клиента в конфигурации «1С:Управление торговлей 11» (УТ 11). Это позволяет избежать повторной печати документов менеджерами, контролировать бумажный поток и оперативно отслеживать состояние заказов.

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

Решение 1. Перехват команды печати в форме документа (Быстрый способ)

Рассмотрим вариант реализации, который чаще всего первым приходит в голову начинающим разработчикам. Он заключается в том, чтобы перехватить нажатие кнопки печати непосредственно на форме документа ЗаказКлиента.

Для реализации этого метода нам потребуется создать расширение конфигурации и перехватить процедуру Подключаемый_ВыполнитьКоманду формы документа с помощью аннотации &После.

Выполним следующие шаги для настройки перехвата команды:

  1. Создадим новое расширение конфигурации (или откроем существующее).
  2. Добавим в расширение форму документа ФормаДокумента объекта Документ.ЗаказКлиента.
  3. Найдем процедуру формы Подключаемый_ВыполнитьКоманду(Команда) и добавим ее в расширение с обработчиком После.
  4. Внедрим код, который проверяет имя вызываемой команды печати и устанавливает флаг в реквизите объекта.

Посмотрим на пример программного кода, который реализует эту логику:


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

Разберем, как работает данный код. При нажатии пользователем на кнопку печати срабатывает подключенная команда формы. Мы проверяем, что имя команды соответствует стандартному имени кнопки печати заказа клиента (ПодменюПечатьОбычное_ЗаказКлиента). Если условие выполняется, реквизиту Напечатан нашего документа присваивается значение Истина, после чего документ принудительно записывается в базу данных.

Критический анализ первого решения: В чем его опасность?

Хотя решение с перехватом команды на форме выглядит простым и рабочим, оно таит в себе серьезные архитектурные проблемы, с которыми столкнется любая реальная торговая организация. Проанализируем эти недостатки подробнее:

  1. Проблема даты запрета изменения данных. Представим ситуацию, когда менеджеру понадобилось повторно распечатать заказ клиента, оформленный в прошлом месяце. Если этот период уже закрыт для редактирования (установлена дата запрета изменения данных), то при попытке выполнить код ЭтаФорма.Записать() система выдаст ошибку прав доступа. Пользователь просто не сможет распечатать документ, либо признак печати не будет сохранен.
  2. Избыточное версионирование и планы обмена. Запись самого документа ради изменения одного флага приводит к созданию новой версии объекта в истории изменений (если включено версионирование). Кроме того, модифицированный документ будет зарегистрирован на узлах планов обмена и при следующей синхронизации отправится, например, в программу «1С:Бухгалтерия», создавая лишнюю нагрузку на каналы связи и базу данных.
  3. Игнорирование групповой печати. Если пользователь выделит в списке заказов несколько документов, нажмет правую кнопку мыши и выберет команду «Печать», то вывод на экран печатных форм произойдет без открытия самих форм документов. Наш код, написанный внутри конкретной формы документа, не сработает, и флаги напечатанных заказов останутся в значении Ложь.

Как же обойти эти ограничения? Рассмотрим более надежные и профессиональные подходы.

Решение 2. Использование типового механизма БСП «Отслеживание состояний оригиналов»

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

Для активации этого механизма не требуется программирование. Выполним следующие настройки в пользовательском режиме:

  1. Перейдем в раздел меню НСИ и администрирование, далее выберем пункт Печатные формы, отчеты и обработки.
  2. Найдем и включим опцию «Отслеживание состояний напечатанных документов» (или «Состояния оригиналов первичных документов» в зависимости от релиза конфигурации).
  3. В настройках состояний укажем, для каких именно типов документов (в нашем случае — «Заказ клиента») требуется вести учет.

После включения данной опции система начнет автоматически фиксировать состояния документов. При выводе печатной формы на экран или отправке ее непосредственно на принтер система автоматически присвоит заказу статус «Форма напечатана». Это состояние будет наглядно отображаться в списках и журналах документов без необходимости доработки конфигурации.

Решение 3. Использование независимого регистра сведений

Если бизнес-требования компании уникальны и стандартный механизм БСП не подходит, лучшим архитектурным решением будет фиксация факта печати в специально созданном **независимом регистре сведений**. Это позволит полностью обойти проблему даты запрета редактирования и избежать нежелательной перезаписи документов.

Разберем по шагам этот метод:

  1. В нашем расширении конфигурации создадим новый независимый регистр сведений с именем ИсторияПечатиДокументов.
  2. Зададим следующие характеристики регистра:
    • Режим записи: Независимый.
    • Измерение: Документ (тип: ДокументСсылка.ЗаказКлиента).
    • Ресурс: Напечатан (тип: Булево).
    • Ресурс: ДатаПечати (тип: Дата).
    • Ресурс: Пользователь (тип: СправочникСсылка.Пользователи).

Создадим в общем модуле нашего расширения экспортную процедуру для записи факта печати в этот регистр. Для обхода даты запрета редактирования мы задействуем привилегированный режим работы:


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

Теперь нам нужно отобразить этот флаг на форме документа ЗаказКлиента. Для этого добавим на форму реквизит НапечатанФлагНаФорме (тип Булево), разместим его на элементах формы в виде флажка и будем заполнять его при открытии формы:


&НаСервере
Процедура Расш1_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Проверим, что документ уже записан в базу
    Если ЗначениеЗаполнено(Объект.Ссылка) Тогда
        
        Запрос = Новый Запрос;
        Запрос.Текст = 
            "ВЫБРАТЬ
            |	ИсторияПечати.Напечатан КАК Напечатан
            |ИЗ
            |	РегистрСведений.ИсторияПечатиДокументов КАК ИсторияПечати
            |ГДЕ
            |	ИсторияПечати.Документ = &Документ";
        
        Запрос.УстановитьПараметр("Документ", Объект.Ссылка);
        РезультатЗапроса = Запрос.Выполнить();
        
        Если НЕ РезультатЗапроса.Пустой() Тогда
            Выборка = РезультатЗапроса.Выбрать();
            Выборка.Следующий();
            НапечатанФлагНаФорме = Выборка.Напечатан;
        Иначе
            НапечатанФлагНаФорме = Ложь;
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Использование независимого регистра сведений гарантирует, что сам документ останется нетронутым, не изменится его версия, и он не будет повторно выгружен в другие информационные базы при обмене данными.

Решение 4. Перехват события печати в модуле менеджера (Поддержка групповой печати)

Чтобы окончательно решить проблему с групповой печатью документов из списков, логику фиксации печати необходимо перенести с уровня формы на уровень бизнес-логики формирования печатных форм — в модуль менеджера документа.

В типовых конфигурациях 1С печать документов контролируется общим модулем управления печатью БСП. Процесс генерации табличных документов происходит в процедуре Печать модуля менеджера конкретного документа. Перехватив эту процедуру в расширении, мы сможем гарантировать стопроцентное срабатывание механизма регистрации печати.

Создадим расширение для модуля менеджера документа ЗаказКлиента и перехватим процедуру Печать:


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

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

Резюме и рекомендации разработчику

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

← На главную