При разработке расширений или доработке существующих конфигураций, таких как 1С:Управление торговлей 11.5, программисты часто сталкиваются с необходимостью программного анализа данных в специализированных формах. Одной из таких сложных форм является рабочее место «Состояние обеспечения заказов». Типичная проблема: при обходе коллекции строк программный код возвращает пустые значения для колонок Номенклатура и Характеристика, хотя визуально в форме данные заполнены. Разберем детально, почему так происходит и как правильно получить эти данные.
Первое, что нам необходимо понять: реквизит, с которым мы работаем в этой обработке, — это не обычная табличная часть Товары, как может показаться на первый взгляд, а Дерево значений (тип ДанныеФормыДерево). В отличие от плоской таблицы, дерево имеет иерархическую структуру.
Рассмотрим стандартную иерархию в обработке «Состояние обеспечения»:
Заказ клиента или Заказ на сборку). На этом уровне колонки Номенклатура и Характеристика всегда будут пустыми, так как строка агрегирует весь документ.Номенклатура и Характеристика.Когда мы используем метод Товары.ПолучитьЭлементы(), система возвращает нам только коллекцию строк верхнего уровня. Если мы начинаем цикл по этой коллекции, мы обращаемся к строкам-заказам, где данных о конкретном товаре просто нет.
Проанализируем фрагмент кода, который часто приводит к ошибке:
// ОШИБОЧНЫЙ ПОДХОД
ДеревоЗначений = Товары.ПолучитьЭлементы(); // Получаем только первый уровень (Заказы)
Для каждого Строка Из ДеревоЗначений Цикл
// Попытка получить номенклатуру из строки заказа
Сообщить(Строка.Номенклатура); // Всегда вернет пустое значение
КонецЦикла;
В данном случае цикл проходит по «шапкам» заказов. Чтобы добраться до товаров, нам нужно «спуститься» на уровень ниже.
Если нам достоверно известно, что данные находятся на втором уровне иерархии, мы можем использовать вложенный цикл. Рассмотрим этот метод подробнее:
КоллекцияЗаказов = Товары.ПолучитьЭлементы();
Для каждого СтрокаЗаказа Из КоллекцияЗаказов Цикл
// Получаем строки товаров для конкретного заказа
СтрокиТоваров = СтрокаЗаказа.ПолучитьЭлементы();
Для каждого СтрокаТовара Из СтрокиТоваров Цикл
// Теперь мы находимся на уровне Номенклатуры
Если ЗначениеЗаполнено(СтрокаТовара.Номенклатура) Тогда
Сообщить("Товар: " + СтрокаТовара.Номенклатура + ", Характеристика: " + СтрокаТовара.Характеристика);
// Здесь можно выполнять ваш запрос или логику
// ВАЖНО: Старайтесь не помещать запросы внутрь циклов!
КонецЕсли;
КонецЦикла;
КонецЦикла;
В сложных интерфейсах 1С уровни вложенности могут меняться в зависимости от настроек группировки. Чтобы код был отказоустойчивым, лучше использовать рекурсивную процедуру. Разберем, как это реализовать:
&НаСервере
Процедура ОбработатьСтрокиДерева(КоллекцияЭлементов)
Для каждого ТекущаяСтрока Из КоллекцияЭлементов Цикл
// Проверяем наличие данных в текущей строке
Если ЗначениеЗаполнено(ТекущаяСтрока.Номенклатура) Тогда
// Выполняем полезную работу
ОбработатьДанныеПозиции(ТекущаяСтрока);
КонецЕсли;
// Рекурсивный вызов для всех вложенных уровней
ПодчиненныеЭлементы = ТекущаяСтрока.ПолучитьЭлементы();
Если ПодчиненныеЭлементы.Количество() > 0 Тогда
ОбработатьСтрокиДерева(ПодчиненныеЭлементы);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
// Вызов процедуры
ОбработатьСтрокиДерева(Товары.ПолучитьЭлементы());
Этот подход гарантирует, что вы найдете номенклатуру независимо от того, на каком уровне иерархии она расположена в текущий момент.
Проанализируем еще несколько причин, по которым данные могут казаться «пустыми», даже если вы правильно обходите уровни дерева:
НоменклатураХарактеристика (составная строка), а реальные данные могут лежать в скрытых колонках Номенклатура и Характеристика. Всегда проверяйте состав колонок реквизита формы ДанныеФормыДерево в конфигураторе.СправочникСсылка.Номенклатура, а вы присваиваете её реквизиту типа Строка, в интерфейсе может отобразиться пустота.Практический совет: Никогда не делайте запрос к базе данных внутри цикла обхода дерева (как было показано в исходном вопросе темы). Это критически замедляет работу системы. Правильнее сначала собрать все ссылки на заказы или товары в массив, выполнить один запрос к базе данных, выгрузить результат в таблицу значений и затем быстро искать данные в этой таблице по ключу внутри цикла.
Выяснив причину отсутствия данных (неверный уровень иерархии), мы можем эффективно дорабатывать логику обеспечения, добавлять в расширения собственные проверки и заполнять дополнительные реквизиты, такие как Менеджер или Снабженец, без потери производительности.