При разработке в среде 1С:Предприятие 8 часто возникает задача создания универсальной печатной формы, которая должна собирать данные из нескольких видов документов. Например, трудовой договор может печататься как из документа ПриемНаРаботу, так и из ПриемНаРаботуСписком или КадровыйПеревод. Основная сложность заключается в том, что структура хранения данных в этих документах различается: в одном случае данные находятся в шапке, в другом — в табличной части.
В этой статье мы подробно разберем, почему стандартный подход с простой заменой текста запроса может не работать, и рассмотрим наиболее надежные способы реализации универсальной печати.
Рассмотрим ситуацию, когда разработчик использует метод СтрЗаменить для модификации текста запроса в зависимости от типа документа. Проблема часто кроется в том, что при переходе от одиночного документа к списочному меняется сам источник данных. Если для одиночного документа источником является Документ.ПриемНаРаботу, то для списочного — Документ.ПриемНаРаботуСписком.Сотрудники.
Проанализируем типичные причины ошибок:
Организация, в табличной части может отсутствовать. Вместо этого к нему нужно обращаться через владельца: Ссылка.Организация.ТипЗнч(СсылканаОбъект) может отработать не так, как ожидалось.СтрЗаменить крайне чувствителен к именам псевдонимов. Если заменить «Документ.ПриемНаРаботу» на «Документ.ПриемНаРаботуСписком.Сотрудники», все последующие обращения к полям должны быть пересмотрены.Разберем, как правильно модифицировать текст запроса, чтобы избежать пустых выборок. Важно не просто менять имя таблицы, но и корректировать пути к реквизитам. Если мы работаем с табличной частью (списочный документ), обращение к реквизитам шапки (Организация, Дата, Номер) должно идти через точку от поля Ссылка.
Рассмотрим пример правильной логики замены:
Если ТипЗнч(СсылканаОбъект) = Тип("ДокументСсылка.ПриемНаРаботуСписком") Тогда
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Документ.ПриемНаРаботу", "Документ.ПриемНаРаботуСписком.Сотрудники");
// Важно заменить обращения к реквизитам шапки, так как в табличной части их нет
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПриемНаРаботу.Дата", "ПриемНаРаботу.Ссылка.Дата");
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПриемНаРаботу.Организация", "ПриемНаРаботу.Ссылка.Организация");
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПриемНаРаботу.ТрудовойДоговорНомер", "ПриемНаРаботу.ТрудовойДоговорНомер"); // Если поле в ТЧ
КонецЕсли;
Совет: Всегда проверяйте итоговый текст запроса через Сообщить() или в отладчике. Скопируйте полученную строку в Консоль запросов — это самый быстрый способ увидеть синтаксическую ошибку или отсутствие данных из-за неверного соединения.
Более профессиональный и надежный метод — создание временной таблицы, в которую помещаются необходимые данные из разных источников, приведенные к единому виду. Это избавляет от хрупких строковых замен.
Выполним следующие шаги:
ФизЛицо, Организация, ДатаДокумента, Ссылка.Рассмотрим пример подготовки данных:
Запрос = Новый Запрос;
ТаблицаДанных = Новый ТаблицаЗначений;
ТаблицаДанных.Колонки.Добавить("Ссылка", Новый ОписаниеТипов("УдалитьЭтоИПоставитьНужныеТипы"));
ТаблицаДанных.Колонки.Добавить("ФизическоеЛицо");
ТаблицаДанных.Колонки.Добавить("Организация");
// Заполняем таблицу в зависимости от типа
Если ТипЗнч(СсылканаОбъект) = Тип("ДокументСсылка.ПриемНаРаботуСписком") Тогда
Для Каждого СтрокаТЧ Из СсылканаОбъект.Сотрудники Цикл
НоваяСтрока = ТаблицаДанных.Добавить();
НоваяСтрока.Ссылка = СсылканаОбъект;
НоваяСтрока.ФизическоеЛицо = СтрокаТЧ.ФизическоеЛицо;
НоваяСтрока.Организация = СсылканаОбъект.Организация;
КонецЦикла;
Иначе
НоваяСтрока = ТаблицаДанных.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СсылканаОбъект);
КонецЕсли;
Запрос.УстановитьПараметр("ТаблицаДанных", ТаблицаДанных);
ТекстЗапроса = "ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Данные ИЗ &ТаблицаДанных КАК ТаблицаДанных; ...";
В запросе автора используются левые соединения с регистрами сведений, например, РегистрСведений.ДокументыФизическихЛиц.СрезПоследних. Проанализируем критичный момент: если документ списочный, и вы соединяете его по полю ФизическоеЛицо, убедитесь, что в параметрах виртуальной таблицы СрезПоследних передана правильная дата.
Использование ЕСТЬNULL — обязательное условие. Если для сотрудника не заполнена контактная информация или паспортные данные, левое соединение вернет NULL. Если это поле участвует в дальнейших расчетах или условиях ГДЕ без обработки NULL, вся строка результата может исчезнуть из выборки.
Пример безопасного соединения:
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДокументыФизическихЛиц.СрезПоследних(&Период, ) КАК Документы
ПО ВТ_Документ.ФизическоеЛицо = Документы.Физлицо
И Документы.ВидДокумента = ЗНАЧЕНИЕ(Справочник.ВидыДокументовФизическихЛиц.ПаспортРФ)
Чтобы ваша печатная форма работала стабильно, придерживайтесь следующих правил:
&Доверенность или &АдресОУП должны передаваться в запрос один раз после того, как текст запроса окончательно сформирован.ЗначениеВФайл("C:\temp\query.txt", ТекстЗапроса);. Это позволит вам увидеть реальный текст, который исполняет система, со всеми вашими заменами.Таким образом, для создания качественной универсальной формы лучше уйти от прямого редактирования текста запроса методом СтрЗаменить в пользу предварительного формирования таблицы исходных данных. Это сделает ваш код прозрачным, а логику работы с разными типами документов — предсказуемой.