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

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

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

Ошибки при попытке удалить запись напрямую

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

  1. Вызов метода удаления у самой проводки: конструкция вида Проводка.Удалить() вызывает синтаксическую ошибку, так как объект РегистрБухгалтерииЗапись не содержит собственного метода для самоудаления. Метод Удалить() принадлежит родительской коллекции — объекту РегистрБухгалтерииНаборЗаписей.
  2. Попытка установить отбор по счету в наборе записей: в регистрах бухгалтерии с поддержкой корреспонденции состав доступных полей в свойстве Отбор строго ограничен (как правило, отбор возможен только по полю Регистратор). Попытка выполнить НаборЗаписей.Отбор.СчетДт.Установить(...) приведет к ошибке во время выполнения. Сначала считываются все движения по регистратору, а фильтрация выполняется уже в коде.
  3. Удаление в прямом цикле: если перебирать записи циклом Для каждого или по возрастанию индекса и удалять их на лету, происходит сдвиг индексов оставшихся элементов, из-за чего часть записей пропускается.

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

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

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


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

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

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

Способ 2. Удаление по объекту записи с использованием массива

Платформа 1С поддерживает удаление записи из набора не только по индексу, но и по переданной ссылке на саму запись: НаборЗаписей.Удалить(Запись). Чтобы не модифицировать коллекцию непосредственно во время ее обхода, удаляемые проводки предварительно собираются в массив.

Разберем данный алгоритм на практике:


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

ПроводкиДляУдаления = Новый Массив;

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

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

// 3. Фиксируем результат
НаборЗаписей.Записать();

Способ 3. Выгрузка в таблицу значений

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


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

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

// Ищем и удаляем строки из таблицы значений
ПараметрыОтбора = Новый Структура("СчетДт", ПланыСчетов.Хозрасчетный.ОсновноеПроизводство);
НайденныеСтроки = ТаблицаДвижений.НайтиСтроки(ПараметрыОтбора);

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

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

Важные практические рекомендации

Выясним, какие особенности контекста исполнения необходимо учитывать:

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