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