При доработке типовых конфигураций на платформе 1С:Предприятие 8, и в частности в «Бухгалтерии предприятия 3.0», разработчики часто сталкиваются с задачей изменения движений документа. Нередко попытки вмешаться в процесс проведения через расширения приводят к тому, что изменения, сделанные в коде, не сохраняются в базе данных. Давайте разберем эту ситуацию по шагам и выясним, почему так происходит и как сделать работу с движениями корректной.
Первый вопрос, который возникает у разработчика — где хранить признак необходимости «особого» поведения документа? Самый правильный архитектурный подход — добавление реквизита непосредственно в объект документа. Почему не реквизит формы? Реквизит формы существует только в контексте интерактивной работы пользователя. Если документ будет проводиться в фоновом режиме, при групповом перепроведении или через обмен данными, код не увидит реквизит формы, и логика не сработает. Добавив реквизит в документ, мы обеспечиваем доступность значения в любом контексте выполнения.
Представим, что мы используем расширение и хотим изменить движения после того, как типовой алгоритм ОбработкаПроведения уже отработал. Мы пишем код, обращаемся к Движения.Хозрасчетный, удаляем записи, меняем суммы, вызываем Движения.Записать(), но в итоге в базе ничего не меняется. В чем причина?
Причина кроется во внутреннем механизме работы платформы 1С с наборами записей регистров. У каждого набора записей есть свойство Записывать. В типовой конфигурации в конце процедуры ОбработкаПроведения система принудительно вызывает метод Движения.Записать(). После того как платформа успешно записала данные в таблицу регистра, она автоматически устанавливает свойство Записывать в значение Ложь для всех наборов записей, чтобы избежать дублирующих записей.
Когда срабатывает наше расширение с аннотацией &После, процедура ОбработкаПроведения уже выполнила запись и сбросила флаг Записывать. Поэтому, даже если мы меняем данные в памяти и вызываем Движения.Записать(), платформа видит, что у набора Хозрасчетный флаг записи стоит Ложь, и просто игнорирует попытку записи.
Чтобы изменения вступили в силу при использовании аннотации &После, необходимо явно сообщить системе, что набор записей нужно сохранить. Для этого перед внесением изменений в данные мы должны принудительно выставить свойство Записывать в состояние Истина.
Разберем пример кода, который позволит нам успешно скорректировать движения:
&После("ОбработкаПроведения")
Процедура РасшАО_ОбработкаПроведения(Отказ, РежимПроведения)
Если ЭтотОбъект.РасшАО_В20 Тогда
// Принудительно включаем возможность записи для набора Хозрасчетный
Движения.Хозрасчетный.Записывать = Истина;
// Выполняем необходимые манипуляции с движениями
Сумма1 = Движения.Хозрасчетный[0].Сумма;
Сумма2 = Движения.Хозрасчетный[1].Сумма;
Движения.Хозрасчетный[0].Сумма = Сумма1 + Сумма2;
Движения.Хозрасчетный.Удалить(1);
Движения.Хозрасчетный.Удалить(2);
КонецЕсли;
КонецПроцедуры
После установки Движения.Хозрасчетный.Записывать = Истина платформа при завершении работы процедуры поймет, что набор записей был изменен и его необходимо сохранить в базе данных. Вызывать Движения.Записать() вручную в данном случае уже не обязательно, так как система сделает это самостоятельно в штатном режиме.
Хотя решение с &После работает, при профессиональной разработке стоит учитывать следующие моменты:
&После могут входить в конфликт с другими механизмами типовой конфигурации, особенно если у документа много подписок на события.ПередЗаписью в модуле набора записей регистра Хозрасчетный. В этом случае вы перехватываете данные непосредственно перед тем, как они попадут в базу данных, и вам не нужно заботиться о флагах записи самого документа.ОбработкаПроведения, помните, что порядок выполнения процедур имеет критическое значение.Используя предложенный подход с установкой флага Записывать, вы сможете гибко управлять движениями документов, сохраняя при этом целостность логики работы учетной системы 1С.