Разработчики часто сталкиваются с ситуацией, когда в подписке на событие ОбработкаПроведения коллекция движений документа (например, Источник.Движения.ЖурналПроводокЕПСБУ) оказывается пустой либо содержит старые записи, существовавшие до текущего проведения. Попытки прочитать движения запросом к базе данных или через метод Прочитать() набора записей также не приносят результата.
В этой статье мы подробно разберем, почему возникает данная проблема, как правильно получать движения документа в памяти в момент проведения и как обойти специфические механизмы очистки проводок в конфигурациях типа БГУ 2.0.
Для начала проанализируем основные причины, по которым движения могут отсутствовать в обработчике подписки:
ОбработкаПроведения (включая все назначенные на него подписки) выполняется внутри транзакции проведения. Физически в СУБД новые записи еще не записаны под своим окончательным статусом. Попытка прочитать их через запрос вернет либо пустоту (если документ проводится впервые), либо старые проводки.Источник.Движения.ИмяРегистра.Прочитать() в процессе проведения принудительно заменяет данные в оперативной памяти данными из базы данных. Так как транзакция проведения еще не зафиксирована, платформа затирает вновь подготовленные движения в памяти пустой или старой информацией из БД.Чтобы прочитать проводки, которые документ подготовил к записи, нельзя обращаться к базе данных или считывать набор заново. Данные уже сформированы в памяти и находятся непосредственно в объекте документа. Чтобы получить их, мы должны использовать метод Выгрузить().
Рассмотрим пример кода в подписке на событие:
// Получаем движения, сформированные в оперативной памяти
ТаблицаПроводок = Источник.Движения.ЖурналПроводокЕПСБУ.Выгрузить();
// Теперь мы можем обойти таблицу значений и проанализировать проводки
Для Каждого СтрокаПроводки Из ТаблицаПроводок Цикл
// Например, проверяем счета или субконто
Если СтрокаПроводки.СчетДт = ПланыСчетов.ЕПСБУ.ПродуктыПитания Тогда
// Выполняем необходимую логику
КонецЕсли;
КонецЦикла;
Метод Выгрузить() позволяет безопасно скопировать текущее состояние набора записей регистра в таблицу значений без обращения к СУБД и без риска затереть кэш транзакции.
Если вы работаете в БГУ 2.0 и ваши программно созданные движения очищаются общим модулем проведения БГУ, необходимо сообщить системе, что проведение выполняется в ручном режиме (как бухгалтерская операция). Это делается путем добавления специального флага в структуру дополнительных свойств источника.
Добавим в код формирования движений или непосредственно в начало обработчика подписки следующий блок:
// Предотвращаем автоматическую очистку движений механизмами БГУ 2.0
Если Не Источник.ДополнительныеСвойства.Свойство("ДанныеАвтопроведения") Тогда
Источник.ДополнительныеСвойства.Вставить("ДанныеАвтопроведения", Новый Структура("ЭтоБухоперация", Истина));
Иначе
Источник.ДополнительныеСвойства.ДанныеАвтопроведения.ЭтоБухоперация = Истина;
КонецЕсли;
После установки этого свойства система БГУ поймет, что движения не требуют проверки на соответствие типовой операции, и позволит успешно сохранить и прочитать их.
Если вашей целью является не просто чтение проводок, а их модификация (например, заполнение служебных субконто, корректировка сумм или создание записей в сопутствующих регистрах), подписка на ОбработкаПроведения документа — не самое лучшее место.
Гораздо надежнее и правильнее использовать подписку на событие ПередЗаписью набора записей самого регистра (в данном случае РегистрБухгалтерииНаборЗаписей.ЖурналПроводокЕПСБУ).
Разберем преимущества этого подхода:
Источник в обработчик передается сам набор записей регистра.Пример кода для обработчика подписки на событие ПередЗаписью регистра бухгалтерии:
Процедура ПередЗаписьюРегистраБухгалтерииПередЗаписью(Источник, Отказ, Замещение) Экспорт
// Получаем ссылку на документ-регистратор
Регистратор = Источник.Отбор.Регистратор.Значение;
// Проверяем тип документа, если обработка нужна только для конкретного вида
Если ТипЗнч(Регистратор) = Тип("ДокументСсылка.ПоступлениеМЗ") Тогда
// Анализируем и модифицируем проводки напрямую в источнике
Для Каждого Запись Из Источник Цикл
// Пример модификации субконто
// Запись.СубконтоДт[ПараметрСубконто] = Значение;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Используя этот подход, вы избавитесь от необходимости контролировать порядок выполнения подписок документа и гарантированно получите доступ к актуальным проводкам перед их физической записью в базу данных.