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