В практической работе любой организации часто возникает ситуация, когда пользователи пытаются распечатать документы до их официального проведения в системе. Для таких документов, как Реализация товаров и услуг, печать в непроведенном состоянии несет в себе серьезные экономические и юридические риски. Непроведенный документ не делает движений по регистрам учета, не списывает остатки со складов и не формирует проводки, однако выданная клиенту печатная форма (например, расходная накладная или УПД) может быть использована как подтверждение отгрузки.
В этой статье мы подробно разберем, как установить жесткий запрет или предупреждение при попытке печати непроведенных документов в конфигурации 1С:Бухгалтерия предприятия 3.0 (а также в других решениях на базе БСП, например, 1С:УНФ), используя как классическое изменение кода, так и современный безопасный механизм расширений.
Давайте проанализируем архитектуру печатных форм в современных конфигурациях 1С и найдем наиболее элегантные решения этой задачи.
Прежде чем переходить к написанию кода, давайте разберем, как устроена подсистема печати под капотом. В управляемых формах 1С за формирование команд печати отвечает специальный объект — таблица команд печати, которая инициализируется в модуле менеджера каждого документа в процедуре ДобавитьКомандыПечати(КомандыПечати).
Каждая добавляемая команда описывается как строка таблицы КомандыПечати и обладает набором свойств. Одно из важнейших, но редко используемых свойств — это ПроверкаПроведенияПередПечатью. По умолчанию это свойство имеет значение Ложь, что позволяет свободно выводить печатные формы на экран для любых документов. Если же установить его в значение Истина, то платформа перед выполнением печати автоматически проверит статус документа:
Рассмотрим несколько практических способов реализации этой проверки в системе.
Этот способ подойдет в том случае, если ваша конфигурация уже снята с поддержки или вы сознательно вносите изменения непосредственно в основную конфигурацию. Нам потребуется внести изменения в модуль менеджера документа РеализацияТоваровИУслуг.
Разберем по шагам, как это сделать:
РеализацияТоваровИУслуг, нажмите на него правой кнопкой мыши и выберите Открыть модуль менеджера.ДобавитьКомандыПечати(КомандыПечати).КомандаПечати.ПроверкаПроведенияПередПечатью = Истина;.Давайте посмотрим на пример кода, как будет выглядеть измененная процедура:
Процедура ДобавитьКомандыПечати(КомандыПечати) Экспорт
// Расходная накладная
КомандаПечати = КомандыПечати.Добавить();
КомандаПечати.Идентификатор = "Накладная";
КомандаПечати.Представление = НСтр("ru = 'Расходная накладная'");
КомандаПечати.Обработчик = "УправлениеПечатьюБПКлиент.ВыполнитьКомандуПечати";
КомандаПечати.СписокФорм = "ФормаСписка,ФормаВыбора,ФормаДокументаОбщая,ФормаДокументаТовары";
// Внедряем проверку проведения перед печатью
КомандаПечати.ПроверкаПроведенияПередПечатью = Истина;
// Акт об оказании услуг
КомандаПечати = КомандыПечати.Добавить();
КомандаПечати.Идентификатор = "Акт";
КомандаПечати.Представление = НСтр("ru = 'Акт об оказании услуг'");
КомандаПечати.Обработчик = "УправлениеПечатьюБПКлиент.ВыполнитьКомандуПечати";
КомандаПечати.СписокФорм = "ФормаСписка,ФормаВыбора,ФормаДокументаОбщая,ФормаДокументаУслуги";
// Внедряем проверку проведения перед печатью
КомандаПечати.ПроверкаПроведенияПередПечатью = Истина;
// Универсальный передаточный документ (УПД)
КомандаПечати = КомандыПечати.Добавить();
КомандаПечати.Идентификатор = "УниверсальныйПередаточныйДокумент";
КомандаПечати.Представление = НСтр("ru = 'Универсальный передаточный документ (УПД)'");
КомандаПечати.Обработчик = "УчетНДСКлиент.ВыполнитьКомандуПечатиУниверсальныхПередаточныхДокументов";
// Внедряем проверку проведения перед печатью
КомандаПечати.ПроверкаПроведенияПередПечатью = Истина;
КонецПроцедуры
Такой подход надежно закроет возможность печати документов "в обход" проведения. Однако у него есть существенный минус — при обновлении конфигурации эти изменения могут быть затерты стандартным обновлением поставщика. Чтобы избежать этого, рассмотрим более современный и безопасный способ.
Расширения конфигурации позволяют внедрять собственный код в существующие процедуры без изменения типовой конфигурации. База данных остается на полной поддержке, а процесс обновлений проходит быстро и безболезненно.
Для реализации проверки проведения через расширение выполните следующие действия:
ЗапретПечатиНепроведенных). Назначение расширения укажите как Адаптация.РеализацияТоваровИУслуг (нажмите правой кнопкой мыши на документ в основной конфигурации и выберите "Добавить в расширение").ДобавитьКомандыПечати с директивой выполнения &После.Вместо того чтобы вручную прописывать свойство для каждой команды отдельно (как мы делали в первом способе), мы можем элегантно обойти всю коллекцию уже сформированных команд в цикле и установить нужное свойство для всех команд разом. Проанализируем пример кода:
&После("ДобавитьКомандыПечати")
Процедура ТМ_ДобавитьКомандыПечати(КомандыПечати)
// Перебираем все сформированные типовые команды печати данного документа
Для Каждого ТекущаяКоманда ИЗ КомандыПечати Цикл
// Для реестра документов или специфических справок можно сделать исключение,
// но для основных товарно-сопроводительных документов включаем проверку жестко
Если ТекущаяКоманда.Идентификатор <> "Реестр" Тогда
ТекущаяКоманда.ПроверкаПроведенияПередПечатью = Истина;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Этот код автоматически применит проверку ко всем печатным формам документа "Реализация товаров и услуг", включая расходную накладную, ТОРГ-12, Акт, УПД и счет-фактуру. Ваша типовая конфигурация при этом останется абсолютно чистой!
Что делать, если руководство компании требует запретить печать непроведенных документов абсолютно для всех видов документов в системе (Поступления, Реализации, Перемещения, ПКО, РКО и т.д.)? Прописывать расширение для каждого менеджера документа вручную крайне трудозатратно.
К счастью, в БСП существует централизованная точка сбора всех команд печати. Мы можем использовать общий переопределяемый модуль УправлениеПечатьюПереопределяемый и его процедуру ПередДобавлениемКомандПечати. Этот модуль можно перехватить в нашем расширении.
Давайте посмотрим, как реализовать глобальный запрет:
УправлениеПечатьюПереопределяемый.
&После("ПередДобавлениемКомандПечати")
Процедура ИмяПрефикса_ПередДобавлениемКомандПечати(ИмяФормы, КомандыПечати, СтандартнаяОбработка)
// Данный цикл сработает при открытии любой формы, где формируются команды печати БСП
Для Каждого СтрокаКоманды Из КомандыПечати Цикл
// Устанавливаем проверку проведения для всех команд в системе
СтрокаКоманды.ПроверкаПроведенияПередПечатью = Истина;
КонецЦикла;
КонецПроцедуры
Этот простой шаг позволит централизованно защитить всю базу данных от печати черновиков документов, значительно повысив дисциплину пользователей в системе.
Как мы уже выяснили, стандартное поведение БСП при включенном флаге ПроверкаПроведенияПередПечатью предлагает пользователю провести документ. Но что, если вам нужен бескомпромиссный вариант — "Если документ не проведен, печать полностью заблокирована, кнопка выдает ошибку и проведение на лету запрещено"?
В этом случае нам потребуется перехватить процедуру открытия печатных форм на стороне клиента. Лучше всего сделать это через расширение общего клиентского модуля УправлениеПечатьюСлужебныйКлиент. Разберем пример реализации:
&Перед("ВыполнитьОткрытиеПечатнойФормы")
Процедура ИмяПрефикса_ВыполнитьОткрытиеПечатнойФормы(ИсточникДанных, ИдентификаторКоманды, ОбъектыНазначения, Форма, СтандартнаяОбработка)
Для Каждого ДокументСсылка Из ОбъектыНазначения Цикл
// Проверяем статус проведения документа через стандартный общий модуль
Если Не ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ДокументСсылка, "Проведен") Тогда
// Вызываем исключение, которое прерывает выполнение печати и сообщает пользователю о запрете
Предупреждение = "Внимание! Печать непроведенного документа '" + Строка(ДокументСсылка) + "' строго запрещена политикой безопасности компании!";
ВызватьИсключение Предупреждение;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
При использовании такого кода пользователь не сможет обойти систему и провести документ в процессе отправки на печать — программа выдаст информационное сообщение об ошибке и полностью прекратит операцию печати.
Если вы используете внешнюю печатную форму, подключенную через справочник Дополнительные отчеты и обработки, то изменения в конфигурации или расширении могут не затронуть ее выполнение. Нам нужно прописать это поведение непосредственно внутри самой внешней обработки.
В модуле внешней обработки найдите функцию СведенияОВнешнейОбработке(). При описании параметров команд добавьте новое свойство в таблицу команд:
// Функция возвращает сведения о внешней печатной форме
Функция СведенияОВнешнейОбработке() Экспорт
ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОПараметрахРегистрации();
// ... описание стандартных параметров (Наименование, Версия и т.д.) ...
// Создаем таблицу команд
Команды = ПолучитьТаблицуКоманд();
// Добавляем команду печати
НоваяКоманда = Команды.Добавить();
НоваяКоманда.Представление = "Внешняя расходная накладная";
НоваяКоманда.Идентификатор = "ВнешняяНакладная";
НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипЗапускаВызовСерверногоМетода();
// Явно указываем БСП на необходимость проверки проведения перед печатью внешней формы
НоваяКоманда.Вставить("ПроверкаПроведенияПередПечатью", Истина);
ПараметрыРегистрации.Команды = Команды;
Возврат ПараметрыРегистрации;
КонецФункции
После перезагрузки файла внешней печатной формы в справочнике дополнительных обработок БСП автоматически применит к ней алгоритм контроля проведения перед отправкой на принтер или экран.
Конфигурация 1С:УНФ также построена на современной технологической платформе и использует механизмы БСП. Описанный выше Способ 2 (через Расширение) будет работать там абсолютно идентично для всех новых документов.
Однако в старых релизах УНФ или при использовании сильно кастомизированных, самописных печатных форм, процедура вызова печати может происходить в обход стандартной БСП-команды. В таком случае проверку нужно встраивать прямо в тело функции формирования табличного документа.
Проанализируем пример доработки функции формирования печатной формы в УНФ:
Функция ПечатнаяФорма(МассивОбъектов, ОбъектыПечати) Экспорт
ТабличныйДокумент = Новый ТабличныйДокумент;
ПервыйДокумент = Истина;
Для каждого ТекущийДокумент Из МассивОбъектов Цикл
// Ручная проверка проведения каждого документа из переданного списка
Если Не ТекущийДокумент.Проведен Тогда
// Если документ не проведен, выводим предупреждение на экран
ТекстОшибки = "Документ " + Строка(ТекущийДокумент) + " не проведен! Печать невозможна.";
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстОшибки);
// Переходим к следующему документу или прерываем выполнение
Продолжить;
КонецЕсли;
// ... далее следует стандартный типовой код формирования макета ...
КонецЦикла;
Возврат ТабличныйДокумент;
КонецФункции
Этот способ гарантирует, что даже при вызове печати из нестандартных интерфейсных окон программа сначала проверит статус проведения конкретного объекта базы данных.
Реализуя подобные доработки, обязательно учитывайте архитектурные особенности крупных баз данных:
ПроверкаПроведенияПередПечатью с ролями пользователя. Например, разрешить руководству с полными правами печатать черновики, а обычным менеджерам запретить. Для этого можно использовать конструкцию вида: КомандаПечати.ПроверкаПроведенияПередПечатью = Не РольДоступна("ПолныеПрава");.Мы детально разобрали все доступные и безопасные способы ограничения печати непроведенных документов. Рекомендуем использовать метод создания расширения (Способ 2) как наиболее гибкий и не влияющий на процесс последующих обновлений программы.