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