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