В типовых конфигурациях при печати документов обычно используется запрос к базе данных для получения данных о документе. Это не всегда удобно, когда требуется вместо реального объекта отправить на печать модифицированный, измененный объект. В таких случаях рекомендую не переписывать запросы типовых, а использовать виртуализацию запросов.
Суть метода заключается в том, чтобы точечно вставить изменение непосредственно перед выполнением кода запроса.
Например, в типовой конфигурации УТ есть запрос по печати расходной накладной в модуле объекта:
ВЫБРАТЬ
РеализацияТоваровУслуг.Номенклатура,
…
Документ.РеализацияТоваровУслуг.ВозвратнаяТара КАК РеализацияТоваровУслуг
ГДЕ
РеализацияТоваровУслуг.Ссылка = &ТекущийДокумент
УПОРЯДОЧИТЬ ПО
Метка,
НомерСтроки
Этот запрос помещается в текст запроса Запрос.Текст, затем вызывается выполнение:
ЗапросТовары = Запрос.Выполнить().Выгрузить();
Для того, чтобы воспользоваться виртуализацией и напечатать текущий модифицированный документ из памяти, а не хранящийся в базе данных, достаточно вызвать метод перед выполнением запроса:
ОбработатьЗапросПоВиртуальномуДокументу(Запрос, Ссылка.ПолучитьОбъект(), ЭтотОбъект());
Этот метод заменяет обращения к таблицам документа на обращения к виртуальным таблицам, помещаемым в менеджер временных таблиц.
Функция позволяет можно заменить табличные части и реквизиты шапки документа.
Более интересное применение виртуализации – модификация документа перед его проведением.
Например, в УТ серии должны храниться в документе по одной строке на каждую серию. Это неудобно для пользователей. Поэтому можно серии вынести в отдельную таблицу, но при проведении эмулировать документ с заполненными сериями, т.е. проставлять для каждой строки серию. В этом случае и пригодится вызов виртуализации при контроле остатков, запросе по табличной части документа и т.п.
В обработке-примере используется документ РеализацияТоваровУслуг из УТ.
В обработку скопирована процедура печати накладной.
Перед вызовом каждого из двух запросов добавлена строка:
ОбработатьЗапросПоВиртуальномуДокументу(Запрос, Ссылка.ПолучитьОбъект(), ЭтотОбъект);
Этого достаточно, чтобы печатная форма брала объект из памяти, а не из базы данных. Сравните с трудоемкостью изменения запроса, если бы вы захотели сделать это другим способом!
В форме можно нажать кнопку «Показать форму документа», внести изменения в документ, затем, не закрывая форму документа, нажать кнопку «Распечатать документ» и получить печатную форму накладной по несохраненному в базе объекту.
Пример:
Открываем обработку, выбираем документ:
Открываем документ:
Нажимаем распечатать:
Модифицируем номер, контрагента и количество товара в первой строке:
Нажимаем распечатать:
Как видно, изменения, сделанные в памяти, отобразились в печатной форме, минуя базу данных.
Функция ОбработатьЗапросПоВиртуальномуДокументу(Запрос, ДокументОбъект, ДокументОбъектНовый) Экспорт
ЗапросТМП = Новый Запрос();
Если Запрос.МенеджерВременныхТаблиц = Неопределено Тогда
ЗапросТМП.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.МенеджерВременныхТаблиц=ЗапросТМП.МенеджерВременныхТаблиц;
Иначе
ЗапросТМП.МенеджерВременныхТаблиц = Запрос.МенеджерВременныхТаблиц;
КонецЕсли;
//Заменяем запрос к документу на запрос к таблице...
ИмяДокумента = ДокументОбъект.Метаданные().Имя;
МД = ДокументОбъект.Метаданные();
ТипСсылка = Новый ОписаниеТипов("ДокументСсылка." + ИмяДокумента);
Для Каждого МДТЧ ИЗ МД.ТабличныеЧасти Цикл
ИмяТЧ = МДТЧ.Имя; //Идентификатор табличной части
МаскаТЧ = "Документ." + ИмяДокумента + "." + ИмяТЧ;
Если Найти(Запрос.Текст, МаскаТЧ) = 0 Тогда Продолжить; КонецЕсли;
ИмяВТ = "ВТТаб" + ИмяТЧ;//Идентификатор временной таблицы
Запрос.Текст = СтрЗаменить(Запрос.Текст, МаскаТЧ, " " + ИмяВТ + " ");
ТЗТабличнаяЧасть = ДокументОбъектНовый[ИмяТЧ].Выгрузить();
ТЗТабличнаяЧасть.Колонки.Добавить("Ссылка", ТипСсылка);
ТЗТабличнаяЧасть.ЗаполнитьЗначения(ДокументОбъект.Ссылка, "Ссылка");
ЗапросТМП.Текст = "Выбрать * ПОМЕСТИТЬ " + ИмяВТ + " Из &Таб Как Т";
ЗапросТМП.УстановитьПараметр("Таб", ТЗТабличнаяЧасть);
ЗапросТМП.Выполнить();
КонецЦикла;
//Заменяем запросы к шапке
МаскаШапки = "Документ." + ИмяДокумента;
Если Найти(Запрос.Текст, МаскаШапки) <> 0 Тогда
ИмяВТ = "ВТТабШапка" ;//Идентификатор временной таблицы
Запрос.Текст = СтрЗаменить(Запрос.Текст, МаскаШапки, " " + ИмяВТ + " ");
//Делаем одну строку таблицы на шапку
ТЗШапка = Новый ТаблицаЗначений();
СтрокаШапки = ТЗШапка.Добавить();
//Берем реквизиты шапки
Для Каждого МДРеквизит ИЗ МД.Реквизиты Цикл
ТЗШапка.Колонки.Добавить(МДРеквизит.Имя, МДРеквизит.Тип);
КонецЦикла;
//Берем ссылку
ТЗШапка.Колонки.Добавить("Ссылка", ТипСсылка);
//СтрокаШапки.Ссылка = ДокументОбъект.Ссылка;
//Берем номер
Если МД.ТипНомера = Метаданные.СвойстваОбъектов.ТипНомераДокумента.Строка Тогда
ТЗШапка.Колонки.Добавить("Номер", Новый ОписаниеТипов("Строка",,Новый КвалификаторыСтроки(МД.ДлинаНомера)));
Иначе
ТЗШапка.Колонки.Добавить("Номер", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(МД.ДлинаНомера)));
КонецЕсли;
//СтрокаШапки.Номер = ДокументОбъектНовый.Номер;
//Берем дату
ТЗШапка.Колонки.Добавить("Дата", Новый ОписаниеТипов("Дата",,, Новый КвалификаторыДаты(ЧастиДаты.ДатаВремя)));
//СтрокаШапки.Дата = ДокументОбъектНовый.Дата;
ЗаполнитьЗначенияСвойств(СтрокаШапки, ДокументОбъектНовый);
ЗапросТМП.Текст = "Выбрать * ПОМЕСТИТЬ " + ИмяВТ + " Из &Таб Как Т";
ЗапросТМП.УстановитьПараметр("Таб", ТЗШапка);
ЗапросТМП.Выполнить();
КонецЕсли;
Возврат ДокументОбъектНовый;
КонецФункции