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