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