Почему не удаляются движения документа в процедуре ОбработкаПроведения и как правильно работать с наборами записей?

Программист 1С v8.3 (Обычные формы) 1C:Бухгалтерия Бухгалтерский учет
← На главную

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

Разбор первой проблемы: Почему внешний НаборЗаписей не удаляет движения в ОбработкеПроведения?

Рассмотрим ситуацию: программист внутри процедуры ОбработкаПроведения пытается очистить движения по регистру бухгалтерии, создавая независимый объект НаборЗаписей. Код выглядит примерно так:


Если Кос_БезОборотовпоБУ Тогда
    НаборЗаписей = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
    НаборЗаписей.Отбор.Регистратор.Значение = ЭтотОбъект.Ссылка;
    НаборЗаписей.Отбор.Регистратор.Использование = Истина;
    НаборЗаписей.Прочитать();
    НаборЗаписей.Очистить();
    НаборЗаписей.Записать();
КонецЕсли;

Проанализируем, что происходит на уровне платформы. Когда документ проводится, система открывает транзакцию. В этой транзакции выполняется код процедуры ОбработкаПроведения. В памяти уже существует коллекция ЭтотОбъект.Движения, которая связана с этим документом. Когда вы создаете отдельный НаборЗаписей и вызываете Записать(), вы действительно удаляете записи в таблицах базы данных. Однако, как только выполнение процедуры ОбработкаПроведения завершается, платформа автоматически берет содержимое коллекции ЭтотОбъект.Движения и записывает его в базу данных, заменяя всё, что там было до этого.

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

Правильный способ удаления движений в ОбработкеПроведения

Для того чтобы гарантированно очистить движения по конкретному регистру во время проведения, нам не нужно создавать новые объекты. Мы воспользуемся встроенной коллекцией движений документа. Рассмотрим правильный алгоритм:

  1. Обратимся к коллекции Движения текущего документа.
  2. Очистим нужный регистр методом Очистить().
  3. Установим свойству Записывать значение Истина. Это критически важно: если этот флаг не будет установлен, платформа просто не станет обновлять данные этого регистра в конце процедуры.

Посмотрим на пример правильного кода:


// Очищаем движения по хозрасчетному регистру
Движения.Хозрасчетный.Очистить();
// Сообщаем платформе, что этот набор нужно записать в базу (даже если он пустой)
Движения.Хозрасчетный.Записывать = Истина;

Платформа увидит, что коллекция пуста и флаг записи установлен, и сама удалит все старые записи из базы данных по данному регистратору по окончании транзакции.

Разбор второй проблемы: Почему при добавлении новой записи исчезают старые?

Иногда возникает обратная задача: нужно программно добавить проводку к уже существующим. Типичная ошибка выглядит так: программист получает объект документа, обращается к движениям и просто добавляет новую строку.


Источник = Стр.Ссылка.ПолучитьОбъект();
Проводка = Источник.Движения.Хозрасчетный.Добавить();
// Настройка полей проводки...
Источник.Движения.Хозрасчетный.Записать();

В результате в базе остается только одна эта новая проводка, а все, что были созданы документом ранее, исчезают. Выясним причину этого поведения. По умолчанию при обращении к Источник.Движения.Хозрасчетный коллекция в памяти пуста. Когда вы вызываете Записать(), 1С выполняет запись с замещением (по умолчанию параметр Замещать равен Истина). Платформа стирает все старые записи регистратора и пишет содержимое текущей (почти пустой) коллекции.

Чтобы избежать этой ошибки, необходимо предварительно прочитать существующие движения из базы в память:


Источник = Стр.Ссылка.ПолучитьОбъект();
// Сначала считываем то, что уже есть в базе по этому документу
Источник.Движения.Хозрасчетный.Прочитать(); 
// Теперь добавляем новую запись к существующим
Проводка = Источник.Движения.Хозрасчетный.Добавить();
// Заполняем данные
Проводка.Период = ТекущаяДата();
// ...
// Записываем обновленный набор (старые + новые)
Источник.Движения.Хозрасчетный.Записать();

Дополнительные советы по работе с движениями

Разберем еще несколько нюансов, которые помогут сделать код чище и стабильнее:

  1. Использование метода Установить(): При работе с отборами в наборах записей вместо ручного заполнения полей Значение и Использование лучше применять метод Установить(). Это сокращает код и делает его более читаемым: НаборЗаписей.Отбор.Регистратор.Установить(Ссылка);
  2. Свойство «Запись движений при проведении»: В конфигураторе у документа есть свойство «Запись движений при проведении». Если установлено значение «Записывать выбранные», то будут записаны только те регистры, у которых в коде явно проставлено Движения.ИмяРегистра.Записывать = Истина.
  3. Оптимизация: Старайтесь не вызывать метод Записать() вручную внутри ОбработкаПроведения без крайней необходимости. Платформа делает это эффективнее сама в конце транзакции, оптимизируя блокировки таблиц.

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

← На главную