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