Как очистить записи регистра накопления по условию при проведении документа

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

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

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

Прежде чем приступать к написанию кода в процедуре ОбработкаПроведения, нам необходимо проанализировать настройки самого объекта конфигурации. Поведение системы при проведении документа во многом определяется свойством «Удаление движений» (вкладка «Логические»).

Разберем два варианта настройки:

  1. Автоматическое удаление: Если установлено значение «Автоматически», платформа очищает все записи документа в регистрах еще до входа в процедуру проведения. В этом случае задача «очистить только часть старых записей» невыполнима стандартными средствами внутри ОбработкаПроведения, так как на момент выполнения кода записей в базе уже нет.
  2. Не удалять автоматически: Чтобы реализовать логику сохранения части старых движений, мы должны установить это свойство в значение «Не удалять автоматически» (или «Удалять при отмене проведения»). Это позволит нам программно прочитать текущее состояние регистра в базе, отфильтровать нужные строки и дозаписать новые.

Важно: Выбирая режим «Не удалять автоматически», мы берем на себя полную ответственность за актуальность движений. Если мы забудем очистить ненужные записи, в системе могут возникнуть «фантомные» остатки.

Реализация через таблицу значений (оптимальный способ)

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

1. Прочитаем существующий набор записей регистра для данного документа.

2. Выгрузим его в таблицу значений.

3. Удалим из таблицы те строки, которые подлежат обновлению (по нашему условию).

4. Загрузим оставшиеся строки обратно в коллекцию движений.

Посмотрим на пример кода, реализующего этот подход:


// В процедуре ОбработкаПроведения
// 1. Читаем текущие движения из базы данных
Движения.МойРегистрНакопления.Прочитать();

// 2. Выгружаем движения в таблицу значений
ТаблицаДвижений = Движения.МойРегистрНакопления.Выгрузить();

// 3. Отбираем строки, которые нужно ОСТАВИТЬ (например, ФлагВыставлен = Истина)
МассивСтрокДляУдаления = Новый Массив;
Для Каждого СтрокаДвижения Из ТаблицаДвижений Цикл
    Если СтрокаДвижения.ФлагВыставлен = Ложь Тогда
        МассивСтрокДляУдаления.Добавить(СтрокаДвижения);
    КонецЕсли;
КонецЦикла;

// Удаляем ненужные строки из ТЗ
Для Каждого СтрокаДляУдаления Из МассивСтрокДляУдаления Цикл
    ТаблицаДвижений.Удалить(СтрокаДляУдаления);
КонецЦикла;

// 4. Очищаем коллекцию в памяти и загружаем отфильтрованные данные
Движения.МойРегистрНакопления.Очистить();
Движения.МойРегистрНакопления.Загрузить(ТаблицаДвижений);

// 5. Устанавливаем флаг записи, чтобы платформа сохранила результат
Движения.МойРегистрНакопления.Записывать = Истина;

Этот метод хорош тем, что мы минимизируем количество транзакций и обращений к базе данных, работая с данными в оперативной памяти.

Разбор типичной ошибки при удалении в цикле

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


// ОШИБОЧНЫЙ ПРИМЕР
Для Каждого Запись Из Движения.МойРегистрНакопления Цикл
    Если Запись.ФлагВыставлен = Ложь Тогда    
        Движения.МойРегистрНакопления.Удалить(Запись); // ОШИБКА: индексы сместятся!
    КонецЕсли;
КонецЦикла;

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

Как сделать правильно, если вы всё же хотите использовать цикл? Нужно выполнять обход с конца в начало. Разберем этот пример:


КоличествоЗаписей = Движения.МойРегистрНакопления.Количество();

// Обходим коллекцию с последнего индекса до нуля
Для Счетчик = 1 По КоличествоЗаписей Цикл
    Индекс = КоличествоЗаписей - Счетчик;
    Запись = Движения.МойРегистрНакопления[Индекс];
    
    Если Запись.ФлагВыставлен = Ложь Тогда
        Движения.МойРегистрНакопления.Удалить(Индекс);
    КонецЕсли;
КонецЦикла;

Такой подход гарантирует, что смещение индексов не повлияет на еще не обработанные элементы.

Управление записью набора: Производительность и Блокировки

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

Рассмотрим правила эффективной записи:

Альтернативный подход: Использование «Разделителя итогов» и бизнес-логики

Если задача стоит в «заморозке» определенных данных, стоит подумать, является ли регистр накопления лучшим местом для этого. Иногда эффективнее разделить данные на два регистра:

  1. Оперативный регистр: в него пишутся движения, которые могут меняться при перепроведении.
  2. Регистр защищенных данных: сюда записи переносятся только тогда, когда ФлагВыставлен принимает значение Истина.

Это полностью исключает риск случайного удаления важных данных при технических сбоях или ошибках в коде перепроведения.

Резюме

Для реализации очистки движений с условием в 1С 8.3:

  1. Убедитесь, что свойство документа «Удаление движений» позволяет вам видеть старые записи (установите «Не удалять автоматически»).
  2. Используйте метод выгрузки в Таблицу Значений для фильтрации данных — это самый быстрый и надежный способ.
  3. Если удаляете записи в цикле — всегда делайте это в обратном порядке.
  4. Управляйте свойством Записывать = Истина, предоставляя платформе возможность зафиксировать транзакцию один раз в конце проведения.
← На главную