Задача №1. Нужно открыть файл шаблона.
Т.к. шаблоны на сервере, мы где-то храним путь к папке на сервере и имена файлов. У меня их было 5. В зависимости от настроек на форме. В обработке сделал 2 поля по отдельности. Выбор файла не сделаешь, ибо они на сервере.
Далее надо проверить, есть ли указанный файл в папке на сервере.
ФайлШаблона = Новый Файл(ПутьКФайлу + "\" + ИмяФайла);
Если Не ФайлШаблона.Существует() Тогда
РезультатВыполнения.Успешно = Ложь;
РезультатВыполнения.ТекстОшибки = "Не найден файл шаблона";
Возврат РезультатВыполнения;
КонецЕсли;
При работе с шаблоном Open Office нам нужен не сам файл, а его двоичные данные.
ДвоичныеДанные = Новый ДвоичныеДанные(ПутьКФайлу + "\" + ИмяФайла)
Кстати, если у Вас шаблон сохранен внутри конфигурации как макет, то эти танцы с бубном Вам не требуются. Макет - это уже двоичные данные.
Задача №2. Необходимо открыть шаблон для редактирования через COM объект Open Office.
Здесь сразу скажу, что сильно помог общий модуль из ЕРП "УправлениеПечатьюOOWriterКлиент". Однако, стоит отметить, что модуль написан под работу на клиенте. Моя же задача решается на сервере (таково требование заказчика).
Главную процедуру немного адаптировал под серверный вызов. Особо понравилось, что коллеги из 1С все необходимые для заполнения данные хранят в Структуре.
СтруктураМакета = ПолучитьМакетOpenOffice(ДвоичныеДанные);
Полученные на первом шаге ДвоичныеДанные являются входящим параметром для этой функции. Структура имеет следующие поля:
СтруктураМакета = Новый Структура("ServiceManager, Desktop, Document, ИмяФайла, ДвоичныеДанные", Неопределено, Неопределено, Неопределено, "", Неопределено);
Здесь требуются некоторые разъяснения:
1. Для того, чтоб получить Document необходимо предварительно создать временный файл с шаблоном.
2. Временный файл создаётся из двоичных данных, которые мы передали как параметр. Кстати, если Вы шаблон храните на клиенте, а заполнить захотите его на сервере, то ДвоичныеДанные нужно будет передать с клиента на сервер. Это можно сделать через помещение во временное хранилище. Также имейте ввиду, что на новых платформах 13+ (это не возраст) необходимо использовать асинхронные вызовы. Это несколько усложняет логику и читабельность кода.
3. При работе на сервере и клиенте временный файл получается так:
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("ODT");
ДвоичныеДанныеШаблона.Записать(ИмяВременногоФайла);
При работе на Веб-клиенте этот метод недоступен! Об этом подробно описано в стандарте разработки на эту тему! Рекомендую изучить. В общем модуле ЕРП работа с Веб-клиентом учтена.
4. Собственно когда мы получили временный файл и связали его с нашими двоичными данными, далее можно связать наш шаблон с COM объектом Open Office. Работа с Microsoft Office конечно гораздо проще.
Document = Desktop.LoadComponentFromURL("file:///" + СтрЗаменить(ИмяВременногоФайла, "\", "/"), "_blank", 0, ПараметрыДокумента);
5. В структуре макета поле "ИмяФайла" - это имя временного файла, а не исходного, из которого мы получили ДвоичныеДанные! Его требуется запомнить, чтоб потом удалить! Удалять временные файлы обязательно, сами они удаляются только при перезапуске 1С. А при работе на Веб-клиенте они не удаляются вовсе! Это также описано в стандарте разработки (вот почему их важно изучать и соблюдать!).
Задача №3. Заполнение показателей.
Здесь есть несколько способов:
1. Замена текста
2. Заполнение переменных. В MS Word переменные назывались DocVariable.
Выбрал первый путь, он проще и понятней. Поэтому как называются переменные в Open Office понятия не имею).
Замена идет в переменной Document в цикле. На каждой итерации создается что-то вроде конструктора замены:
//Заполним все переменные в шаблоне
Для Каждого ТекПоказатель Из Объект.СтроковыеПоказатели Цикл
ReplaceDescriptor = СтруктураМакета.Document.createReplaceDescriptor();
ReplaceDescriptor.SearchString = СокрЛП(ТекПоказатель.ИдентификаторПоказателя);
ReplaceDescriptor.ReplaceString = СокрЛП(ТекПоказатель.Значение);
СтруктураМакета.Document.replaceAll(ReplaceDescriptor);
КонецЦикла;
Задача 4. Сохранить результаты заполнения на сервере, чтоб с сервера их передать на клиент.
Здесь пришлось подумать сильней всего. Вот причины этого:
1. COM объект передать с клиента на сервер и обратно невозможно.
2. Передача файлов также не предусмотрена. Передать можно только двоичные данные.
3. Данные у меня были сохранены во временный файл на сервере, но результат заполнения переменных в этом временном файле не сохранен.
4. Исходно я получил и заполнил шаблон ODT, а сохранить мне надо либо в ODT, либо в PDF. По этой причине сохранять данные в первый временный файл не получится. Требуется ещё один.
5. Самое сложное было понять где в текущий момент времени находятся двоичные данные с заполненными показателями. Их нет ни в переданном ранее параметре ДвоичныеДанные, ни во временном файле. Они хранятся в переменной Document, в которой и производилась замена переменных.
Собственно, как написал выше мы должны сохранить данные в новый временный файл. Имя временного файла, точнее его расширение зависит от выбора пользователя. Важно знать, что для PDF формата необходимо при сохранении заполнить параметр FilterName значением "calc_pdf_Export". Иначе двоичные данные будут предназначены для формата ODT и сохранить на клиенте их в формат PDF будет нельзя!
ПараметрТипФайла = "";
Если Объект.ФорматPDF Тогда
ЗаполненныйВременныйФайл = ПолучитьИмяВременногоФайла(".pdf");
ПараметрТипФайла = "calc_pdf_Export";
Иначе
ЗаполненныйВременныйФайл = ПолучитьИмяВременногоФайла(".odt");
КонецЕсли;
НастройкиСохранения.SetValue(0, СвойствоЗначение(СтруктураМакета.ServiceManager, "FilterName", ПараметрТипФайла));
//Сохраним полученный временный файл, чтоб далее его удалить
СтруктураМакета.Вставить("ЗаполненныйВременныйФайл", ЗаполненныйВременныйФайл);
//Приводим путь к файлу в формат Open Office и записываем файл
ЗаполненныйВременныйФайл_какУРЛ = "file:///" + СтрЗаменить(ЗаполненныйВременныйФайл, "\", "/");
СтруктураМакета.Document.storeToURL(ЗаполненныйВременныйФайл_какУРЛ, НастройкиСохранения);
Также необходимо запомнить путь к второму временному файлу. Ниже напишу зачем.
Задача 5. Передача заполненного шаблона с сервера на клиент.
Как писал выше, передать мы можем двоичные данные. На текущий момент они хранятся во втором созданном временном файле. На данном этапе COM объект Open Office уже не требуется, поэтому уничтожаем его. Процедуру для этого взял из модуля ЕРП, код дублировать здесь не буду.
Получим двоичные данные и поместим их в хранилище для передачи на клиент.
ДвоичныеДанные = Новый ДвоичныеДанные(СтруктураМакета.ЗаполненныйВременныйФайл);
АдресВХранилище = ПоместитьВоВременноеХранилище(ДвоичныеДанные, Новый УникальныйИдентификатор);
После этого временные файл не нужны, их необходимо удалить.
Если СтруктураМакета.Свойство("ИмяФайла") Тогда
УдалитьФайлы(СтруктураМакета.ИмяФайла);
КонецЕсли;
Если СтруктураМакета.Свойство("ЗаполненныйВременныйФайл") Тогда
УдалитьФайлы(СтруктураМакета.ЗаполненныйВременныйФайл);
КонецЕсли;
Дальнейший код будет выполняться на клиенте/на веб-клиенте.
Задача 6. Получить данные с сервера и открыть пользователю заполненный шаблон.
Получаем двоичные данные с сервера:
ДвоичныеДанныеШаблона = ПолучитьИзВременногоХранилища(РезультатВыполнения.АдресВХранилище);
Теперь нужно превратить двоичные данные в файл, чтоб можно было его запустить и показать пользователю.
Здесь мы сталкиваемся с особенностью работы веб-клиента. Путь решения описан в стандарте разработки.
Для веб-клиент необходимо получить каталог, в который будет сохранен временный файл и придумать ему имя. Формат вывода зависит от выбора пользователя.
//Получим имя временного файла
#Если ВебКлиент Тогда
Расширение = ?(Объект.ФорматPDF, ".PDF", ".ODT");
Каталог = КаталогВременныхФайлов();
ИмяФайла = Строка(Новый УникальныйИдентификатор) + Расширение;
ИмяВременногоФайла = Каталог + ИмяФайла;
#Иначе
Расширение = ?(Объект.ФорматPDF, "PDF", "ODT");
ИмяВременногоФайла = ПолучитьИмяВременногоФайла(Расширение);
#КонецЕсли
//Сохраним временный файл
ДвоичныеДанныеШаблона.Записать(ИмяВременногоФайла);
Осталось показать полученный временный файл пользователю. Для этого на платформах 13+ надо использовать асинхронный вызов:
НачатьЗапускПриложения(ОповещениеЗапускаПриложения, ИмяВременногоФайла);
Т.к. мы создали ещё один временный файл, его необходимо удалить. Я это делаю в 2-х событиях:
1. ПередЗакрытием
2. При повторном нажатии на кнопку вывода шаблона.
Последнее, что осталось описать - как воспользоваться приложенной обработкой:
1. На форме заполнить Имя файла шаблона и Путь к шаблонам (напоминаю, что путь актуален на сервере!)
2. В функции "ПолучитьСписокОбщихПоказателей" указать список параметров Вашего макета.
3. Есть дополнительная функция "ПолучитьСписокНеРедактируемыхПоказателей". В ней указываются те показатели, которые заполняются из реквизитов шапки формы. Но здесь важно, чтоб имя показателя совпадало с именем реквизита на форме (не с синонимом!). Это важно т.к. заполнение идёт следующим кодом:
СписокНеРедактируемыхПоказателей = ПолучитьСписокНеРедактируемыхПоказателей();
Для Каждого ТекПоказатель Из СписокНеРедактируемыхПоказателей Цикл
НайдСтрокиТЧ = Объект.СтроковыеПоказатели.НайтиСтроки(Новый Структура("ИдентификаторПоказателя", ТекПоказатель));
Если Не НайдСтрокиТЧ.Количество() = 0 Тогда
СтрокаТЧ = НайдСтрокиТЧ[0];
СтрокаТЧ.Значение = Объект[ТекПоказатель];
КонецЕсли;
КонецЦикла;
4. Собственно создать необходимые Вам реквизиты обработки и разместить их на форме.
Весь остальной код работает без всякой адаптации.
Если Вам необходимо макет хранить в конфигурации, то вместо задачи №1 необходимо написать получение макета.
Если необходимо выполнять код на клиенте, то учитывать особенность веб-клиента, которая описана в задаче №6.
Спасибо за внимание.