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