Печатная форма создавалась как заготовка для печати всевозможных кадровых документов из ЗУП 3.1 (3.1.15.40), версия платформы 1С:Предприятие 8.3 (8.3.16.1224). На ее основе очень просто создавать различные договоры, дополнительные соглашения, согласия на обработку персональных данных и прочих документов, которые постоянно меняются. Главное, что большую часть работы выполняет непосредственно кадровик или юрист, верстая образец в формате WORD. Наша задача взять этот образец, в нужных местах слова заменить параметрами и сохранить в макетах печатной формы в качестве двоичных данных.
ШАГ 1 Создание внешней печатной формы.
В модуле обработке добавляем стандартные функции и процедуры
Функция СведенияОВнешнейОбработке() Экспорт
// Объявим переменную, в которой мы сохраним и вернем "наружу" необходимые данные
ИмяОбработки = ЭтотОбъект.Метаданные().Имя;
Синоним = ЭтотОбъект.Метаданные().Синоним;
Синоним = ?(ЗначениеЗаполнено(Синоним),Синоним, ИмяОбработки);
//Массив назначений
МассивНазначений = Новый Массив;
УказанныеТипы = ЭтотОбъект.Метаданные().Реквизиты.СсылкаНаОбъект.Тип.Типы(); // Возьмем типы из реквизита "Документ"
Для Каждого УказанныйТип ИЗ УказанныеТипы Цикл
ОбъектМетаданных = Метаданные.НайтиПотипу(УказанныйТип);
Если ОбъектМетаданных <> Неопределено Тогда
МассивНазначений.Добавить("Документ." + ОбъектМетаданных.Имя);
КонецЕсли;
КонецЦикла;
ПараметрыРегистрации = Новый Структура;
ПараметрыРегистрации.Вставить("Вид", "ПечатнаяФорма");
ПараметрыРегистрации.Вставить("Назначение", МассивНазначений);
ПараметрыРегистрации.Вставить("Наименование", Синоним);
// Зададим право обработке на использование безопасного режима. Более подробно можно узнать в справке к платформе (метод УстановитьБезопасныйРежим)
ПараметрыРегистрации.Вставить("БезопасныйРежим", Ложь);
// Следующие два параметра играют больше информационную роль, т.е. это то, что будет видеть пользователь в информации к обработке
ПараметрыРегистрации.Вставить("Версия", "1.0");
ПараметрыРегистрации.Вставить("Информация", "Обработка"+Синоним);
// Создадим таблицу команд (подробнее смотрим ниже)
ТаблицаКоманд = ПолучитьТаблицуКоманд();
// Добавим команду в таблицу
ДобавитьКоманду(ТаблицаКоманд, Синоним, "Справка", "ВызовКлиентскогоМетода", Истина,"ПечатьMXL" );
// ДобавитьКоманду(ТаблицаКоманд, Синоним, "Справка", "ВызовСерверногоМетода", Истина,"ПечатьMXL" );
// Сохраним таблицу команд в параметры регистрации обработки
ПараметрыРегистрации.Вставить("Команды", ТаблицаКоманд);
// Теперь вернем системе наши параметры
Возврат ПараметрыРегистрации;
КонецФункции
В этой функции важно что "ВызовКлиентскогоМетода". То есть печать происходит на клиенте.
В модуле печатной формы (модуль объекта) добавляем также стандартные ПолучитьТаблицуКоманд() и
ДобавитьКоманду(ТаблицаКоманд, Представление, Идентификатор, Использование, ПоказыватьОповещение = Ложь, Модификатор = ""), а также пустую процедуру печать
Процедура Печать(МассивОбъектов, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
КонецПроцедуры
Шаг 2. Открываем форму обработки. Переходим в модуль формы. Добавляем Функцию печать на клиенте. Она имеет только два параметра ИдентификаторКоманды и ОбъектыНазначения. Нам интересен второй параметр ОбъектыНазначения. Это список значений, куда передана ссылка на документ, из которого мы печатаем файл.
&НаКлиенте
Функция Печать(ИдентификаторКоманды, ОбъектыНазначения) Экспорт
Дата = ТекущаяДата();
Номермакета = ""+Год(Дата)+""+ Месяц(Дата)+""+День(Дата)+""+Час(Дата)+""+Минута(Дата)+""+Секунда(Дата);
МассивДоков = ПолучитьМассивДоков(ОбъектыНазначения);
for each Результат in МассивДоков do
ОткрытьФайлПриложением( Результат.АдресХранилища, "Мат. ответственность"+НомерМакета);
НомерМакета = НомерМакета + 1;
EndDo;
КонецФункции
Но сделать нужный нам запрос обращаясь к документу на форме мы не можем. Ругается, что полученное значение не является объектным. Здесь я не сразу сообразил, что делать, пока не перенес нужный мне запрос в модуль обработки с передачей туда параметра ОбъектыНазначения. Там я смог получить из ОбъектовНазначения нужные мне параметры для передачи в запрос. И обратно получил уже результат запроса.
Для этого сначала передал данные в серверную функцию
&НаСервере
Функция ПолучитьМассивДоков(ОбъектыНазначения)
ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
Выборка = ОбработкаОбъект.ПолучитьЗапросНаСервере(ОбъектыНазначения);
МассивД = New Array;
While Выборка.Следующий() Do
Результат = ВывестиМакетНаСервере(Выборка);
If Результат = Undefined then
continue;
endIf;
МассивД.Добавить(Результат);
EndDo;
return МассивД;
КонецФункции
Которая уже сделала нужный запрос к данным
Функция ПолучитьЗапросНаСервере(ОбъектыНазначения) Экспорт
Запрос = New Query;
Запрос.Текст =
"ВЫБРАТЬ
| СотрудникиОрганизаций.Сотрудник КАК Сотрудник,
| КадроваяИсторияСотрудниковИнтервальный.Должность КАК Должность,
| СотрудникиОрганизаций.ФизическоеЛицо КАК ФизЛицо,
| ПриемНаРаботу.Сотрудник.Код КАК ТабельныйНомер,
| ПриемНаРаботу.ТрудовойДоговорНомер КАК ДоговорНомер,
| ПриемНаРаботу.Должность КАК ДолжностьПриема,
| ПриемНаРаботу.ТрудовойДоговорДата КАК ДоговорДата,
| ПриемНаРаботу.ГрафикРаботы КАК ГрафикРаботы,
| ПриемНаРаботу.ДатаПриема КАК ДатаПриема,
| ПриемНаРаботу.КоличествоСтавок КАК КоличествоСтавок,
| ПриемНаРаботу.ДолжностьРуководителя КАК ДолжностьРуководителя,
| ПриемНаРаботу.Руководитель КАК Руководитель,
| ПриемНаРаботу.Организация КАК Организация,
| ПриемНаРаботу.Организация.ОГРН КАК ОрганизацияОГРН,
| ПриемНаРаботу.Организация.НаименованиеСокращенное КАК ОрганизацияНаименованиеСокращенное,
| ПриемНаРаботу.Организация.НаименованиеПолное КАК ОрганизацияНаименованиеПолное,
| ПриемНаРаботу.Организация.ИНН КАК ОрганизацияИНН,
| ПриемНаРаботу.Организация.РегистрацияВНалоговомОргане.КПП КАК ОрганизацияКПП,
| ПриемНаРаботуНачисления.Размер КАК Оклад,
| ПаспортныеДанныеФизЛиц.Серия КАК ПаспортСерия,
| ПаспортныеДанныеФизЛиц.Номер КАК ПаспортНомер,
| ПаспортныеДанныеФизЛиц.ДатаВыдачи КАК ДатаВыдачи,
| ПаспортныеДанныеФизЛиц.КемВыдан КАК КемВыдан,
| ПаспортныеДанныеФизЛиц.КодПодразделения КАК КодПодразделения,
| ПаспортныеДанныеФизЛиц.Представление КАК ПредставлениеПаспорта,
| ПриемНаРаботу.Ссылка.Номер КАК ПриказНомер,
| ПриемНаРаботу.Ссылка.Дата КАК ПриказДата,
| ЮрАдресОрганизации.Представление КАК ЮрАдресОрганизации,
| ЮрАдресОрганизации.Город КАК Город,
| ПочтовыйАдресОрганизации.Представление КАК ПочтовыйАдресОрганизации,
| АдресПоПропискеФизЛицо.Представление КАК АдресПоПропискеФизЛица,
| АдресПроживанияФизЛицо.Представление КАК АдресПроживанияФизЛица
|
|
|ИЗ
| РегистрСведений.ТекущиеКадровыеДанныеСотрудников КАК СотрудникиОрганизаций
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДокументыФизическихЛиц КАК ПаспортныеДанныеФизЛиц
| ПО СотрудникиОрганизаций.ФизическоеЛицо = ПаспортныеДанныеФизЛиц.ФизЛицо
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПриемНаРаботу КАК ПриемНаРаботу
| ПО СотрудникиОрганизаций.Сотрудник = ПриемНаРаботу.Сотрудник
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПриемНаРаботу.Начисления КАК ПриемНаРаботуНачисления
| ПО СотрудникиОрганизаций.Сотрудник = ПриемНаРаботуНачисления.Ссылка.Сотрудник
| И ПриемНаРаботуНачисления.Начисление.Наименование = &ОплатаПоОкладу
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ФизическиеЛица.КонтактнаяИнформация КАК АдресПоПропискеФизЛицо
| ПО (СотрудникиОрганизаций.ФизическоеЛицо = АдресПоПропискеФизЛицо.Ссылка)
| И (АдресПоПропискеФизЛицо.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Адрес))
| И (АдресПоПропискеФизЛицо.Вид = ЗНАЧЕНИЕ(Справочник.ВидыКонтактнойИнформации.АдресПоПропискеФизическиеЛица))
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ФизическиеЛица.КонтактнаяИнформация КАК АдресПроживанияФизЛицо
| ПО (СотрудникиОрганизаций.ФизическоеЛицо = АдресПроживанияФизЛицо.Ссылка)
| И (АдресПроживанияФизЛицо.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Адрес))
| И (АдресПроживанияФизЛицо.Вид = ЗНАЧЕНИЕ(Справочник.ВидыКонтактнойИнформации.АдресМестаПроживанияФизическиеЛица))
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КадроваяИсторияСотрудниковИнтервальный КАК КадроваяИсторияСотрудниковИнтервальный
| ПО СотрудникиОрганизаций.Сотрудник = КадроваяИсторияСотрудниковИнтервальный.Сотрудник
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Организации.КонтактнаяИнформация КАК ЮрАдресОрганизации
| ПО (ПриемНаРаботу.Организация = ЮрАдресОрганизации.Ссылка)
| И (ЮрАдресОрганизации.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Адрес))
| И (ЮРАдресОрганизации.Вид = ЗНАЧЕНИЕ(Справочник.ВидыКонтактнойИнформации.ЮрАдресОрганизации))
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Организации.КонтактнаяИнформация КАК ПочтовыйАдресОрганизации
| ПО (ПриемНаРаботу.Организация = ПочтовыйАдресОрганизации.Ссылка)
| И (ПочтовыйАдресОрганизации.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Адрес))
| И (ПочтовыйАдресОрганизации.Вид = ЗНАЧЕНИЕ(Справочник.ВидыКонтактнойИнформации.ПочтовыйАдресОрганизации))
|
|
|ГДЕ
| СотрудникиОрганизаций.Сотрудник = &Сотрудник";
Запрос.УстановитьПараметр("ДатаУвольнения", ТекущаяДата());
Запрос.УстановитьПараметр("ОплатаПоОкладу", "Оплата по окладу");
Запрос.УстановитьПараметр("Сотрудник", ОбъектыНазначения.Получить(0).Сотрудник);
Запрос.УстановитьПараметр("ПодразделениеОрганизации", ОбъектыНазначения.Получить(0).Подразделение);
Запрос.УстановитьПараметр("ПустаяДата", '00010101');
Выборка = Запрос.Выполнить().Выбрать();
Возврат Выборка;
КонецФункции
Не забываем, что в данном случае ОбъектыНазначения это список значений, состоящий из одного значение, поэтому и получить это значение проще всего ОбъектыНазначения.Получить(0).
Дальше, с помощью функции
&НаСервере
Функция ВывестиМакетНаСервере(Выборка)
ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
// ДокОбъект = Ссылка.ПолучитьОбъект();
// Получили параметры шаблонов
ПараметрыЗаполненияШаблона = Новый Структура;
ПараметрыЗаполненияШаблона.Вставить("РазделительЛевый","<");
ПараметрыЗаполненияШаблона.Вставить("РазделительПравый",">");
// Получили макет
ВременныйФайл = ПолучитьИмяВременногоФайла("docx");
Если Выборка.Организация.ЮридическоеФизическоеЛицо = Перечисления.ЮридическоеФизическоеЛицо.ФизическоеЛицо Тогда
ОбработкаОбъект.ПолучитьМакет("СправкаИП").Записать(ВременныйФайл);
Иначе
ОбработкаОбъект.ПолучитьМакет("Справка").Записать(ВременныйФайл);
КонецЕсли;
// Получили данные к выводу
ДанныеКВыводу = ДанныеКВыводу(Выборка);
//Результат - Структура имеет параметр "АдресХранилища" и параметры файла такие как размер, расширение
Результат = ОбработатьФайлDocx(
ВременныйФайл,
ПараметрыЗаполненияШаблона,
ДанныеКВыводу
);
Возврат Результат
КонецФункции
и ряда вспомогательныз функций, относящихся к обработке файлов WORD как файлов, имеющих в своей основе MXL вывел файл на экран в формате WORD.
&НаСервере
Функция ВывестиМакетНаСервере(Выборка)
ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
// ДокОбъект = Ссылка.ПолучитьОбъект();
// Получили параметры шаблонов
ПараметрыЗаполненияШаблона = Новый Структура;
ПараметрыЗаполненияШаблона.Вставить("РазделительЛевый","<");
ПараметрыЗаполненияШаблона.Вставить("РазделительПравый",">");
// Получили макет
ВременныйФайл = ПолучитьИмяВременногоФайла("docx");
Если Выборка.Организация.ЮридическоеФизическоеЛицо = Перечисления.ЮридическоеФизическоеЛицо.ФизическоеЛицо Тогда
ОбработкаОбъект.ПолучитьМакет("СправкаИП").Записать(ВременныйФайл);
Иначе
ОбработкаОбъект.ПолучитьМакет("Справка").Записать(ВременныйФайл);
КонецЕсли;
// Получили данные к выводу
ДанныеКВыводу = ДанныеКВыводу(Выборка);
//Результат - Структура имеет параметр "АдресХранилища" и параметры файла такие как размер, расширение
Результат = ОбработатьФайлDocx(
ВременныйФайл,
ПараметрыЗаполненияШаблона,
ДанныеКВыводу
);
Возврат Результат
КонецФункции
Как видите, здесь параметры заключаются в скобки из знаков <> больше, меньше. В этой печатной форме реализован также вывод параметров в колонтитулы. Это когда кадрам очень хочется чтобы название организации или что еще повторялось в заголовке или внизу каждой страницы.