Как правильно получить ФИО и инициалы сотрудников в печатной форме документа 1С?

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

При разработке внешних печатных форм для кадровых документов нередко возникает ситуация: в документе указано несколько сотрудников, однако в печатную форму выводятся данные только по первому человеку либо запрос возвращает ошибку несовместимости типов. Разберем типичные ошибки, проанализируем причины их возникновения и рассмотрим правильные варианты реализации выборки данных.

Анализ исходных ошибок в коде

Посмотрим на исходный фрагмент кода, вызвавший затруднение:


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|   ФИОФизЛицСрезПоследних.Фамилия КАК Фамилия,
|   ФИОФизЛицСрезПоследних.Имя КАК Имя,
|   ФИОФизЛицСрезПоследних.Отчество КАК Отчество
| ИЗ
|   РегистрСведений.ФИОФизЛиц.СрезПоследних(&Дата, ) КАК ФИОФизЛицСрезПоследних
|   ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ПриемНаРаботуВОрганизацию КАК ПриемНаРаботуВОрганизацию
|   ПО ФИОФизЛицСрезПоследних.ФизЛицо = ПриемНаРаботуВОрганизацию.РаботникиОрганизации.ФизЛицо
|ГДЕ
|   ПриемНаРаботуВОрганизацию.РаботникиОрганизации.ФизЛицо = &ФизЛицо";

Запрос.УстановитьПараметр("ФизЛицо", СтрДокП.Сотрудник.Физлицо);
Запрос.УстановитьПараметр("Дата", ТекущаяДата());

Выясним причину некорректной работы такого запроса. Здесь допущено сразу несколько грубых архитектурных ошибок:

  1. Обращение к табличной части через точку от документа в секции соединения. Конструкция Документ.ПриемНаРаботуВОрганизацию обращается к объекту (шапке) документа, а не к его строкам. Попытка связать поле через ПриемНаРаботуВОрганизацию.РаботникиОрганизации.ФизЛицо некорректна, так как табличная часть — это отдельная подчиненная таблица базы данных.
  2. Передача единичного физлица вместо выборки по документу. Параметр &ФизЛицо устанавливается из конкретной переменной СтрДокП. Если этот код выполняется вне цикла или переменная указывает на первую строку, запрос физически не сможет вернуть данные по остальным сотрудникам.
  3. Сравнение составных полей. При попытке передать ссылку на табличную часть или коллекцию строк в условие сравнения вида Ссылка = &Ссылка платформа выдает ошибку: «Неверные параметры в операции сравнения. Нельзя сравнивать поля неограниченной длины и поля несовместимых типов». В параметр &Ссылка необходимо передавать ссылку на сам документ (СсылкаНаОбъект), а не на его табличную часть.
  4. Перезапись параметров области макета. Если параметры области Подвал заполняются в цикле выборки, а сама область выводится в результирующий табличный документ после окончания цикла, в итоговый печатный документ попадут данные исключительно последней итерации.

Способ 1. Запрос с корректным соединением с табличной частью документа

Рассмотрим по шагам правильное построение запроса. Для того чтобы получить актуальные ФИО всех сотрудников, указанных в документе, необходимо обращаться непосредственно к табличной части РаботникиОрганизации и соединять ее со срезом последних регистра сведений ФИОФизЛиц.

Посмотрим на пример правильного текста запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|   ПриемТЧ.НомерСтроки КАК НомерСтроки,
|   ПриемТЧ.ФизЛицо КАК ФизЛицо,
|   ФИОФизЛицСрезПоследних.Фамилия КАК Фамилия,
|   ФИОФизЛицСрезПоследних.Имя КАК Имя,
|   ФИОФизЛицСрезПоследних.Отчество КАК Отчество
|ИЗ
|   Документ.ПриемНаРаботуВОрганизацию.РаботникиОрганизации КАК ПриемТЧ
|   ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ФИОФизЛиц.СрезПоследних(&ДатаСреза, ) КАК ФИОФизЛицСрезПоследних
|       ПО ПриемТЧ.ФизЛицо = ФИОФизЛицСрезПоследних.ФизЛицо
|ГДЕ
|   ПриемТЧ.Ссылка = &Ссылка
|УПОРЯДОЧИТЬ ПО
|   ПриемТЧ.НомерСтроки";

Запрос.УстановитьПараметр("Ссылка", СсылкаНаОбъект);
Запрос.УстановитьПараметр("ДатаСреза", СсылкаНаОбъект.Дата);

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    // Заполнение параметров области строки или подвала
    ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
    
    Фамилия = Выборка.Фамилия;
    Имя = Выборка.Имя;
    Отчество = Выборка.Отчество;
    
    // Формирование инициалов
    ФИОИнициалы = "";
    Если ЗначениеЗаполнено(Имя) Тогда
        ФИОИнициалы = Лев(Имя, 1) + ".";
    КонецЕсли;
    Если ЗначениеЗаполнено(Отчество) Тогда
        ФИОИнициалы = ФИОИнициалы + " " + Лев(Отчество, 1) + ".";
    КонецЕсли;
    ФИОИнициалы = СокрЛП(ФИОИнициалы + " " + Фамилия);
    
    ОбластьСтрока.Параметры.ФИОСотрудника = ФИОИнициалы;
    ТабличныйДокумент.Вывести(ОбластьСтрока);
КонецЦикла;

Важные замечания по оптимизации и логике:

  1. Дата среза: Никогда не используйте ТекущаяДата() для исторических документов. Если сотрудник сменил фамилию после приема на работу, использование текущей даты приведет к искажению данных в печатной форме за прошлый период. Срез необходимо делать на дату документа (СсылкаНаОбъект.Дата) либо на дату приема на работу конкретного сотрудника.
  2. Тип соединения: Рекомендуется использовать ЛЕВОЕ СОЕДИНЕНИЕ, чтобы при случайном отсутствии записи в регистре сведений строка документа не пропадала из печатной формы полностью.
  3. Вывод областей: Метод ТабличныйДокумент.Вывести() должен вызываться на каждой итерации цикла по выборке.

Способ 2. Формирование инициалов непосредственно в запросе

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

Посмотрим на пример запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|   ПриемТЧ.НомерСтроки КАК НомерСтроки,
|   ВЫБОР
|       КОГДА ФИОФизЛицСрезПоследних.Фамилия ЕСТЬ NULL 
|           ТОГДА ПриемТЧ.ФизЛицо.Наименование
|       ИНАЧЕ
|           ФИОФизЛицСрезПоследних.Фамилия +
|           ВЫБОР
|               КОГДА ПОДСТРОКА(ФИОФизЛицСрезПоследних.Имя, 1, 1) <> """"
|                   ТОГДА "" "" + ПОДСТРОКА(ФИОФизЛицСрезПоследних.Имя, 1, 1) + "".""
|               ИНАЧЕ """"
|           КОНЕЦ +
|           ВЫБОР
|               КОГДА ПОДСТРОКА(ФИОФизЛицСрезПоследних.Отчество, 1, 1) <> """"
|                   ТОГДА "" "" + ПОДСТРОКА(ФИОФизЛицСрезПоследних.Отчество, 1, 1) + "".""
|               ИНАЧЕ """"
|           КОНЕЦ
|   КОНЕЦ КАК ФИОСИнициалами
|ИЗ
|   Документ.ПриемНаРаботуВОрганизацию.РаботникиОрганизации КАК ПриемТЧ
|   ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ФИОФизЛиц.СрезПоследних(&ДатаСреза, ) КАК ФИОФизЛицСрезПоследних
|       ПО ПриемТЧ.ФизЛицо = ФИОФизЛицСрезПоследних.ФизЛицо
|ГДЕ
|   ПриемТЧ.Ссылка = &Ссылка
|УПОРЯДОЧИТЬ ПО
|   ПриемТЧ.НомерСтроки";

Запрос.УстановитьПараметр("Ссылка", СсылкаНаОбъект);
Запрос.УстановитьПараметр("ДатаСреза", СсылкаНаОбъект.Дата);
РезультатЗапроса = Запрос.Выполнить();

Такой подход избавляет от необходимости дополнительной строковой обработки параметров в цикле вывода макета.

Способ 3. Использование типовых общих модулей конфигурации

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

  1. Для конфигураций на обычных формах (ЗУП 2.5, УПП 1.3):

    Для форматирования строки представления физического лица доступна функция общего модуля:

    
    ПредставлениеФИО = ОбщегоНазначенияЗК.ФамилияИнициалыФизЛица(Выборка.ФизЛицоНаименование);
    

    Если требуется получить структуру с отдельными полями (Фамилия, Имя, Отчество) на нужную дату, используется метод:

    СтруктураФИО = УправлениеПерсоналом.ПолучитьФИОФизЛица(ФизЛицо, ДатаДокумента);
  2. Для конфигураций на управляемых формах (ЗУП 3, ERP 2, КА 2, БСП):

    В современных конфигурациях структура регистра называется ФИОФизическихЛиц, а преобразование строки выполняется общими модулями БСП:

    
    // Получение фамилии с инициалами из полного ФИО
    Инициалы = ФизическиеЛицаКлиентСервер.ФамилияИнициалы(ПолноеФИО);
    

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

← На главную