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

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

В практике разработчика 1С часто возникает задача программной очистки табличных частей документов от определенных строк. Это может быть связано с исправлением ошибок загрузки, удалением позиций с нулевым количеством или, как в нашем случае, удалением конкретной номенклатуры из документа «Отчет о розничных продажах». В этой статье мы подробно разберем, как правильно реализовать этот механизм, учитывая контекст выполнения кода и требования к проведению документа. Если требуется оперативно скорректировать строки и движения без написания собственного кода, можно использовать универсальный редактор документов для управляемых форм.

Метод 1. Удаление строк через объект документа (Серверный контекст)

Рассмотрим наиболее надежный способ, когда у нас есть ссылка на документ, и нам необходимо внести в него изменения «тихо», без участия пользователя, или из внешней обработки. Основная логика заключается в получении объекта из ссылки, поиске нужных строк и их физическом удалении из коллекции.

Разберем по шагам алгоритм, предложенный участниками обсуждения:

  1. Получаем объект документа из ссылки с помощью метода ПолучитьОбъект().
  2. Создаем структуру отбора, где ключом будет имя реквизита (например, Номенклатура), а значением — искомый объект.
  3. Используем метод НайтиСтроки(), который возвращает массив строк, соответствующих условию.
  4. В цикле обходим полученный массив и удаляем каждую строку из табличной части.
  5. Записываем документ с режимом проведения.

Проанализируем пример кода:


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

Важный нюанс: Обратите внимание на использование РежимЗаписиДокумента.Проведение. Если просто вызвать метод Записать(), документ будет сохранен, но его движения по регистрам останутся прежними (старыми). Для актуализации данных в учете проведение обязательно.

Метод 2. Удаление строк непосредственно в форме (ДанныеФормыКоллекция)

Если задача стоит так, что пользователь нажал кнопку в открытой форме документа и строки должны исчезнуть прямо «на глазах», мы работаем не с объектом базы данных, а с типом ДанныеФормыКоллекция. Это гораздо быстрее, так как не требует лишних обращений к базе и перечитывания объекта.

Рассмотрим, как это выглядит в модуле формы:


&НаКлиенте
Процедура УдалитьВыбраннуюНоменклатуру(Команда)
    
    // Предположим, переменная УдаляемаяНоменклатура уже выбрана пользователем
    ПараметрыОтбора = Новый Структура("Номенклатура", УдаляемаяНоменклатура);
    
    // Работаем напрямую с реквизитом формы "Объект.Товары"
    СтрокиДляУдаления = Объект.Товары.НайтиСтроки(ПараметрыОтбора);
    
    Для Каждого Стр Из СтрокиДляУдаления Цикл
        Объект.Товары.Удалить(Стр);
    КонецЦикла;
    
    // Устанавливаем признак того, что форма изменена
    Модифицированность = Истина;
    
КонецПроцедуры

Выясним причину, почему в Сообщении 11 акцентировалось внимание на контексте. Если вы удаляете строки в форме, вам не нужно вызывать Записать() программно, если вы хотите дать пользователю возможность самому решить — сохранять изменения или нет. Если же нужно сразу провести — вызываем Записать() на клиенте.

Особенности обхода коллекции при удалении

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

Проанализируем проблему: когда мы удаляем строку с индексом 0, строка, которая была под индексом 1, становится на место 0-й. Если счетчик цикла увеличится до 1, мы фактически пропустим ту строку, которая только что сместилась вверх.

Если вам все же нужно использовать обход по счетчику, всегда делайте это с конца в начало:


ВсегоСтрок = Объект.Товары.Количество();
Для Счетчик = 1 По ВсегоСтрок Цикл
    ТекущийИндекс = ВсегоСтрок - Счетчик;
    СтрокаТЧ = Объект.Товары[ТекущийИндекс];
    
    Если СтрокаТЧ.Номенклатура = ИскомаяНоменклатура Тогда
        Объект.Товары.Удалить(ТекущийИндекс);
    КонецЕсли;
КонецЦикла;

Оптимизация для больших табличных частей

В случае, если в вашем документе «Отчет о розничных продажах» содержатся тысячи строк, а удалить нужно, например, половину из них, метод Удалить() в цикле может работать неэффективно. Система при каждом удалении перестраивает индексы коллекции.

Выясним, как сделать это быстрее. В профессиональной разработке применяется метод «перезагрузки»:

  1. Выгружаем табличную часть в таблицу значений (ТЗ).
  2. Удаляем лишние строки из ТЗ (это работает быстрее в оперативной памяти).
  3. Очищаем табличную часть документа методом Очистить().
  4. Загружаем отфильтрованные данные обратно методом Загрузить().

Пример реализации:


ТЗ = ОбъектДок.Товары.Выгрузить();
ПараметрыОтбора = Новый Структура("Номенклатура", ИскомаяНоменклатура);
НайденныеСтрокиТЗ = ТЗ.НайтиСтроки(ПараметрыОтбора);

Для Каждого СтрТЗ Из НайденныеСтрокиТЗ Цикл
    ТЗ.Удалить(СтрТЗ);
КонецЦикла;

ОбъектДок.Товары.Загрузить(ТЗ);

Выбор номенклатуры пользователем (Асинхронность)

В обсуждении на форуме был поднят вопрос: «как выбрать номенклатуру?». На платформе 8.3 в управляемых формах для этого используются асинхронные методы, чтобы не блокировать интерфейс. Если вы пишете обработку, лучше всего использовать стандартный выбор из справочника.

Рассмотрим пример вызова диалога выбора:


&НаКлиенте
Процедура ВыбратьИУдалить(Команда)
    
    Оповещение = Новый ОписаниеОповещения("ПослеВыбораНоменклатуры", ЭтотОбъект);
    ПараметрыВыбора = Новый Структура;
    
    ОткрытьФорму("Справочник.Номенклатура.ФормаВыбора", ПараметрыВыбора, ЭтотОбъект, , , , Оповещение);
    
КонецПроцедуры

&НаКлиенте
Процедура ПослеВыбораНоменклатуры(ВыбранноеЗначение, ДополнительныеПараметры) Экспорт
    
    Если ЗначениеЗаполнено(ВыбранноеЗначение) Тогда
        // Здесь вызываем процедуру удаления, передавая ВыбранноеЗначение
        УдалитьСтрокиНаСервере(ВыбранноеЗначение);
    КонецЕсли;
    
КонецПроцедуры

Резюме и рекомендации

Подводя итог, можно выделить следующие правила хорошего тона при программном удалении строк в 1С 8.3:

Применение этих методик позволит вам создавать надежные и быстрые алгоритмы обработки данных в конфигурациях на базе управляемых форм.

← На главную