Как получить данные из ячейки табличной части при проведении документа в 1С?

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

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

В этой статье мы подробно разберем три основных технических подхода для получения данных из табличной части в модуле документа (внутри обработчика ОбработкаПроведения): обход коллекции в цикле, использование метода НайтиСтроки() и выполнение запроса к базе данных. Мы проанализируем преимущества и недостатки каждого метода, оценим их производительность, а также рассмотрим современные стандарты разработки фирмы «1С».

Важный технический нюанс: Записан ли документ при проведении?

Среди начинающих разработчиков часто бытует мнение, что в момент проведения документа запросом нельзя получить данные его табличной части, так как объект «еще не записан в базу данных». Это критическое заблуждение.

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

  1. Начинается транзакция базы данных.
  2. Выполняется запись самого документа и всех его табличных частей во физические таблицы СУБД.
  3. Вызывается обработчик события ОбработкаПроведения в модуле объекта.
  4. Происходит запись сформированных движений в базу данных.
  5. Транзакция фиксируется (Commit).

Таким образом, внутри процедуры ОбработкаПроведения данные документа уже физически находятся в таблицах СУБД. Вы можете абсолютно безопасно использовать запросы к табличным частям этого документа по его ссылке (ЭтотОбъект.Ссылка) — они вернут самые актуальные данные, включая те изменения, которые пользователь только что внес на форме перед нажатием кнопки «Провести».

---

Способ №1: Обход табличной части в цикле «Для каждого»

Это самый простой и интуитивно понятный способ, который чаще всего используют новички. Мы напрямую перебираем строки нашей табличной части, обращаясь к оперативной памяти сервера приложений, где в данный момент находится наш объект.

Рассмотрим пример реализации этого подхода. Предположим, у нас есть документ, табличная часть которого называется ДанныеОЗвонках, а реквизит этой табличной части — РезультатОбзвона. Нам нужно отфильтровать строки со значением "Подписан договор." и сделать движения по регистру сведений ПодписанныеДоговоры.


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

Преимущества обхода в цикле:

Недостатки и риски:

---

Способ №2: Использование метода «НайтиСтроки()»

Если нам не нужно обходить абсолютно все строки, а требуется выбрать только те, которые соответствуют конкретному условию, мы можем использовать встроенный метод платформы НайтиСтроки(). Этот метод выполняет поиск элементов коллекции в оперативной памяти.

Давайте посмотрим на практический пример реализации этого метода:


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

Преимущества метода НайтиСтроки():

Важные ограничения метода:

---

Способ №3: Запрос к табличной части документа (Рекомендуемый стандарт)

Использование языка запросов 1С — это наиболее гибкий, масштабируемый и профессиональный подход к получению данных. Он позволяет переложить всю тяжелую работу по сортировке, группировке, фильтрации и соединению данных на СУБД (MS SQL, PostgreSQL и др.), которая справляется с этим максимально эффективно.

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


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    Движения.ПодписанныеДоговоры.Записывать = Истина;
    Движения.ПодписанныеДоговоры.Очистить();
    
    // Создаем объект запроса
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	ОбзвонДанныеОЗвонках.НаименованиеКонтрагента КАК Контрагент
        |ИЗ
        |	Документ.ОбзвонКлиентов.ДанныеОЗвонках КАК ОбзвонДанныеОЗвонках
        |ГДЕ
        |	ОбзвонДанныеОЗвонках.Ссылка = &Ссылка
        |	И ОбзвонДанныеОЗвонках.РезультатОбзвона = &РезультатОбзвона";
    
    // Передаем ссылку на текущий проводимый документ и условие отбора
    Запрос.УстановитьПараметр("Ссылка", ЭтотОбъект.Ссылка);
    Запрос.УстановитьПараметр("РезультатОбзвона", "Подписан договор.");
    
    РезультатЗапроса = Запрос.Выполнить();
    
    // Если результат пустой, проведение можно завершить досрочно
    Если РезультатЗапроса.Пустой() Тогда
        Возврат;
    КонецЕсли;
    
    Выборка = РезультатЗапроса.Выбрать();
    
    Пока Выборка.Следующий() Цикл
        
        НоваяЗапись = Движения.ПодписанныеДоговоры.Добавить();
        НоваяЗапись.Период = Дата;
        НоваяЗапись.Контрагент = Выборка.Контрагент;
        НоваяЗапись.ПодписанДоговор = Истина;
        
    КонецЦикла;
    
КонецПроцедуры

Преимущества работы через запрос:

Альтернативный вариант в памяти (Временные Таблицы):
Если перед проведением вы модифицировали табличную часть программно и не хотите лишний раз обращаться к физическим таблицам СУБД на диске, вы можете выгрузить ТЧ в память, передать её в запрос как параметр и поместить во Временную Таблицу. Это позволит использовать всю мощь языка запросов к оперативным данным в ОЗУ:


ТаблицаДанных = ЭтотОбъект.ДанныеОЗвонках.Выгрузить();

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Данные ИЗ &ТаблицаДанных КАК ТаблицаДанных;
    |ВЫБРАТЬ Контрагент ИЗ ВТ_Данные ГДЕ РезультатОбзвона = &Результат";
Запрос.УстановитьПараметр("ТаблицаДанных", ТаблицаДанных);
Запрос.УстановитьПараметр("Результат", "Подписан договор.");

---

Современные стандарты проведения в типовых конфигурациях (БСП)

Если мы обратимся к архитектуре современных типовых конфигураций фирмы «1С» (таких как ERP, Управление торговлей, Комплексная автоматизация), то увидим, что разработчики практически полностью отказались от написания движений непосредственно в модуле объекта документа.

Сегодня стандартом разработки является разделение транзакционной логики:

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

Такой подход гарантирует максимальное быстродействие системы в режиме многопользовательской работы и полностью исключает появление классических ошибок блокировок и падения производительности.

Подведем итог: Для простых задач и небольших документов на этапе обучения вполне допустимо использовать обычный цикл или метод НайтиСтроки(). Однако, если вы нацелены на создание профессиональных, тиражируемых и отказоустойчивых решений, вашим основным инструментом всегда должно быть получение данных с помощью запросов.

← На главную