Почему внешняя печатная форма документа "КадровыйПеревод" не формирует табличный документ?

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом
← На главную

При разработке внешних печатных форм для документов 1С:Предприятия 8.3 пользователи нередко сталкиваются с ситуацией, когда табличный документ не формируется или выводится пустым, несмотря на, казалось бы, корректный код. Рассмотрим подробно основные причины такой проблемы на примере внешней печатной формы для документа "КадровыйПеревод" и разберем по шагам, как диагностировать и устранить подобные неполадки.

Наша цель – понять, почему печатная форма не выводится, и выявить типичные ошибки, которые могут к этому привести. Мы проанализируем процесс регистрации внешней обработки, логику обработчика печати и функцию формирования самого табличного документа, а также уделим особое внимание отладке запросов и заполнению макета.

1. Регистрация внешней печатной формы и обработчик печати

Первым шагом при работе с внешними печатными формами является их корректная регистрация в системе. Система 1С использует функцию СведенияОВнешнейОбработке для получения метаданных о печатной форме, а затем обрабатывает запрос на печать в специальной процедуре Печать.

Начнем с кода, отвечающего за регистрацию и вызов печатной формы:


Функция СведенияОВнешнейОбработке() Экспорт
    ПараметрыРегистрации = Новый Структура;
    ПараметрыРегистрации.Вставить("Вид", "ПечатнаяФорма");
    ПараметрыРегистрации.Вставить("Назначение", ПолучитьНазначениеОбработки());
    ПараметрыРегистрации.Вставить("Наименование", "Приказ о переводе");
    ПараметрыРегистрации.Вставить("Версия", "1.0");
    ПараметрыРегистрации.Вставить("Информация", "Приказ о переводе");
    ПараметрыРегистрации.Вставить("БезопасныйРежим", Ложь);

    Команды = ПолучитьТаблицуКоманд();
    ДобавитьКоманду(Команды, "Приказ О Переводе1", "ПФ_ПриказОПереводе", "ВызовСерверногоМетода", Ложь, "ПечатьMXL");
    ПараметрыРегистрации.Вставить("Команды", Команды);

    Возврат ПараметрыРегистрации;
КонецФункции

Функция ПолучитьНазначениеОбработки()
    Массив = Новый Массив;
    Массив.Добавить("Документ.КадровыйПеревод");
    Возврат Массив;
КонецФункции

Функция ПолучитьТаблицуКоманд()
    Команды = Новый ТаблицаЗначений;
    Команды.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка"));
    Команды.Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("Строка"));
    Команды.Колонки.Добавить("Использование", Новый ОписаниеТипов("Строка"));
    Команды.Колонки.Добавить("ПоказыватьОповещение", Новый ОписаниеТипов("Булево"));
    Команды.Колонки.Добавить("Модификатор", Новый ОписаниеТипов("Строка"));
    Возврат Команды;
КонецФункции

Процедура ДобавитьКоманду(ТаблицаКоманд, Представление, Идентификатор, Использование, ПоказыватьОповещение = Ложь, Модификатор = "")
    НоваяКоманда = ТаблицаКоманд.Добавить();
    НоваяКоманда.Представление = Представление;
    НоваяКоманда.Использование = Использование;
    НоваяКоманда.ПоказыватьОповещение = ПоказыватьОповещение;
    НоваяКоманда.Модификатор = Модификатор;
    НоваяКоманда.Идентификатор = Идентификатор;
КонецПроцедуры

//Печать ПФ
Процедура ДобавитьКомандыПечати(КомандыПечати) Экспорт
    КомандаПечати = КомандыПечати.Добавить();
    КомандаПечати.Идентификатор = "ПФ_ПриказОПереводе";
    КомандаПечати.Представление = НСтр("ru = 'Приказ о переводе'");
    КомандаПечати.Порядок = 30;
КонецПроцедуры

Процедура Печать(МассивОбъектов, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
    Если УправлениеПечатью.НужноПечататьМакет(КоллекцияПечатныхФорм, "ПФ_ПриказОПереводе") Тогда
        УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(
            КоллекцияПечатныхФорм, 
            "ПФ_ПриказОПереводе", 
            НСтр("ru = 'Приказ о переводе'"), 
            ПриказОПереводе(МассивОбъектов, ОбъектыПечати), 
            , 
            "Документ.КадровыйПеревод.ПФ_ПриказОПереводе"
        );
    КонецЕсли;
КонецПроцедуры

Важный момент, выявленный в ходе обсуждения: несовпадение идентификаторов.

В первоначальном варианте кода, предоставленном автором, в функции ДобавитьКоманду идентификатор команды был "ПриказОПереводе1", в то время как в процедуре Печать для обращения к макету использовался идентификатор "ПФ_ПриказОПереводе". Система 1С, основанная на БСП (Библиотека Стандартных Подсистем), использует эти идентификаторы для связки команды печати с соответствующим макетом. Если они не совпадают, то команда печати не сможет найти свой макет, и табличный документ не будет сформирован.

  1. В функции СведенияОВнешнейОбработке, при добавлении команды с помощью ДобавитьКоманду, мы указываем уникальный идентификатор для нашей печатной формы:
  2. 
    ДобавитьКоманду(Команды, "Приказ О Переводе1", "ПФ_ПриказОПереводе", "ВызовСерверногоМетода", Ложь, "ПечатьMXL");
    

    Здесь "ПФ_ПриказОПереводе" - это тот самый идентификатор.

  3. В процедуре ДобавитьКомандыПечати мы также регистрируем эту команду, указывая тот же идентификатор:
  4. 
    КомандаПечати.Идентификатор = "ПФ_ПриказОПереводе";
    КомандаПечати.Представление = НСтр("ru = 'Приказ о переводе'");
    
  5. И, наконец, в процедуре Печать, когда мы хотим вывести табличный документ, мы обращаемся к нему по этому же идентификатору:
  6. 
    Если УправлениеПечатью.НужноПечататьМакет(КоллекцияПечатныхФорм, "ПФ_ПриказОПереводе") Тогда
        УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(
            КоллекцияПечатныхФорм, 
            "ПФ_ПриказОПереводе", 
            // ... другие параметры
        );
    КонецЕсли;
    

Убедитесь, что все три места используют ОДИНАКОВЫЙ идентификатор. В представленном нами примере кода эти идентификаторы уже скорректированы, и они совпадают. Если после исправления этой ошибки табличный документ все еще не формируется, значит, проблема кроется глубже – скорее всего, в логике получения и обработки данных.

Функция УправлениеПечатью.НужноПечататьМакет() проверяет, действительно ли запрошена печать именно этого макета. Если она вернет Ложь, весь блок формирования табличного документа будет пропущен. Убедитесь, что в списке запрашиваемых к печати форм (передается в КоллекцияПечатныхФорм) присутствует элемент с идентификатором "ПФ_ПриказОПереводе".

2. Анализ функции формирования табличного документа "ПриказОПереводе"

Сердцем любой печатной формы является функция, которая непосредственно формирует табличный документ, заполняя его данными и выводя области макета. В нашем случае это функция ПриказОПереводе(МассивОбъектов, ОбъектыПечати).


Функция ПриказОПереводе(МассивОбъектов, ОбъектыПечати) Экспорт
    ДокументРезультат = Новый ТабличныйДокумент;
    ДокументРезультат.АвтоМасштаб = Истина;
    ДокументРезультат.ОриентацияСтраницы = ОриентацияСтраницы.Портрет;
    ДокументРезультат.КлючПараметровПечати = "ПАРАМЕТРЫ_ПЕЧАТИ_КадровыйПеревод";

    КлючВарианта = "Т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;
    КонецЦикла;

    Возврат ДокументРезультат;
КонецФункции

Разберем логику этой функции по частям:

  1. Инициализация табличного документа:

    ДокументРезультат = Новый ТабличныйДокумент; - это первое, что мы делаем, создавая новый табличный документ. Установка свойств АвтоМасштаб, ОриентацияСтраницы, КлючПараметровПечати важна для корректного отображения и сохранения настроек печати.

  2. Использование Системы Компоновки Данных (СКД) отчета:

    Часть кода использует отчет Отчеты.ПечатнаяФормаТ5 и связанные с ним функции из общего модуля ЗарплатаКадрыОтчеты. Это стандартный подход в конфигурациях 1С (например, ЗУП), когда основная логика формирования сложных печатных форм выносится в СКД отчетов. Здесь происходит инициализация настроек отчета, загрузка стандартных и пользовательских настроек, установка параметров отбора (МассивОбъектов) и, наконец, выполнение компоновки для получения результата (РезультатКомпоновки).

    Потенциальная проблема: Несмотря на то, что результат СКД получается в РезультатКомпоновки, далее в коде используются данные из прямого запроса. Строка Таблица = РезультатКомпоновки.ДанныеОтчета.Строки[0].Строки; предполагает, что в результате СКД есть данные, и они имеют определенную структуру. Если этот путь получения данных не используется или структура РезультатКомпоновки не соответствует ожиданиям, это может привести к ошибкам (например, "Индекс находится за границами массива").

  3. Прямой запрос к базе данных:

    Основная часть данных для заполнения макета получается через сложный SQL-запрос. Этот запрос использует несколько временных таблиц (ВТДанныеДокумента, ВТДолжности, ВТ_СотрудникДолжность, ВТ_МаксПодписант, ВТ_Подписант, ВТ_КурирующиеМаксПериод, ВТ_Курирующие, ВТ_ОтветственныеМакс) для сбора информации из документа "КадровыйПеревод" и различных регистров сведений, таких как ФД_РеестрРаспорядительныхДокументов, КадроваяИсторияСотрудниковИнтервальный, ФД_ПодписантыСотрудников, ФД_КурирующиеЗаместители, СведенияОбОтветственныхЛицах.

    Ключевой момент: Последний блок запроса (ВЫБРАТЬ ИЗ ВТ_ПодписантИтоги) ссылается на временную таблицу ВТ_ПодписантИтоги, которая не была определена в предыдущих блоках запроса. Это является грубой ошибкой в синтаксисе запроса и приведет к тому, что запрос не будет выполнен, а РезультатЗапроса.Выбрать() вернет пустую выборку. В таком случае цикл Пока Выборка.Следующий() Цикл не выполнится ни разу, и табличный документ останется пустым.

    Решение: Внимательно проверьте, все ли временные таблицы, используемые в запросе, действительно объявлены с помощью ПОМЕСТИТЬ. Вероятно, ВТ_ПодписантИтоги должно быть либо ВТ_Подписант, либо результат ранее пропущенной временной таблицы.

  4. Заполнение макета:

    После выполнения запроса мы получаем макет "ПФ_ПриказОПереводе" и в цикле перебираем строки результата запроса. Для каждой строки происходит следующее:

    • Область = Макет.ПолучитьОбласть("Шапка");: Получаем область макета, которая будет выводиться. Убедитесь, что область с именем "Шапка" действительно существует в макете.
    • Область.Параметры.Заполнить(Выборка);: Автоматически заполняет параметры области, имена которых совпадают с именами полей в выборке запроса. Это очень удобно, но не всегда достаточно.
    • Далее идет ручное заполнение специфических параметров, таких как ТипПриказа (с преобразованием в верхний регистр), Дата (с форматированием), Сотрудник, ДолжностьПрошлая, ДолжностьНовая и т.д. Здесь используются вспомогательные функции СклонениеПредставленийОбъектов.ПросклонятьФИО и ФизическиеЛицаКлиентСервер.ФамилияИнициалы для склонения ФИО и должностей, что типично для кадрового учета.
    • ДокументРезультат.Вывести(Область);: Выводит сформированную область в табличный документ.
    • ДокументРезультат.ВывестиГоризонтальныйРазделительСтраниц();: Размещает принудительный разрыв страницы после каждой выведенной области.

    Потенциальные проблемы при заполнении макета:

    1. Несоответствие имен параметров: Убедитесь, что имена параметров в коде (например, Область.Параметры.ТипПриказа) точно соответствуют именам параметров, определенных в самой области макета. Регистр букв имеет значение.
    2. Ошибка "Индекс находится за границами массива" при работе с Таблица[Сч]: Строки Таблица[Сч].РаботаДолжностьПрежняя и Таблица[Сч].РаботаПодразделениеПрежнееНаПечать предполагают, что переменная Таблица содержит коллекцию объектов, а индекс Сч находится в ее пределах. Переменная Таблица была получена из РезультатКомпоновки.ДанныеОтчета.Строки[0].Строки;. Если СКД не вернула данных или ее структура отличается от ожидаемой, то Таблица может быть пустой, и обращение по индексу Таблица[Сч] (особенно при Сч = 0 в первой итерации) приведет к ошибке. Проверьте содержимое Таблица в отладчике. Возможно, данные для этих полей должны были прийти из основной выборки Выборка, а не из отдельной таблицы, полученной из СКД.
    3. Пустые значения: Если какое-либо поле выборки (например, Выборка.Дата или Выборка.Сотрудник) окажется пустым или Неопределено, это может вызвать ошибку при форматировании или вызове вспомогательных функций, которые ожидают определенный тип данных.

3. Диагностика и отладка проблем с данными и запросом

Если после исправления идентификаторов печатная форма все еще не формируется, наиболее вероятная причина кроется в получении данных. Нам предстоит тщательно проанализировать запрос и убедиться, что он возвращает ожидаемые данные.

  1. Пошаговая отладка запроса:

    Самый эффективный способ – использовать отладчик 1С. Установите точки останова в следующих местах:

    • Перед Запрос.Выполнить();.
    • Сразу после РезультатЗапроса = Запрос.Выполнить();.
    • В начале цикла Пока Выборка.Следующий() Цикл.

    Пошагово выполняя код, вы сможете проверить:

    • Содержимое МассивОбъектов – действительно ли в нем есть ссылки на документы, которые мы хотим распечатать.
    • Запрос.Текст – просмотрите текст запроса перед его выполнением, чтобы убедиться в его корректности.
    • РезультатЗапроса – после выполнения запроса проверьте, пуст ли он (РезультатЗапроса.Пустой()) или содержит ли ожидаемое количество строк (РезультатЗапроса.Количество()).
    • Выборка – на каждой итерации цикла проверяйте, какие значения приходят в переменные выборки (Выборка.Ссылка, Выборка.Дата, Выборка.Сотрудник и т.д.).

    Если РезультатЗапроса пуст, то табличный документ не будет заполнен. Это указывает на проблему в самом запросе.

  2. Анализ запроса на корректность:

    Как мы уже упоминали, в предоставленном запросе есть явная ошибка: обращение к неопределенной временной таблице ВТ_ПодписантИтоги. Это необходимо исправить. Помимо этого, рассмотрим другие возможные проблемы:

    • Пустой МассивОбъектов: Если параметр &МассивОбъектов пуст, условие ГДЕ КадровыйПеревод.Ссылка В(&МассивОбъектов) не сработает, и запрос вернет пустой результат.
    • Ошибки в соединениях: Сложные соединения (ВНУТРЕННЕЕ СОЕДИНЕНИЕ, ЛЕВОЕ СОЕДИНЕНИЕ) могут быть причиной отсутствия данных.
      • Если используется ВНУТРЕННЕЕ СОЕДИНЕНИЕ, а данные в одной из таблиц отсутствуют для текущего документа, вся строка будет отфильтрована.
      • Проверьте условия соединений (ПО ...): корректно ли связаны поля? Например, РегистрСведений.ПериодЗаписи = КОНЕЦПЕРИОДА(...) – убедитесь, что логика сравнения периодов верна.
    • Ошибки в условиях ГДЕ или ИМЕЮЩИЕ: Любое некорректное условие фильтрации может привести к тому, что запрос не найдет ни одной записи.
    • Отсутствие данных в регистрах: Откройте регистры сведений, к которым обращается запрос (ФД_РеестрРаспорядительныхДокументов, КадроваяИсторияСотрудниковИнтервальный, ФД_ПодписантыСотрудников, ФД_КурирующиеЗаместители, СведенияОбОтветственныхЛицах), и убедитесь, что для ваших тестовых документов "КадровыйПеревод" там есть соответствующие записи.
    • Проблемы с функциями даты: Функции НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА должны использоваться аккуратно, чтобы не отфильтровать нужные записи. Проверьте их применение.
  3. Использование консоли запросов:

    Скопируйте текст запроса в консоль запросов (доступную через внешнюю обработку или в режиме отладки). Подставьте тестовые значения для параметра &МассивОбъектов. Это позволит быстро проверить корректность запроса и его результат без перезапуска всей печатной формы.

4. Проблемы с заполнением макета

Даже если запрос вернул данные, табличный документ может остаться пустым или выглядеть некорректно, если есть ошибки при заполнении областей макета.

  1. Имена параметров макета:

    Мы уже упоминали об этом: имена параметров в коде Область.Параметры.ИмяПараметра должны точно совпадать с именами параметров, которые вы задали в макете через Конфигуратор (в свойствах ячейки или группы ячеек). Проверьте регистр букв и отсутствие опечаток.

  2. Доступность вспомогательных данных (Таблица[Сч]):

    В нашем случае, строки Область.Параметры.ДолжностьПрошлая = СклонениеПредставленийОбъектов.ПросклонятьФИО(Строка(Таблица[Сч].РаботаДолжностьПрежняя), ...) могут вызвать ошибку, если переменная Таблица пуста или индекс Сч выходит за ее пределы. Проверьте в отладчике содержимое Таблица после выполнения строки Таблица = РезультатКомпоновки.ДанныеОтчета.Строки[0].Строки;. Возможно, требуется дополнительная проверка на заполненность Таблица или изменение логики получения данных для РаботаДолжностьПрежняя и РаботаПодразделениеПрежнееНаПечать.

  3. Корректность данных и функций преобразования:

    Если в Выборка.Дата пришло Неопределено или пустая дата, функция Формат(Выборка.Дата, "ДФ=dd.MM.yyyy") может вызвать ошибку. Аналогично, если Выборка.Сотрудник или Выборка.Подписант пусты, функции склонения и форматирования ФИО (СклонениеПредставленийОбъектов.ПросклонятьФИО, ФизическиеЛицаКлиентСервер.ФамилияИнициалы) могут работать некорректно или возвращать пустую строку. Рекомендуется использовать проверки на ЗначениеЗаполнено() перед такими вызовами.

  4. Проблемы с выводом областей:

    Иногда табличный документ формируется, но отображается пустая страница или только статические данные без параметров. Убедитесь, что вызов ДокументРезультат.Вывести(Область) действительно происходит внутри цикла. Также, если вы используете несколько областей, проверьте их последовательность вывода. Метод ПроверитьВывод() табличного документа может помочь диагностировать проблемы с переполнением страницы или наложением областей, но его нужно использовать аккуратно, обычно в отладочных целях.

5. Общие рекомендации по отладке внешней печатной формы

Для эффективной работы с внешними печатными формами придерживайтесь следующих рекомендаций:

  1. Используйте пошаговую отладку: Это самый мощный инструмент для выявления проблем. Устанавливайте точки останова во всех ключевых местах: в СведенияОВнешнейОбработке, Печать, ПриказОПереводе, внутри цикла заполнения макета и перед выполнением запроса.
  2. Создайте тестовый сценарий: Используйте конкретный документ "КадровыйПеревод", для которого вы точно знаете, что данные существуют во всех необходимых регистрах.
  3. Временные сообщения Сообщить(): В сложных местах кода, особенно при работе с запросами или вызовами внешних функций, используйте Сообщить(Переменная) или Сообщить(ТипЗнч(Переменная)) для вывода текущих значений переменных и их типов. Это поможет быстро понять, какие данные поступают на входы функций и что возвращается.
  4. Очистите кэш 1С: Иногда проблемы с внешними обработками могут быть связаны с кэшем. Попробуйте очистить кэш пользователя 1С или кэш конфигурации.
  5. Проверьте права доступа: Убедитесь, что у пользователя, под которым запускается печать, есть все необходимые права для чтения данных из всех документов и регистров, используемых в запросе, а также для доступа к общим модулям и функциям.
  6. Проверьте макет: Откройте макет печатной формы в Конфигураторе и убедитесь, что области и параметры названы корректно, нет опечаток, а сам макет выглядит так, как ожидается.
  7. Используйте блоки Попытка...Исключение: Для отладки и обработки потенциальных ошибок, особенно при работе с внешними компонентами или сложными преобразованиями, оборачивайте проблемные участки кода в конструкцию Попытка...Исключение. Это позволит перехватывать ошибки и выводить их в сообщения, не прерывая выполнение.
  8. 
    Попытка
        // Ваш код, который может вызвать ошибку
        Область.Параметры.ДолжностьПрошлая = СклонениеПредставленийОбъектов.ПросклонятьФИО(Строка(Таблица[Сч].РаботаДолжностьПрежняя), 2, Таблица[Сч].РаботаДолжностьПрежняя);
    Исключение
        Сообщить("Ошибка при заполнении ДолжностьПрошлая: " + ОписаниеОшибки());
        // Дополнительные действия, например, пропустить заполнение этого параметра
    КонецПопытки;
    

Решение проблемы неформирования табличного документа во внешней печатной форме – это, как правило, последовательная диагностика. Начните с самых общих мест (регистрация, обработчик Печать) и постепенно углубляйтесь в логику формирования данных (запрос) и заполнения макета. Внимательный анализ кода и систематическая отладка обязательно помогут вам выявить и устранить причину проблемы.

← На главную