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

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

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

Базовый синтаксис удаления строки проводки

Движения документа по бухгалтерскому регистру представляют собой объект НаборЗаписей. Коллекция проводок внутри набора поддерживает стандартные методы работы с коллекциями, включая метод Удалить().

Для удаления конкретной проводки в метод Удалить() передается либо сама строка проводки, либо ее числовой индекс в наборе записей. После изменения состава набора необходимо зафиксировать изменения в базе данных с помощью метода Записать().

Рассмотрим базовый пример вызова:


// Удаление конкретной строки
НаборПроводок.Удалить(Проводка);

// Запись изменений в регистр
НаборПроводок.Записать(Истина);

Опасность удаления элементов в цикле «Для Каждого»

Проанализируем распространенную ошибку: попытку удаления элементов прямо внутри обхода Для Каждого Проводка Из НаборПроводок Цикл. При вызове метода Удалить() размер коллекции уменьшается, а все последующие элементы сдвигаются на одну позицию влево (их индексы уменьшаются на 1). При этом счетчик итератора цикла переходит к следующему порядковому номеру.

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

Способ 1. Обход набора записей в обратном порядке (по индексу)

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

Посмотрим на пример реализации с предварительным получением счета:


// Получаем счет заранее до цикла, чтобы не вызывать поиск на каждой итерации
СчетУСН = ПланыСчетов.Хозрасчетный.НайтиПоКоду("УСН.01");

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

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

// Записываем набор, очищая признак модифицированности
НаборПроводок.Записать(Истина);

Способ 2. Предварительный сбор удаляемых строк в массив

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

  1. В первом цикле проходим по набору записей и собираем все проводки, подлежащие удалению, в отдельный Массив.
  2. Во втором цикле перебираем элементы массива и удаляем их из набора записей.
  3. Записываем измененный набор.

Посмотрим, как выглядит программный код:


СчетУСН = ПланыСчетов.Хозрасчетный.НайтиПоКоду("УСН.01");

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

МассивУдаляемых = Новый Массив;

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

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

НаборПроводок.Записать(Истина);

Важные правила работы с движениями документов

При программной корректировке проводок необходимо учитывать следующие особенности платформы 1С:

  1. Оптимизация чтения данных: Не следует получать объект документа целиком через ПолучитьОбъект() только ради доступа к движениям. Гораздо быстрее и безопаснее создавать объект НаборЗаписей регистра бухгалтерии напрямую, установив отбор по регистратору. Это исключает избыточные блокировки объекта документа в базе данных.
  2. Вынос поиска объектов из цикла: Вызов метода ПланыСчетов.Хозрасчетный.НайтиПоКоду() внутри цикла приводит к повторным поискам на каждой итерации. Ссылку на счет необходимо получить один раз до начала обхода либо использовать обращение к предопределенному счету конфигурации напрямую (например, ПланыСчетов.Хозрасчетный.УСН_01).
  3. Поведение при перепроведении: Удаление проводок из набора является модификацией регистра. Если документ в будущем будет перепроведен пользователем или групповой обработкой, процедура ОбработкаПроведения заново сформирует типовые проводки. Чтобы зафиксировать ручные изменения в типовых конфигурациях, у документа устанавливают реквизит РучнаяКорректировка = Истина.
  4. Параметр метода Записать: Передача параметра Истина в вызов НаборПроводок.Записать(Истина) явно указывает платформе на необходимость замещения существующих записей в базе данных записями из текущего набора.
← На главную