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