При разработке внешних печатных форм для документов 1С:Предприятия 8.3 пользователи нередко сталкиваются с ситуацией, когда табличный документ не формируется или выводится пустым, несмотря на, казалось бы, корректный код. Рассмотрим подробно основные причины такой проблемы на примере внешней печатной формы для документа "КадровыйПеревод" и разберем по шагам, как диагностировать и устранить подобные неполадки.
Наша цель – понять, почему печатная форма не выводится, и выявить типичные ошибки, которые могут к этому привести. Мы проанализируем процесс регистрации внешней обработки, логику обработчика печати и функцию формирования самого табличного документа, а также уделим особое внимание отладке запросов и заполнению макета.
Первым шагом при работе с внешними печатными формами является их корректная регистрация в системе. Система 1С использует функцию СведенияОВнешнейОбработке для получения метаданных о печатной форме, а затем обрабатывает запрос на печать в специальной процедуре Печать.
Начнем с кода, отвечающего за регистрацию и вызов печатной формы:
Функция СведенияОВнешнейОбработке() Экспорт
ПараметрыРегистрации = Новый Структура;
ПараметрыРегистрации.Вставить("Вид", "ПечатнаяФорма");
ПараметрыРегистрации.Вставить("Назначение", ПолучитьНазначениеОбработки());
ПараметрыРегистрации.Вставить("Наименование", "Приказ о переводе");
ПараметрыРегистрации.Вставить("Версия", "1.0");
ПараметрыРегистрации.Вставить("Информация", "Приказ о переводе");
ПараметрыРегистрации.Вставить("БезопасныйРежим", Ложь);
Команды = ПолучитьТаблицуКоманд();
ДобавитьКоманду(Команды, "Приказ О Переводе1", "ПФ_ПриказОПереводе", "ВызовСерверногоМетода", Ложь, "ПечатьMXL");
ПараметрыРегистрации.Вставить("Команды", Команды);
Возврат ПараметрыРегистрации;
КонецФункции
Функция ПолучитьНазначениеОбработки()
Массив = Новый Массив;
Массив.Добавить("Документ.КадровыйПеревод");
Возврат Массив;
КонецФункции
Функция ПолучитьТаблицуКоманд()
Команды = Новый ТаблицаЗначений;
Команды.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка"));
Команды.Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("Строка"));
Команды.Колонки.Добавить("Использование", Новый ОписаниеТипов("Строка"));
Команды.Колонки.Добавить("ПоказыватьОповещение", Новый ОписаниеТипов("Булево"));
Команды.Колонки.Добавить("Модификатор", Новый ОписаниеТипов("Строка"));
Возврат Команды;
КонецФункции
Процедура ДобавитьКоманду(ТаблицаКоманд, Представление, Идентификатор, Использование, ПоказыватьОповещение = Ложь, Модификатор = "")
НоваяКоманда = ТаблицаКоманд.Добавить();
НоваяКоманда.Представление = Представление;
НоваяКоманда.Использование = Использование;
НоваяКоманда.ПоказыватьОповещение = ПоказыватьОповещение;
НоваяКоманда.Модификатор = Модификатор;
НоваяКоманда.Идентификатор = Идентификатор;
КонецПроцедуры
//Печать ПФ
Процедура ДобавитьКомандыПечати(КомандыПечати) Экспорт
КомандаПечати = КомандыПечати.Добавить();
КомандаПечати.Идентификатор = "ПФ_ПриказОПереводе";
КомандаПечати.Представление = НСтр("ru = 'Приказ о переводе'");
КомандаПечати.Порядок = 30;
КонецПроцедуры
Процедура Печать(МассивОбъектов, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
Если УправлениеПечатью.НужноПечататьМакет(КоллекцияПечатныхФорм, "ПФ_ПриказОПереводе") Тогда
УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(
КоллекцияПечатныхФорм,
"ПФ_ПриказОПереводе",
НСтр("ru = 'Приказ о переводе'"),
ПриказОПереводе(МассивОбъектов, ОбъектыПечати),
,
"Документ.КадровыйПеревод.ПФ_ПриказОПереводе"
);
КонецЕсли;
КонецПроцедуры
Важный момент, выявленный в ходе обсуждения: несовпадение идентификаторов.
В первоначальном варианте кода, предоставленном автором, в функции ДобавитьКоманду идентификатор команды был "ПриказОПереводе1", в то время как в процедуре Печать для обращения к макету использовался идентификатор "ПФ_ПриказОПереводе". Система 1С, основанная на БСП (Библиотека Стандартных Подсистем), использует эти идентификаторы для связки команды печати с соответствующим макетом. Если они не совпадают, то команда печати не сможет найти свой макет, и табличный документ не будет сформирован.
СведенияОВнешнейОбработке, при добавлении команды с помощью ДобавитьКоманду, мы указываем уникальный идентификатор для нашей печатной формы:
ДобавитьКоманду(Команды, "Приказ О Переводе1", "ПФ_ПриказОПереводе", "ВызовСерверногоМетода", Ложь, "ПечатьMXL");
Здесь "ПФ_ПриказОПереводе" - это тот самый идентификатор.
ДобавитьКомандыПечати мы также регистрируем эту команду, указывая тот же идентификатор:
КомандаПечати.Идентификатор = "ПФ_ПриказОПереводе";
КомандаПечати.Представление = НСтр("ru = 'Приказ о переводе'");
Печать, когда мы хотим вывести табличный документ, мы обращаемся к нему по этому же идентификатору:
Если УправлениеПечатью.НужноПечататьМакет(КоллекцияПечатныхФорм, "ПФ_ПриказОПереводе") Тогда
УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(
КоллекцияПечатныхФорм,
"ПФ_ПриказОПереводе",
// ... другие параметры
);
КонецЕсли;
Убедитесь, что все три места используют ОДИНАКОВЫЙ идентификатор. В представленном нами примере кода эти идентификаторы уже скорректированы, и они совпадают. Если после исправления этой ошибки табличный документ все еще не формируется, значит, проблема кроется глубже – скорее всего, в логике получения и обработки данных.
Функция УправлениеПечатью.НужноПечататьМакет() проверяет, действительно ли запрошена печать именно этого макета. Если она вернет Ложь, весь блок формирования табличного документа будет пропущен. Убедитесь, что в списке запрашиваемых к печати форм (передается в КоллекцияПечатныхФорм) присутствует элемент с идентификатором "ПФ_ПриказОПереводе".
Сердцем любой печатной формы является функция, которая непосредственно формирует табличный документ, заполняя его данными и выводя области макета. В нашем случае это функция ПриказОПереводе(МассивОбъектов, ОбъектыПечати).
Функция ПриказОПереводе(МассивОбъектов, ОбъектыПечати) Экспорт
ДокументРезультат = Новый ТабличныйДокумент;
ДокументРезультат.АвтоМасштаб = Истина;
ДокументРезультат.ОриентацияСтраницы = ОриентацияСтраницы.Портрет;
ДокументРезультат.КлючПараметровПечати = "ПАРАМЕТРЫ_ПЕЧАТИ_КадровыйПеревод";
КлючВарианта = "Т5";
ОбъектОтчета = Отчеты.ПечатнаяФормаТ5.Создать();
НастройкиОтчетаКД = Неопределено;
ПользовательскиеНастройкиКД = Неопределено;
ЗарплатаКадрыОтчеты.ИнициализироватьНастройкиОтчета(ОбъектОтчета, "", КлючВарианта, НастройкиОтчетаКД, ПользовательскиеНастройкиКД);
Если НастройкиОтчетаКД = Неопределено Тогда
НастройкиОтчетаКД = ОбъектОтчета.СхемаКомпоновкиДанных.ВариантыНастроек[КлючВарианта].Настройки;
КонецЕсли;
ОбъектОтчета.КомпоновщикНастроек.ЗагрузитьНастройки(НастройкиОтчетаКД);
Если ТипЗнч(ПользовательскиеНастройкиКД) = Тип("ПользовательскиеНастройкиКомпоновкиДанных") Тогда
ОбъектОтчета.КомпоновщикНастроек.ЗагрузитьПользовательскиеНастройки(ПользовательскиеНастройкиКД);
КонецЕсли;
ЗарплатаКадрыОтчеты.УстановитьПараметрОтбора(ОбъектОтчета, МассивОбъектов);
РезультатКомпоновки = ЗарплатаКадрыОтчеты.РезультатКомпоновкиМакетаПечатнойФормы(ОбъектОтчета, , , , );
Таблица = РезультатКомпоновки.ДанныеОтчета.Строки[0].Строки; // Обратите внимание на этот момент
Макет = ПолучитьМакет("ПФ_ПриказОПереводе");
Запрос = Новый Запрос;
Запрос.Текст = "
|ВЫБРАТЬ
| КадровыйПеревод.Ссылка КАК Ссылка,
| КадровыйПеревод.ДатаНачала КАК ДатаНачала,
| КадровыйПеревод.ДатаОкончания КАК ДатаОкончания,
| КадровыйПеревод.Сотрудник КАК Сотрудник,
| КадровыйПеревод.Организация КАК Организация,
| ФД_РеестрРаспорядительныхДокументов.РаспорядительныйДокумент.ТипПриказа КАК ТипПриказа,
| ФД_РеестрРаспорядительныхДокументов.РаспорядительныйДокумент.ДатаРД КАК Дата,
| ФД_РеестрРаспорядительныхДокументов.РаспорядительныйДокумент.НомерРД КАК Номер,
| ФД_РеестрРаспорядительныхДокументов.РаспорядительныйДокумент.ТипПриказа.Город КАК Город,
| ВЫРАЗИТЬ(ФД_РеестрРаспорядительныхДокументов.РаспорядительныйДокумент.ТипПриказа.НазваниеРаспорядитель КАК СТРОКА(500)) КАК НазваниеРаспорядитель
|ПОМЕСТИТЬ ВТДанныеДокумента
|ИЗ
| Документ.КадровыйПеревод КАК КадровыйПеревод
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ФД_РеестрРаспорядительныхДокументов КАК ФД_РеестрРаспорядительныхДокументов
| ПО КадровыйПеревод.Ссылка = ФД_РеестрРаспорядительныхДокументов.ДокументОснование
|ГДЕ
| КадровыйПеревод.Ссылка В(&МассивОбъектов)
|;
|
//////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТДанныеДокумента.Ссылка КАК Ссылка,
| ВТДанныеДокумента.НазваниеРаспорядитель КАК НазваниеРаспорядитель,
| ВТДанныеДокумента.ДатаНачала КАК ДатаНачала,
| ВТДанныеДокумента.ДатаОкончания КАК ДатаОкончания,
| ВТДанныеДокумента.Сотрудник КАК Сотрудник,
| ВТДанныеДокумента.Организация КАК Организация,
| ВТДанныеДокумента.ТипПриказа КАК ТипПриказа,
| ВТДанныеДокумента.Дата КАК Дата,
| ВТДанныеДокумента.Номер КАК Номер,
| ВТДанныеДокумента.Город КАК Город,
| МАКСИМУМ(РегистрСведений.ПериодЗаписи) КАК ПериодЗаписи
|ПОМЕСТИТЬ ВТДолжности
|ИЗ
| ВТДанныеДокумента КАК ВТДанныеДокумента
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КадроваяИсторияСотрудниковИнтервальный КАК РегистрСведений
| ПО ВТДанныеДокумента.Сотрудник = РегистрСведений.Сотрудник
| И (НАЧАЛОПЕРИОДА(РегистрСведений.ДатаНачала, ДЕНЬ) = КОНЕЦПЕРИОДА(ВЫБОР
| КОГДА ВТДанныеДокумента.ДатаНачала = ДАТАВРЕМЯ(1, 1, 1)
| ТОГДА ДАТАВРЕМЯ(3999, 12, 31, 23, 59, 59)
| ИНАЧЕ ВТДанныеДокумента.ДатаНачала
| КОНЕЦ, ДЕНЬ))
|
|СГРУППИРОВАТЬ ПО
| ВТДанныеДокумента.Город,
| ВТДанныеДокумента.НазваниеРаспорядитель,
| ВТДанныеДокумента.Сотрудник,
| ВТДанныеДокумента.ДатаНачала,
| ВТДанныеДокумента.ДатаОкончания,
| ВТДанныеДокумента.Дата,
| ВТДанныеДокумента.Ссылка,
| ВТДанныеДокумента.Организация,
| ВТДанныеДокумента.ТипПриказа,
| ВТДанныеДокумента.Номер
|;
|
//////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТДолжности.Ссылка КАК Ссылка,
| ВТДолжности.НазваниеРаспорядитель КАК НазваниеРаспорядитель,
| ВТДолжности.ДатаНачала КАК ДатаНачала,
| ВТДолжности.ДатаОкончания КАК ДатаОкончания,
| ВТДолжности.Сотрудник КАК Сотрудник,
| ВТДолжности.Организация КАК Организация,
| ВТДолжности.ТипПриказа КАК ТипПриказа,
| ВТДолжности.Дата КАК Дата,
| ВТДолжности.Номер КАК Номер,
| ВТДолжности.Город КАК Город,
| РегистрСведений.Должность КАК Должность,
| РегистрСведений.Подразделение КАК Подразделение
|ПОМЕСТИТЬ ВТ_СотрудникДолжность
|ИЗ
| ВТДолжности КАК ВТДолжности
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КадроваяИсторияСотрудниковИнтервальный КАК РегистрСведений
| ПО ВТДолжности.Сотрудник = РегистрСведений.Сотрудник
| И (НАЧАЛОПЕРИОДА(РегистрСведений.ДатаНачала, ДЕНЬ) = КОНЕЦПЕРИОДА(ВЫБОР
| КОГДА ВТДолжности.ДатаНачала = ДАТАВРЕМЯ(1, 1, 1)
| ТОГДА ДАТАВРЕМЯ(3999, 12, 31, 23, 59, 59)
| ИНАЧЕ ВТДолжности.ДатаНачала
| КОНЕЦ, ДЕНЬ))
| И ВТДолжности.ПериодЗаписи = РегистрСведений.ПериодЗаписи
|;
|
//////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| МАКСИМУМ(ФД_ПодписантыСотрудников.Период) КАК Период,
| ФД_ПодписантыСотрудников.Сотрудник КАК Сотрудник,
| ВТДоки.Ссылка КАК Ссылка
|ПОМЕСТИТЬ ВТ_МаксПодписант
|ИЗ
| ВТ_СотрудникДолжность КАК ВТДоки
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ФД_ПодписантыСотрудников КАК ФД_ПодписантыСотрудников
| ПО ВТДоки.Сотрудник = ФД_ПодписантыСотрудников.Сотрудник
| И ВТДоки.ДатаНачала >= ФД_ПодписантыСотрудников.Период
|
|СГРУППИРОВАТЬ ПО
| ФД_ПодписантыСотрудников.Сотрудник,
| ВТДоки.Ссылка
|;
|
//////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_МаксПодписант.Сотрудник КАК Сотрудник,
| ВТ_МаксПодписант.Ссылка КАК Ссылка,
| ФД_ПодписантыСотрудников.Подписант КАК Подписант
|ПОМЕСТИТЬ ВТ_Подписант
|ИЗ
| ВТ_МаксПодписант КАК ВТ_МаксПодписант
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ФД_ПодписантыСотрудников КАК ФД_ПодписантыСотрудников
| ПО ВТ_МаксПодписант.Период = ФД_ПодписантыСотрудников.Период
| И ВТ_МаксПодписант.Сотрудник = ФД_ПодписантыСотрудников.Сотрудник
|;
|
//////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_ПредварительнаяТаблица.Ссылка КАК Ссылка,
| ВТ_ПредварительнаяТаблица.Подразделение КАК Подразделение,
| МАКСИМУМ(ФД_КурирующиеЗаместители.Период) КАК Период,
| ВТ_ПредварительнаяТаблица.Организация КАК Организация
|ПОМЕСТИТЬ ВТ_КурирующиеМаксПериод
|ИЗ
| ВТ_СотрудникДолжность КАК ВТ_ПредварительнаяТаблица
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ФД_КурирующиеЗаместители КАК ФД_КурирующиеЗаместители
| ПО ВТ_ПредварительнаяТаблица.ДатаНачала >= ФД_КурирующиеЗаместители.Период
| И ВТ_ПредварительнаяТаблица.Подразделение = ФД_КурирующиеЗаместители.Подразделение
| И ВТ_ПредварительнаяТаблица.Организация = ФД_КурирующиеЗаместители.Организация
|
|СГРУППИРОВАТЬ ПО
| ВТ_ПредварительнаяТаблица.Ссылка,
| ВТ_ПредварительнаяТаблица.Подразделение,
| ВТ_ПредварительнаяТаблица.Организация
|;
|
//////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_КурирующиеМаксПериод.Ссылка КАК Ссылка,
| ВТ_КурирующиеМаксПериод.Подразделение КАК Подразделение,
| ВТ_КурирующиеМаксПериод.Организация КАК Организация,
| ФД_КурирующиеЗаместители.КурирующийЗаместитель КАК КурирующийЗаместитель
|ПОМЕСТИТЬ ВТ_Курирующие
|ИЗ
| ВТ_КурирующиеМаксПериод КАК ВТ_КурирующиеМаксПериод
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ФД_КурирующиеЗаместители КАК ФД_КурирующиеЗаместители
| ПО ВТ_КурирующиеМаксПериод.Подразделение = ФД_КурирующиеЗаместители.Подразделение
| И ВТ_КурирующиеМаксПериод.Организация = ФД_КурирующиеЗаместители.Организация
| И ВТ_КурирующиеМаксПериод.Период = ФД_КурирующиеЗаместители.Период
|;
|
//////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| МАКСИМУМ(СведенияОбОтветственныхЛицах.Период) КАК Период,
| ВТ_ПредварительнаяТаблица.Организация КАК Организация,
| ВТ_ПредварительнаяТаблица.Ссылка КАК Ссылка
|ПОМЕСТИТЬ ВТ_ОтветственныеМакс
|ИЗ
| РегистрСведений.СведенияОбОтветственныхЛицах КАК СведенияОбОтветственныхЛицах
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_СотрудникДолжность КАК ВТ_ПредварительнаяТаблица
| ПО СведенияОбОтветственныхЛицах.Организация = ВТ_ПредварительнаяТаблица.Организация
| И СведенияОбОтветственныхЛицах.Период = КОНЕЦПЕРИОДА(ВЫБОР
| КОГДА ВТ_СотрудникДолжность.ДатаНачала = ДАТАВРЕМЯ(1, 1, 1)
| ТОГДА ДАТАВРЕМЯ(3999, 12, 31, 23, 59, 59)
| ИНАЧЕ ВТ_СотрудникДолжность.ДатаНачала
| КОНЕЦ, ДЕНЬ))
|
|СГРУППИРОВАТЬ ПО
| ВТ_СотрудникДолжность.Должность,
| ВТ_СотрудникДолжность.НазваниеРаспорядитель,
| ВТ_СотрудникДолжность.Дата,
| ВТ_СотрудникДолжность.Номер,
| ВТ_СотрудникДолжность.ДатаНачала,
| ВТ_СотрудникДолжность.ДатаОкончания,
| ВТ_СотрудникДолжность.Подразделение,
| ВТ_СотрудникДолжность.Подписант,
| ВТ_СотрудникДолжность.Город,
| ВТ_СотрудникДолжность.Ссылка,
| ВТ_СотрудникДолжность.ТипПриказа,
| ВТ_СотрудникДолжность.Организация,
| ВТ_СотрудникДолжность.Сотрудник
|;
|
//////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_Подписант.Ссылка КАК Ссылка,
| ВТ_Подписант.НазваниеРаспорядитель КАК НазваниеРаспорядитель,
| ВТ_Подписант.Сотрудник.Наименование КАК Сотрудник,
| ВТ_Подписант.Организация КАК Организация,
| ВТ_Подписант.ДатаНачала КАК ДатаНачала,
| ВТ_Подписант.ДатаОкончания КАК ДатаОкончания,
| ВТ_Подписант.ТипПриказа КАК ВидДокумента,
| ВТ_Подписант.Дата КАК Дата,
| ВТ_Подписант.Номер КАК Номер,
| ВТ_Подписант.Подписант КАК Подписант,
| ВТ_Подписант.Город КАК Город,
| ВТ_Подписант.Должность КАК Должность,
| РегистрСведений.Должность КАК ДолжностьПодписанта,
| ВТ_Подписант.Подразделение КАК Подразделение
|ИЗ
| ВТ_ПодписантИтоги КАК ВТ_Подписант // Предполагается, что ВТ_ПодписантИтоги ранее была определена
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КадроваяИсторияСотрудниковИнтервальный КАК РегистрСведений
| ПО ВТ_Подписант.Подписант = РегистрСведений.Сотрудник
| И ВТ_Подписант.ПериодЗаписи = РегистрСведений.ПериодЗаписи
| И (НАЧАЛОПЕРИОДА(РегистрСведений.ДатаНачала, ДЕНЬ) = КОНЕЦПЕРИОДА(ВЫБОР
| КОГДА ВТ_Подписант.ДатаНачала = ДАТАВРЕМЯ(1, 1, 1)
| ТОГДА ДАТАВРЕМЯ(3999, 12, 31, 23, 59, 59)
| ИНАЧЕ ВТ_Подписант.ДатаНачала
| КОНЕЦ, ДЕНЬ))";
Запрос.УстановитьПараметр("МассивОбъектов", МассивОбъектов);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Сч = 0;
Пока Выборка.Следующий() Цикл
Область = Макет.ПолучитьОбласть("Шапка");
Область.Параметры.Заполнить(Выборка); // Заполняем параметры области из выборки запроса
Область.Параметры.ТипПриказа = ВРег(Выборка.ВидДокумента);
Область.Параметры.Дата = Формат(Выборка.Дата, "ДФ=dd.MM.yyyy");
Область.Параметры.НазваниеРаспорядитель = ?(ЗначениеЗаполнено(Выборка.НазваниеРаспорядитель), Выборка.НазваниеРаспорядитель, Выборка.Организация);
Область.Параметры.Сотрудник = СклонениеПредставленийОбъектов.ПросклонятьФИО(Строка(Выборка.Сотрудник), 4, Выборка.Сотрудник);
Область.Параметры.ДолжностьПрошлая = СклонениеПредставленийОбъектов.ПросклонятьФИО(Строка(Таблица[Сч].РаботаДолжностьПрежняя), 2, Таблица[Сч].РаботаДолжностьПрежняя); // !!! Потенциальная ошибка
Область.Параметры.ДолжностьНовая = СклонениеПредставленийОбъектов.ПросклонятьФИО(Строка(Выборка.Должность), 2, Выборка.Должность);
Область.Параметры.ПодразделениеНовое = СклонениеПредставленийОбъектов.ПросклонятьФИО(Строка(Выборка.Подразделение), 2, Выборка.Подразделение);
Область.Параметры.ПодразделениеПрошлое = СклонениеПредставленийОбъектов.ПросклонятьФИО(Строка(Таблица[Сч].РаботаПодразделениеПрежнееНаПечать), 2, Таблица[Сч].РаботаПодразделениеПрежнееНаПечать); // !!! Потенциальная ошибка
Область.Параметры.ДатаНачала = Формат(Выборка.ДатаНачала, "ДФ=dd.MM.yyyy");
//Область.Параметры.ДатаОкончания = Формат(Выборка.ДатаОкончания, "ДФ=dd.MM.yyyy"); // Закомментированная строка
Область.Параметры.Подписант = ФизическиеЛицаКлиентСервер.ФамилияИнициалы(Строка(Выборка.Подписант));
ДокументРезультат.Вывести(Область);
ДокументРезультат.ВывестиГоризонтальныйРазделительСтраниц();
Сч = Сч + 1;
КонецЦикла;
Возврат ДокументРезультат;
КонецФункции
Разберем логику этой функции по частям:
ДокументРезультат = Новый ТабличныйДокумент; - это первое, что мы делаем, создавая новый табличный документ. Установка свойств АвтоМасштаб, ОриентацияСтраницы, КлючПараметровПечати важна для корректного отображения и сохранения настроек печати.
Часть кода использует отчет Отчеты.ПечатнаяФормаТ5 и связанные с ним функции из общего модуля ЗарплатаКадрыОтчеты. Это стандартный подход в конфигурациях 1С (например, ЗУП), когда основная логика формирования сложных печатных форм выносится в СКД отчетов. Здесь происходит инициализация настроек отчета, загрузка стандартных и пользовательских настроек, установка параметров отбора (МассивОбъектов) и, наконец, выполнение компоновки для получения результата (РезультатКомпоновки).
Потенциальная проблема: Несмотря на то, что результат СКД получается в РезультатКомпоновки, далее в коде используются данные из прямого запроса. Строка Таблица = РезультатКомпоновки.ДанныеОтчета.Строки[0].Строки; предполагает, что в результате СКД есть данные, и они имеют определенную структуру. Если этот путь получения данных не используется или структура РезультатКомпоновки не соответствует ожиданиям, это может привести к ошибкам (например, "Индекс находится за границами массива").
Основная часть данных для заполнения макета получается через сложный SQL-запрос. Этот запрос использует несколько временных таблиц (ВТДанныеДокумента, ВТДолжности, ВТ_СотрудникДолжность, ВТ_МаксПодписант, ВТ_Подписант, ВТ_КурирующиеМаксПериод, ВТ_Курирующие, ВТ_ОтветственныеМакс) для сбора информации из документа "КадровыйПеревод" и различных регистров сведений, таких как ФД_РеестрРаспорядительныхДокументов, КадроваяИсторияСотрудниковИнтервальный, ФД_ПодписантыСотрудников, ФД_КурирующиеЗаместители, СведенияОбОтветственныхЛицах.
Ключевой момент: Последний блок запроса (ВЫБРАТЬ ИЗ ВТ_ПодписантИтоги) ссылается на временную таблицу ВТ_ПодписантИтоги, которая не была определена в предыдущих блоках запроса. Это является грубой ошибкой в синтаксисе запроса и приведет к тому, что запрос не будет выполнен, а РезультатЗапроса.Выбрать() вернет пустую выборку. В таком случае цикл Пока Выборка.Следующий() Цикл не выполнится ни разу, и табличный документ останется пустым.
Решение: Внимательно проверьте, все ли временные таблицы, используемые в запросе, действительно объявлены с помощью ПОМЕСТИТЬ. Вероятно, ВТ_ПодписантИтоги должно быть либо ВТ_Подписант, либо результат ранее пропущенной временной таблицы.
После выполнения запроса мы получаем макет "ПФ_ПриказОПереводе" и в цикле перебираем строки результата запроса. Для каждой строки происходит следующее:
Область = Макет.ПолучитьОбласть("Шапка");: Получаем область макета, которая будет выводиться. Убедитесь, что область с именем "Шапка" действительно существует в макете.Область.Параметры.Заполнить(Выборка);: Автоматически заполняет параметры области, имена которых совпадают с именами полей в выборке запроса. Это очень удобно, но не всегда достаточно.ТипПриказа (с преобразованием в верхний регистр), Дата (с форматированием), Сотрудник, ДолжностьПрошлая, ДолжностьНовая и т.д. Здесь используются вспомогательные функции СклонениеПредставленийОбъектов.ПросклонятьФИО и ФизическиеЛицаКлиентСервер.ФамилияИнициалы для склонения ФИО и должностей, что типично для кадрового учета.ДокументРезультат.Вывести(Область);: Выводит сформированную область в табличный документ.ДокументРезультат.ВывестиГоризонтальныйРазделительСтраниц();: Размещает принудительный разрыв страницы после каждой выведенной области.Потенциальные проблемы при заполнении макета:
Область.Параметры.ТипПриказа) точно соответствуют именам параметров, определенных в самой области макета. Регистр букв имеет значение.Таблица[Сч]: Строки Таблица[Сч].РаботаДолжностьПрежняя и Таблица[Сч].РаботаПодразделениеПрежнееНаПечать предполагают, что переменная Таблица содержит коллекцию объектов, а индекс Сч находится в ее пределах. Переменная Таблица была получена из РезультатКомпоновки.ДанныеОтчета.Строки[0].Строки;. Если СКД не вернула данных или ее структура отличается от ожидаемой, то Таблица может быть пустой, и обращение по индексу Таблица[Сч] (особенно при Сч = 0 в первой итерации) приведет к ошибке. Проверьте содержимое Таблица в отладчике. Возможно, данные для этих полей должны были прийти из основной выборки Выборка, а не из отдельной таблицы, полученной из СКД.Выборка.Дата или Выборка.Сотрудник) окажется пустым или Неопределено, это может вызвать ошибку при форматировании или вызове вспомогательных функций, которые ожидают определенный тип данных.Если после исправления идентификаторов печатная форма все еще не формируется, наиболее вероятная причина кроется в получении данных. Нам предстоит тщательно проанализировать запрос и убедиться, что он возвращает ожидаемые данные.
Самый эффективный способ – использовать отладчик 1С. Установите точки останова в следующих местах:
Запрос.Выполнить();.РезультатЗапроса = Запрос.Выполнить();.Пока Выборка.Следующий() Цикл.Пошагово выполняя код, вы сможете проверить:
МассивОбъектов – действительно ли в нем есть ссылки на документы, которые мы хотим распечатать.Запрос.Текст – просмотрите текст запроса перед его выполнением, чтобы убедиться в его корректности.РезультатЗапроса – после выполнения запроса проверьте, пуст ли он (РезультатЗапроса.Пустой()) или содержит ли ожидаемое количество строк (РезультатЗапроса.Количество()).Выборка – на каждой итерации цикла проверяйте, какие значения приходят в переменные выборки (Выборка.Ссылка, Выборка.Дата, Выборка.Сотрудник и т.д.).Если РезультатЗапроса пуст, то табличный документ не будет заполнен. Это указывает на проблему в самом запросе.
Как мы уже упоминали, в предоставленном запросе есть явная ошибка: обращение к неопределенной временной таблице ВТ_ПодписантИтоги. Это необходимо исправить. Помимо этого, рассмотрим другие возможные проблемы:
МассивОбъектов: Если параметр &МассивОбъектов пуст, условие ГДЕ КадровыйПеревод.Ссылка В(&МассивОбъектов) не сработает, и запрос вернет пустой результат.ВНУТРЕННЕЕ СОЕДИНЕНИЕ, ЛЕВОЕ СОЕДИНЕНИЕ) могут быть причиной отсутствия данных.
ВНУТРЕННЕЕ СОЕДИНЕНИЕ, а данные в одной из таблиц отсутствуют для текущего документа, вся строка будет отфильтрована.ПО ...): корректно ли связаны поля? Например, РегистрСведений.ПериодЗаписи = КОНЕЦПЕРИОДА(...) – убедитесь, что логика сравнения периодов верна.ГДЕ или ИМЕЮЩИЕ: Любое некорректное условие фильтрации может привести к тому, что запрос не найдет ни одной записи.ФД_РеестрРаспорядительныхДокументов, КадроваяИсторияСотрудниковИнтервальный, ФД_ПодписантыСотрудников, ФД_КурирующиеЗаместители, СведенияОбОтветственныхЛицах), и убедитесь, что для ваших тестовых документов "КадровыйПеревод" там есть соответствующие записи.НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА должны использоваться аккуратно, чтобы не отфильтровать нужные записи. Проверьте их применение.Скопируйте текст запроса в консоль запросов (доступную через внешнюю обработку или в режиме отладки). Подставьте тестовые значения для параметра &МассивОбъектов. Это позволит быстро проверить корректность запроса и его результат без перезапуска всей печатной формы.
Даже если запрос вернул данные, табличный документ может остаться пустым или выглядеть некорректно, если есть ошибки при заполнении областей макета.
Мы уже упоминали об этом: имена параметров в коде Область.Параметры.ИмяПараметра должны точно совпадать с именами параметров, которые вы задали в макете через Конфигуратор (в свойствах ячейки или группы ячеек). Проверьте регистр букв и отсутствие опечаток.
Таблица[Сч]):
В нашем случае, строки Область.Параметры.ДолжностьПрошлая = СклонениеПредставленийОбъектов.ПросклонятьФИО(Строка(Таблица[Сч].РаботаДолжностьПрежняя), ...) могут вызвать ошибку, если переменная Таблица пуста или индекс Сч выходит за ее пределы. Проверьте в отладчике содержимое Таблица после выполнения строки Таблица = РезультатКомпоновки.ДанныеОтчета.Строки[0].Строки;. Возможно, требуется дополнительная проверка на заполненность Таблица или изменение логики получения данных для РаботаДолжностьПрежняя и РаботаПодразделениеПрежнееНаПечать.
Если в Выборка.Дата пришло Неопределено или пустая дата, функция Формат(Выборка.Дата, "ДФ=dd.MM.yyyy") может вызвать ошибку. Аналогично, если Выборка.Сотрудник или Выборка.Подписант пусты, функции склонения и форматирования ФИО (СклонениеПредставленийОбъектов.ПросклонятьФИО, ФизическиеЛицаКлиентСервер.ФамилияИнициалы) могут работать некорректно или возвращать пустую строку. Рекомендуется использовать проверки на ЗначениеЗаполнено() перед такими вызовами.
Иногда табличный документ формируется, но отображается пустая страница или только статические данные без параметров. Убедитесь, что вызов ДокументРезультат.Вывести(Область) действительно происходит внутри цикла. Также, если вы используете несколько областей, проверьте их последовательность вывода. Метод ПроверитьВывод() табличного документа может помочь диагностировать проблемы с переполнением страницы или наложением областей, но его нужно использовать аккуратно, обычно в отладочных целях.
Для эффективной работы с внешними печатными формами придерживайтесь следующих рекомендаций:
СведенияОВнешнейОбработке, Печать, ПриказОПереводе, внутри цикла заполнения макета и перед выполнением запроса.Сообщить(): В сложных местах кода, особенно при работе с запросами или вызовами внешних функций, используйте Сообщить(Переменная) или Сообщить(ТипЗнч(Переменная)) для вывода текущих значений переменных и их типов. Это поможет быстро понять, какие данные поступают на входы функций и что возвращается.Попытка...Исключение: Для отладки и обработки потенциальных ошибок, особенно при работе с внешними компонентами или сложными преобразованиями, оборачивайте проблемные участки кода в конструкцию Попытка...Исключение. Это позволит перехватывать ошибки и выводить их в сообщения, не прерывая выполнение.
Попытка
// Ваш код, который может вызвать ошибку
Область.Параметры.ДолжностьПрошлая = СклонениеПредставленийОбъектов.ПросклонятьФИО(Строка(Таблица[Сч].РаботаДолжностьПрежняя), 2, Таблица[Сч].РаботаДолжностьПрежняя);
Исключение
Сообщить("Ошибка при заполнении ДолжностьПрошлая: " + ОписаниеОшибки());
// Дополнительные действия, например, пропустить заполнение этого параметра
КонецПопытки;
Решение проблемы неформирования табличного документа во внешней печатной форме – это, как правило, последовательная диагностика. Начните с самых общих мест (регистрация, обработчик Печать) и постепенно углубляйтесь в логику формирования данных (запрос) и заполнения макета. Внимательный анализ кода и систематическая отладка обязательно помогут вам выявить и устранить причину проблемы.