Как получить старые движения документа при его перепроведении в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки в системе 1С:Предприятие 8 часто возникает задача анализа изменений, которые вносит документ в учет. Например, нам может потребоваться узнать, какие остатки были списаны в прошлый раз, чтобы корректно пересчитать их при текущем проведении, или отправить уведомление, если сумма в движениях существенно изменилась. В этой статье мы подробно разберем механизмы работы платформы с регистрами и выясним, в какой момент удаляются движения и как их «перехватить» до того, как они исчезнут из базы данных.

Анализируем свойство Удалять движения

Прежде всего, нам необходимо разобраться с настройкой самого объекта метаданных. У каждого документа в 1С есть свойство Удалять движения. Оно имеет три значения, два из которых критически важны для нашей задачи:

  1. Удалять автоматически: При такой настройке платформа самостоятельно очищает все движения документа в самом начале транзакции записи (до того, как управление передается в процедуру ПередЗаписью модуля документа). Если мы попробуем выполнить запрос к таблицам регистров внутри модуля документа, мы получим пустой результат — старых данных в базе уже нет.
  2. Не удалять автоматически: В этом случае движения остаются в базе данных. Они будут либо перезаписаны новыми наборами в процессе выполнения кода проведения, либо удалены явным программным вызовом. Это именно тот режим, который чаще всего используется в типовых конфигурациях, таких как 1С:Бухгалтерия 3.0 или 1С:ERP.

Рассмотрим ситуацию, когда установлено значение Не удалять автоматически. В этом режиме мы получаем полный контроль над процессом, но и берем на себя ответственность за корректную очистку данных.

Метод Прочитать() как способ получения текущих данных

Разберем самый простой и надежный способ получения «старых» движений непосредственно в модуле документа. Коллекция Движения объекта содержит наборы записей всех регистров, по которым документ может делать записи. По умолчанию эти наборы в памяти пусты (если мы их еще не заполняли в коде).

Для того чтобы загрузить в память то, что в данный момент записано в базе данных под этим регистратором, мы можем использовать метод Прочитать(). Рассмотрим пример кода в процедуре ОбработкаПроведения:


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    // Читаем старые движения из базы в память
    Движения.Хозрасчетный.Прочитать();
    
    // Теперь в коллекции Движения.Хозрасчетный находятся записи предыдущего проведения
    Для Каждого Запись Из Движения.Хозрасчетный Цикл
        // Проводим анализ старых данных
        Сообщить("Старая запись по счету: " + Запись.Счет);
    КонецЦикла;
    
    // После анализа необходимо очистить набор, чтобы подготовить его к новым записям
    Движения.Хозрасчетный.Очистить();
    
    // Далее следует стандартный алгоритм формирования новых движений
    // ...
    
КонецПроцедуры

Важно помнить: если вы вызвали Прочитать(), а затем добавили новые записи в этот же набор без вызова Очистить(), то при записи набора 1С попытается объединить старые и новые записи (если не установлен флаг Записывать = Истина для всего набора сразу после очистки).

Перехват движений в модуле набора записей

Проанализируем ситуацию, когда нам нужно отловить изменения движений глобально, вне зависимости от того, какой именно документ их породил. Для этого идеально подходит модуль набора записей регистра (или подписки на события набора записей).

В модуле набора записей существуют два ключевых события:

Посмотрим на пример реализации в модуле набора записей регистра накопления:


Процедура ПередЗаписью(Отказ, Замещение)
    
    // Если Замещение = Истина, значит старые записи будут удалены
    Если Замещение Тогда
        Запрос = Новый Запрос;
        Запрос.Текст = 
            "ВЫБРАТЬ * ИЗ РегистрНакопления.ОстаткиНоменклатуры ГДЕ Регистратор = &Регистратор";
        Запрос.УстановитьПараметр("Регистратор", Отбор.Регистратор.Значение);
        
        СтарыеДвижения = Запрос.Выполнить().Выгрузить();
        // Теперь в таблице СтарыеДвижения у нас есть данные до перезаписи
    КонецЕсли;
    
КонецПроцедуры

Почему ERP и другие современные системы сравнивают движения

Выясним причину, по которой в конфигурациях уровня 1С:ERP 2 или Комплексная автоматизация реализованы сложные механизмы сравнения движений. В сообщении форума упоминается, что типовые решения часто проверяют, изменилось ли что-то в движениях по сравнению с предыдущим разом.

Это делается для оптимизации производительности. Процесс записи данных в базу — это «дорогая» операция, вызывающая блокировки и рост лога транзакций. Если алгоритм проведения сформировал точно такие же записи, какие уже лежат в базе, система принимает решение не записывать их заново. Это предотвращает каскадные обновления итогов и не запускает лишние триггеры в цепочках актуализации (например, пересчет себестоимости или партионного учета).

Алгоритм «умной» записи обычно выглядит так:

  1. Выгрузка старых движений из базы в таблицу (через Прочитать() или запрос).
  2. Формирование новых движений в отдельной таблице значений.
  3. Сравнение двух таблиц (обычно с помощью объекта СравнениеЗначений или через временные таблицы в запросе).
  4. Установка флага Движения.ИмяРегистра.Записывать = Истина только в том случае, если обнаружены расхождения.

Использование инструментов БСП

Если ваша конфигурация построена на базе БСП (Библиотеки Стандартных Подсистем), рекомендуется использовать штатные функции для управления очисткой движений. В частности, часто применяется метод ОбщегоНазначения.УдалитьДвиженияРегистратора().

Этот метод берет на себя рутинную работу по очистке наборов записей, учитывая специфику режима проведения и настройки блокировок. Проанализируем пример использования:


ОбщегоНазначения.УдалитьДвиженияРегистратора(ЭтотОбъект, Отказ, Истина, РежимПроведения);

Здесь параметр Истина указывает на то, что необходимо выполнить удаление старых записей. Это гарантирует, что к моменту формирования новых проводок база будет очищена, а вы сможете избежать «зависания» лишних записей, если логика проведения вдруг изменилась и документ перестал делать записи по какому-то из регистров.

Резюме

Мы рассмотрели различные подходы к работе со старыми движениями. Подведем итоги:

← На главную