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

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

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

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

Анализ типовых ошибок при модификации набора записей

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


Движ1 = Док.ПолучитьОбъект().Движения.РасчетыСКлиентами;
Движ1.Прочитать();
Для Каждого Стр Из Движ1 Цикл
    Если Стр.Сумма >= 0 Тогда
        Стр.Очистить(); // Ошибка: у строки набора записей нет метода Очистить()
    КонецЕсли;
КонецЦикла;
Движ1.Записать();

В этом примере допущены две критические ошибки:

  1. Метод Очистить() существует у всей коллекции (набора записей), но отсутствует у объекта строки (РегистрНакопленияЗапись). Для удаления конкретной строки из набора необходимо использовать метод коллекции Удалить().
  2. Удаление элементов коллекции внутри прямого цикла Для Каждого приводит к смещению индексов оставшихся элементов. Если под критерий удаления попадают две строки подряд, итератор пропустит следующую за удаленной строку, что приведет к неполной обработке данных.

Способ 1. Удаление записей через обратный цикл по индексу

Рассмотрим наиболее производительный и надежный способ непосредственного удаления строк из набора записей — обход коллекции с конца с помощью цикла Пока.

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


// Создаем набор записей регистра накопления
НаборЗаписей = РегистрыНакопления.РасчетыСКлиентами.СоздатьНаборЗаписей();

// Устанавливаем отбор по регистратору
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаДокумент);

// Считываем текущие движения из базы данных
НаборЗаписей.Прочитать();

// Получаем начальный индекс последней строки набора
Индекс = НаборЗаписей.Количество() - 1;

Пока Индекс >= 0 Цикл
    ТекущаяЗапись = НаборЗаписей[Индекс];
    
    // Проверяем условие для удаления
    Если ТекущаяЗапись.Сумма >= 0 Тогда
        НаборЗаписей.Удалить(Индекс);
    КонецЕсли;
    
    Индекс = Индекс - 1;
КонецЦикла;

// Записываем набор с замещением существующих движений
НаборЗаписей.Записать();

Способ 2. Обработка движений через выгрузку в Таблицу Значений

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


НаборЗаписей = РегистрыНакопления.РасчетыСКлиентами.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаДокумент);
НаборЗаписей.Прочитать();

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

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

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

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

Способ 3. Использование промежуточного массива строк набора

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


НаборЗаписей = РегистрыНакопления.РасчетыСКлиентами.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаДокумент);
НаборЗаписей.Прочитать();

СтрокиК_Удалению = Новый Массив;

Для Каждого Запись Из НаборЗаписей Цикл
    Если Запись.Сумма >= 0 Тогда
        СтрокиК_Удалению.Добавить(Запись);
    КонецЕсли;
КонецЦикла;

Для Каждого УдаляемаяЗапись Из СтрокиК_Удалению Цикл
    НаборЗаписей.Удалить(УдаляемаяЗапись);
КонецЦикла;

НаборЗаписей.Записать();

Важные особенности и риски прямой модификации движений

Выясним ключевые нюансы платформы 1С:Предприятие, о которых важно помнить при программном изменении наборов записей:

  1. Замещение движений: Метод Записать() по умолчанию вызывается с параметром Замещать = Истина. Это означает, что при записи набор полностью перезаписывает все движения регистратора. Если перед вызовом не выполнить НаборЗаписей.Прочитать(), платформа посчитает набор пустым и полностью сотрет все записи документа в этом регистре.
  2. Повторное проведение документа: Прямая правка регистра не изменяет данные в табличных частях самого документа. При любой последующей перепроводке документа модулем ОбработкаПроведения движения будут пересчитаны заново по стандартному алгоритму конфигурации, и ваши ручные правки пропадут.
  3. Пересчет итогов и блокировки: Метод Записать() инициирует автоматический пересчет итоговых таблиц регистров накопления. При массовой корректировке движений по большому количеству документов рекомендуется группировать операции в транзакции для минимизации блокировок.
  4. Альтернативные подходы: Если требуется сохранить прозрачность учета и исключить затирание правок при перепроведении, предпочтительно использовать штатный документ Операция / Корректировка регистров либо включать признак РучнаяКорректировка у исходного документа, если такой механизм предусмотрен в конфигурации.
← На главную