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