При доработке алгоритмов проведения документов или создании внешних обработок разработчики часто сталкиваются с задачей выборочного удаления записей из регистра бухгалтерии. Например, требуется удалить только проводки по определенному счету дебета или кредита, оставив остальные движения документа нетронутыми. Разберем по шагам, как правильно работать с набором записей регистра бухгалтерии и какие нюансы платформы 1С:Предприятие необходимо учитывать.
Рассмотрим частые ошибки, возникающие при попытке удаления строк:
Проводка.Удалить() вызывает синтаксическую ошибку, так как объект РегистрБухгалтерииЗапись не содержит собственного метода для самоудаления. Метод Удалить() принадлежит родительской коллекции — объекту РегистрБухгалтерииНаборЗаписей.Отбор строго ограничен (как правило, отбор возможен только по полю Регистратор). Попытка выполнить НаборЗаписей.Отбор.СчетДт.Установить(...) приведет к ошибке во время выполнения. Сначала считываются все движения по регистратору, а фильтрация выполняется уже в коде.Для каждого или по возрастанию индекса и удалять их на лету, происходит сдвиг индексов оставшихся элементов, из-за чего часть записей пропускается.Проанализируем классический и наиболее надежный способ обхода коллекции — цикл с конца к началу. При таком подходе удаление текущего элемента не нарушает нумерацию еще не проверенных записей.
Посмотрим на пример кода при работе с набором записей вне модуля проведения документа:
НаборЗаписей = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ДокументСсылка);
НаборЗаписей.Прочитать();
// Обходим набор с конца к началу
Для НомерСтроки = НаборЗаписей.Количество() - 1 По 0 Цикл
Проводка = НаборЗаписей[НомерСтроки];
// Проверяем условие для удаления
Если Проводка.СчетДт = ПланыСчетов.Хозрасчетный.ОсновноеПроизводство И Проводка.Сумма <> 0 Тогда
НаборЗаписей.Удалить(НомерСтроки);
КонецЕсли;
КонецЦикла;
// Записываем изменения в базу данных
НаборЗаписей.Записать();
Платформа 1С поддерживает удаление записи из набора не только по индексу, но и по переданной ссылке на саму запись: НаборЗаписей.Удалить(Запись). Чтобы не модифицировать коллекцию непосредственно во время ее обхода, удаляемые проводки предварительно собираются в массив.
Разберем данный алгоритм на практике:
НаборЗаписей = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ДокументСсылка);
НаборЗаписей.Прочитать();
ПроводкиДляУдаления = Новый Массив;
// 1. Находим все проводки, соответствующие условию
Для Каждого Проводка Из НаборЗаписей Цикл
Если Проводка.СчетДт = ПланыСчетов.Хозрасчетный.ОсновноеПроизводство И Проводка.Сумма <> 0 Тогда
ПроводкиДляУдаления.Добавить(Проводка);
КонецЕсли;
КонецЦикла;
// 2. Удаляем найденные проводки из набора
Для Каждого УдаляемаяПроводка Из ПроводкиДляУдаления Цикл
НаборЗаписей.Удалить(УдаляемаяПроводка);
КонецЦикла;
// 3. Фиксируем результат
НаборЗаписей.Записать();
Если требуется применить сложную фильтрацию или дополнительную группировку строк, удобно использовать выгрузку движений в таблицу значений:
НаборЗаписей = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ДокументСсылка);
НаборЗаписей.Прочитать();
ТаблицаДвижений = НаборЗаписей.Выгрузить();
// Ищем и удаляем строки из таблицы значений
ПараметрыОтбора = Новый Структура("СчетДт", ПланыСчетов.Хозрасчетный.ОсновноеПроизводство);
НайденныеСтроки = ТаблицаДвижений.НайтиСтроки(ПараметрыОтбора);
Для Каждого СтрокаТЗ Из НайденныеСтроки Цикл
Если СтрокаТЗ.Сумма <> 0 Тогда
ТаблицаДвижений.Строки.Удалить(СтрокаТЗ);
КонецЕсли;
КонецЦикла;
// Загружаем скорректированную таблицу обратно и записываем
НаборЗаписей.Загрузить(ТаблицаДвижений);
НаборЗаписей.Записать();
Выясним, какие особенности контекста исполнения необходимо учитывать:
Прочитать() не требуется — движения формируются в памяти через коллекцию Движения.Хозрасчетный. Достаточно скорректировать строки до завершения процедуры и убедиться, что для коллекции выставлено свойство Движения.Хозрасчетный.Записывать = Истина.РучнаяКорректировка = Истина.НачатьТранзакцию() / ЗафиксироватьТранзакцию()) для обеспечения целостности данных и исключения блокировок.