Разработка внешних печатных форм (ВПФ) — это классическая задача для начинающего программиста 1С. Однако даже в простых на первый взгляд механизмах таятся нюансы, которые могут привести к трудночитаемым ошибкам. Одной из самых частых является ошибка «Итератор для значения не определен». В этой статье мы подробно разберем, почему она возникает, как проанализировать код и какие шаги предпринять для успешной регистрации и работы печатной формы в системе.
Для начала разберем саму суть сообщения системы. Ошибка «Итератор для значения не определен» в 1С возникает в тот момент, когда платформа встречает конструкцию Для каждого ... Из ... Цикл, но объект, который стоит после слова Из, не является коллекцией. Коллекцией в 1С считаются массивы, таблицы значений, списки значений и табличные части документов или справочников.
Если в коде указано:
Для Каждого ТекущаяСтрока из СсылкаНаОбъект.ПеремещениеТоваров Цикл
// действия
КонецЦикла;
А переменная СсылкаНаОбъект.ПеремещениеТоваров на момент выполнения кода имеет значение Неопределено или является строкой, числом или самим документом (а не его табличной частью), система выдаст ошибку итератора. Рассмотрим подробнее основные сценарии, приводящие к этому результату.
Проанализируем ситуацию, описанную в теме. Автор пытается перебрать СсылкаНаОбъект.ПеремещениеТоваров. Здесь кроется типичная ошибка новичка: путаница между названием самого документа и его внутренней структурой. Если СсылкаНаОбъект — это ссылка на документ типа «Перемещение товаров», то обращение к нему по имени типа ничего не даст. Нам нужно обратиться к конкретной табличной части, которая в типовых конфигурациях обычно называется Товары.
Исправленный фрагмент кода должен выглядеть так:
// Вместо обращения к типу документа, обращаемся к табличной части "Товары"
Для Каждого ТекущаяСтрока из СсылкаНаОбъект.Товары Цикл
ОбластьСтроки.Параметры.Счёт = ТекущаяСтрока.СчётУчёта;
ОбластьСтроки.Параметры.МатериалНаименование = ТекущаяСтрока.Номенклатура;
// ... заполнение остальных параметров
ТабличныйДокумент.Вывести(ОбластьСтроки);
КонецЦикла;
Важный момент: всегда проверяйте точное имя табличной части в Конфигураторе. В разных конфигурациях (БП, УТ, ERP) имена могут отличаться: Состав, Материалы, Услуги и так далее.
Если ошибка возникает не при нажатии на кнопку «Печать», а в момент подключения (регистрации) внешней обработки в справочнике «Дополнительные отчеты и обработки», значит, проблема кроется в модуле объекта обработки, а именно в функции СведенияОВнешнейОбработке().
Современные конфигурации на базе Библиотеки Стандартных Подсистем (БСП) требуют строгого соблюдения структуры этой функции. Если в ней неверно указан тип команды или параметры использования, система может попытаться инициализировать обработку некорректно, что приведет к сбою итератора во внутренних механизмах БСП.
Рассмотрим пример правильной структуры регистрации команды для печатной формы:
Функция СведенияОВнешнейОбработке() Экспорт
ПараметрыРегистрации = Новый Структура;
ПараметрыРегистрации.Вставить("Вид", "ПечатнаяФорма");
ПараметрыРегистрации.Вставить("Назначение", ПолучитьНазначениеОбработки());
ПараметрыРегистрации.Вставить("Наименование", "Акт на списание материалов (внешний)");
ПараметрыРегистрации.Вставить("Версия", "1.0");
ПараметрыРегистрации.Вставить("БезопасныйРежим", Истина);
Команды = Новый ТаблицаЗначений;
Команды.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка"));
Команды.Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("Строка"));
Команды.Колонки.Добавить("Использование", Новый ОписаниеТипов("Строка"));
Команды.Колонки.Добавить("ПоказыватьОповещение", Новый ОписаниеТипов("Булево"));
Команды.Колонки.Добавить("Модификатор", Новый ОписаниеТипов("Строка"));
НоваяКоманда = Команды.Добавить();
НоваяКоманда.Представление = "Печать акта на списание";
НоваяКоманда.Идентификатор = "ПФ_MXL_МБ8";
НоваяКоманда.Использование = "ВызовСерверногоМетода"; // Для печати через модуль объекта
НоваяКоманда.ПоказыватьОповещение = Ложь;
ПараметрыРегистрации.Вставить("Команды", Команды);
Возврат ПараметрыРегистрации;
КонецФункции
Поскольку внешняя обработка запускается в контексте основной конфигурации, отлаживать её напрямую бывает сложно. Выясним, как упростить этот процесс. Рассмотрим два эффективных метода:
СсылкаНаОбъект с типом нужного документа. Добавим кнопку «Выполнить», в обработчике которой вызовем нашу функцию СформироватьПечатнуюФорму(). Теперь мы можем запустить обработку через «Файл -> Открыть», выбрать документ и нажать «Выполнить», предварительно поставив точку останова в коде.Проанализируем ситуацию через «Табло» во время отладки. Если на строке с циклом мы остановимся и вычислим выражение СсылкаНаОбъект, мы должны увидеть ссылку на реальный документ. Если там Неопределено, значит, механизм БСП не передал данные в форму, и нужно проверять экспортную процедуру Печать() в модуле объекта.
В исходном коде автора параметры заполняются вручную. Разберем, как сделать это элегантнее. Если имена полей в вашей табличной части (например, Количество, Номенклатура) совпадают с именами параметров в макете, можно использовать метод Заполнить(). Это застрахует вас от ошибок при ручном вводе и сократит объем кода.
Посмотрим на пример оптимизации:
Для Каждого ТекущаяСтрока из СсылкаНаОбъект.Товары Цикл
ОбластьСтроки.Параметры.Заполнить(ТекущаяСтрока);
// Дозаполняем только те поля, которых нет в строке ТЧ напрямую
ОбластьСтроки.Параметры.ЕдиницаИзмерения = ТекущаяСтрока.Упаковка;
ТабличныйДокумент.Вывести(ОбластьСтроки);
КонецЦикла;
Проанализировав проблему, стоит упомянуть «золотой стандарт» разработки. Вместо перебора табличной части «через точку» (СсылкаНаОбъект.Товары), опытные разработчики используют запросы.
Почему это важно?
Рассмотрим пример правильного подхода:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПеремещениеТоваровТовары.Номенклатура.Наименование КАК МатериалНаименование,
| ПеремещениеТоваровТовары.КоличествоУпаковок КАК Количество,
| ПеремещениеТоваровТовары.СчетУчета КАК Счёт
|ИЗ
| Документ.ПеремещениеТоваров.Товары КАК ПеремещениеТоваровТовары
|ГДЕ
| ПеремещениеТоваровТовары.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", СсылкаНаОбъект);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
ОбластьСтроки.Параметры.Заполнить(Выборка);
ТабличныйДокумент.Вывести(ОбластьСтроки);
КонецЦикла;
Таким образом, для решения проблемы «Итератор для значения не определен» необходимо последовательно проверить три аспекта: правильность обращения к коллекциям (табличным частям), корректность заполнения регистрационных данных в СведенияОВнешнейОбработке и убедиться в том, что ссылка на объект печати действительно передается в процедуру формирования документа.