Введение. Предметная область
Макет – это один из самых универсальных объектов 1С Предприятия 8. Использование макетов широко применяется как в оформлении различных документов (отчеты, печатные формы и т.д.), так и в решении нестандартных задач (например хранение файлов внутри конфигурации).
Для чего нужен и применяется такой прекрасный тип макета как ActiveDocument? Самый банальный пример – это шаблон договора, сделанный юристом на скорую руку в MS Word. Тип макета ActiveDocument позволяет загрузить этот шаблон MS Word в конфигурации и осуществлять редактирование напрямую из конфигуратора.
Т.е. вот вы сделали шаблон договора, загрузили в конфигурацию, проработали с этим шаблоном 1 год, и потом вдруг выяснилось, что нужно изменить кусок текста этого договора. Без проблем – открываем конфигуратор, 2 щелчка на нужном макете и можем править word-вский файлик прямо в конфигураторе. Закрываем, обновляем конфигурацию – дело сделано!
Принцип работы.
К сожалению (или к счастью) работа с макетом ActiveDocument возможна только программная. Т.е. чтобы при нажатии кнопки пользователю открылся наш word-вский файлик, нужно написать код! (ВАУ)
Сама схема кода следующая:
1 – Получаем макет ActiveDocument
2 – Инициализируем COM-объект нашего ActiveDocument
3 – Работаем с этим COM-объектом (заполняем данные, редактируем, выводим на экран)
И вот тут начинается самое интересное…
Когнитивный диссонанс
&НаСервере
АктивныйДокумент = ПолучитьМакет("Макет");
КомОбъект = АктивныйДокумент.Получить();
Вот самые первые строчки, на которые натыкается в гугле юный неофит. В файловом варианте такой код сработает корректно (неважно в толстом или тонком клиенте). Т.к. и сервер и клиент у нас находятся на одной машине, и MS Word тоже установлен на этой машине.
А давайте представим, что у нас клиент-сервер, да ещё и сервер находится на другой машине. Будет оно работать в тонком клиенте? Нет. И тут возникнет когнитивный диссонанс. WTF? O_o
Во-первых, получить макет (любой) можно только &На Сервере. Результатом нашего получения будет объект «Оболочка ActiveDocument». «Фигня!» - скажет опытный гуру конфигурирования – «вернём &НаКлиент, как и в случае с табличным документом!»
Не фигня. Оболочка ActiveDocument существует только на сервере и вернуть её на клиент не получится (а нам-то нужно запустить Word именно на клиентской машине).
Во-вторых, инициализировав COM-объект &НаСервере, вернуть его на клиент, также не получится
(и кстати, если сделать наоборот - с клиента на сервер, тоже не прокатит)
Танцы с бубном
Как быть? Ведь нужно инициализировать COM-объект на клиенте, причем из данных, получаемых только на сервере и которых на клиент передать нельзя.
Решение у этой задачи самое корявое, которое только может быть. Но давайте вспомним, зачем мы вообще используем ActiveDocument? Правильно, чтобы внести изменения в шаблон через конфигуратор «на лету». Это и есть та единственная причина, по которой мы используем ActiveDocument. Иначе бы мы использовали тип макета «Двоичные данные».
А вот само решение точно такое же, как при использовании макета с двоичными данными! Т.е. сначала нам нужно сохранить ActiveDocument в файл, а потом, используя этот файл, инициализировать COM-объект (причем сделать это нужно на клиенте!).
Таким образом наша предыдущая схема превращается вот во что:
1 – &НаСервере Получаем макет ActiveDocument
2 – &НаСервере Сохраняем полученный макет в файл и возвращаем на клиент полное имя файла (полный путь + наименование с расширением)
3 – &НаКлиенте Инициализируем COM-объект из файла
4 - &НаКлиенте заполняем и выводим этот COM-объект
Листинг
Небольшой листинг кода:
&НаКлиенте
Процедура ПоказатьМакет(Документ)
Макет = ОбщийМодуль.ПолучитьМакет(Документ); //серверная функция, записывает макет в файл и возвращает полное имя файла
Попытка
Шаблон = ПолучитьCOMОбъект(Макет); //инициализируем COM-объект
Исключение
КомОбъект = 0;
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = ОписаниеОшибки();
Сообщение.Сообщить();
Возврат;
КонецПопытки;
Если Шаблон = Неопределено Тогда
Возврат;
КонецЕсли;
//здесь делаем всякие штуки типа заполнения и прочего
Шаблон.Fields.UpDate();
Шаблон.Activate();
Шаблон.Application.Visible = 1; //указываем, что надо показать юзеру наш COM-объект
Шаблон.Save(); //записываем изменения
Шаблон = 0;
КонецПроцедуры
//Получает макет ActiveDocument и записывает его в файл
&НаСервере
Функция ПолучитьМакет(Документ) Экспорт
Каталог = ПараметрыСеанса.ТекущийПользователь.РабочийКаталог;
Каталог = ?(Прав(Каталог,1) = "\", Каталог, Каталог+"\");
Если ЗначениеЗаполнено(Каталог) Тогда
Попытка
ПолноеИмяФайла = Каталог+Документ.Номер+".doc";
Макет = Документы.ДоговорыКонтрагентов.ПолучитьМакет("ActiveDocument");
Макет.Записать(ПолноеИмяФайла);
Возврат ПолноеИмяФайла;
Исключение
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не удалось записать файл "+ОписаниеОшибки();
Сообщение.Сообщить();
Возврат Неопределено;
КонецПопытки;
Иначе
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не указан каталог. Сохранение файла невозможно";
Сообщение.Сообщить();
Возврат Неопределено;
КонецЕсли;
КонецФункции // ()
Заключение
Естественно, пример с MS Word самый простой и банальный. Вы можете запихнуть туда и другие файлики).
Надеюсь статья кому-то сэкономит 10мин :) Удачи! ;)
P.S. кстати, обратите внимание, какая изящная задача получилась для тестирования опытного кандидата на работу. Если вам нужен человек, для интеграции 1С с другими ПО, да еще и чтоб в Управляемых формах шарил - вы легко сможете это определить.