Каталог решений - Создание динамически подгружаемых печатных форм на 8.2, как это было реализовано в 1С:7.7

Создание динамически подгружаемых печатных форм на 8.2, как это было реализовано в 1С:7.7

Создание динамически подгружаемых печатных форм на 8.2, как это было реализовано в 1С:7.7

В наличии

При создании собственной, легкой, автономной конфигурации для филиалов на управляемых формах необходимо было решить одну задачу: «БЕЗ обновления конфигураций необходимо легко и быстро обновлять/добавлять печатные формы для любого документа в 1С».
Очень понравилось ранее существовавшее решение по динамической подгрузке внешних печатных форм в 1С 7.7.
Его и реализуем.

Категория:

Описание

Вопросы безопасности пока опустим, это тема для отдельных разговоров, но это решение позволяло нам через GPRS соединение в филиале обновлять выборочные печатный формы «на фоне», не останавливая работу в 1С и не отвлекая филиал от работы. Им даже никаких действия для обновления предпринимать не надо, по мере обновления файлов в папке, формы автоматические будут подхватываться.
Описывая далее наше решение, следует помнить, что в разработке собственной конфигурации мы умышленно не используем «библиотеку стандартных процедур», дабы не увеличивать размер и  нагрузку для конфигурации филиала.
Конечно, некоторые общие модули кастрировав, мы все же перенесли в свою конфигурацию (например: «АдресныйКлассификатор, СтроковыеФункцииКлиентСервер»).

И так план решения поставленной задачи:

  1. Выделяем каталог где хранятся печатные внешние формы. В нашем случае: «%КаталогБД%/ExtForms/PrnForms»
  2. В данный каталог складываем одноимённые файлы печатной формы ERF и XML с описанием формы, например: «ЗакупочныйАкт.erf» и «ЗакупочныйАкт.xml»
  3. При открытии любой формы документов (справочников) собираются список печатных форм из файлов XML и создаются на форме соответствующие кнопки печать.
  4. При старте формирования печатной формы, загружается внешняя печатная форма и открывается ее форма.

Реализуем:

1. Этап

Создаем константу для хранения каталога печатных форм: «КаталогПечатныхФорм». Тип(«Строка») . Длина(255). Ее, кстати, заполнять не обязательно, если не заполнена будем использовать условленный в плане путь «по умолчанию».

Создаем Общий модуль «_ВнешниеПечатныеФормы» доступный с клиентов и с сервера.

Добавляем функцию:

//Получает каталог Печатных форм
Функция КаталогПечатныхФорм() Экспорт
	СтрКаталогПечатныхФорм = СокрЛП(ОбщегоНазначения.ЗначениеКонстантыПоИмени("КаталогПечатныхФорм"));
	#Если ВебКлиент Тогда
		Если ПустаяСтрока(СтрКаталогПечатныхФорм) Тогда
		СтрКаталогПечатныхФорм = "D:\Filial82\ExtForms\PrnForms\";
		КонецЕсли;
	    Возврат СтрКаталогПечатныхФорм;
	#Иначе
		Если ПустаяСтрока(СтрКаталогПечатныхФорм) Тогда
			СтрКаталогПечатныхФорм = НСтр(СтрокаСоединенияИнформационнойБазы(), "File");
			Если ЗначениеЗаполнено(СтрКаталогПечатныхФорм) Тогда    //Файловая версия
				Возврат СтрКаталогПечатныхФорм + ?(Прав(СтрКаталогПечатныхФорм,1)="\","","\")+"ExtForms\PrnForms\";
			Иначе
				СтрКаталогПечатныхФорм = КаталогПрограммы();
				Возврат СтрКаталогПечатныхФорм + ?(Прав(СтрКаталогПечатныхФорм,1)="\","","\")+"ExtForms\PrnForms\";
			КонецЕсли;		
		Иначе	
		    Возврат СтрКаталогПечатныхФорм;
		КонецЕсли;
	#КонецЕсли
КонецФункции

2. Этап

Определяем для себя формат файла XML

Например для печатной формы «Закупочный акт» создаем файл: «ЗакупочныйАкт.xml»

<?xml version="1.0" encoding="windows-1251"?>
<ПечатнаяФорма ИД="ЗакупочныйАкт" ИмяФормы="ЗакупочныйАкт" ИмяВСпискеМеню="Закупочный акт" ИмяКнопки="Закупочный акт" ОтображатьКнопку="Авто" Иконка="Печать">
<СсылкаНаОбъект>ДокументСсылка.ЗакупочныйАкт</СсылкаНаОбъект>
</ПечатнаяФорма>

Добавляем в общий модуль «_ВнешниеПечатныеФормы» функцию получения массива печатных форм для объекта

//Возвращает массив печатных форм
//Пример1: ПолучитьМассивПечатныхФорм("ДокументСсылка","РКО");
//Пример2: ПолучитьМассивПечатныхФорм("СправочникСсылка","Контрагенты");
Функция ПолучитьМассивПечатныхФорм(стрТипОбъекта,стрВидОбъекта) Экспорт
	Перем МассивПечатныхФорм;
	МассивПечатныхФорм=Новый Массив;
	КаталогПечатныхФорм = Новый Файл(КаталогПечатныхФорм());
	Если НЕ КаталогПечатныхФорм.Существует() Тогда
		Сообщить("Каталог печатных форм не существует: "+КаталогПечатныхФорм());
		Возврат МассивПечатныхФорм;
	КонецЕсли;
	Для каждого ФайлXML из НайтиФайлы(КаталогПечатныхФорм.ПолноеИмя,"*.xml",Ложь) 
Цикл
		Попытка
			ФайлERF=Новый Файл(Сред(ФайлXML.ПолноеИмя,1,СтрДлина(ФайлXML.ПолноеИмя)-4)+".erf");
			Если НЕ ФайлERF.Существует() Тогда
				Продолжить;
			КонецЕсли;
			ЧитатьХМЛ = Новый ЧтениеXML;
			ЧитатьХМЛ.ОткрытьФайл(ФайлXML.ПолноеИмя);
			ПостроитьДУМ = Новый ПостроительDOM; 
			ДокументДУМ = ПостроитьДУМ.Прочитать(ЧитатьХМЛ);
			КорневойУзел = ДокументДУМ.ПервыйДочерний;
			Если НЕ КорневойУзел.ЕстьАтрибуты() Тогда
				Продолжить;
			КонецЕсли;
			Если КорневойУзел.ЕстьДочерниеУзлы() Тогда
				Для Каждого УзелСсылкаНаОбъект ИЗ КорневойУзел.ПолучитьЭлементыПоИмени("СсылкаНаОбъект") Цикл
					Если (стрТипОбъекта+"."+стрВидОбъекта = УзелСсылкаНаОбъект.ТекстовоеСодержимое) Тогда
						СтруктураДанныхВМассив = Новый Структура("ТипОбъекта,ВидОбъекта,ФайлПолныйПуть,ИД,ИмяФормы,ИмяВСпискеМеню,ИмяКнопки,ОтображатьКнопку,Иконка");
						СтруктураДанныхВМассив.ТипОбъекта = стрТипОбъекта;
						СтруктураДанныхВМассив.ВидОбъекта = стрВидОбъекта;
						СтруктураДанныхВМассив.ФайлПолныйПуть = ФайлERF.ПолноеИмя;
						СтруктураДанныхВМассив.ИД = КорневойУзел.ПолучитьАтрибут("ИД");
						СтруктураДанныхВМассив.ИмяФормы = КорневойУзел.ПолучитьАтрибут("ИмяФормы");
						СтруктураДанныхВМассив.ИмяВСпискеМеню = КорневойУзел.ПолучитьАтрибут("ИмяВСпискеМеню");
						СтруктураДанныхВМассив.ИмяКнопки = КорневойУзел.ПолучитьАтрибут("ИмяКнопки");
						СтруктураДанныхВМассив.ОтображатьКнопку = КорневойУзел.ПолучитьАтрибут("ОтображатьКнопку");
						СтруктураДанныхВМассив.Иконка = КорневойУзел.ПолучитьАтрибут("Иконка");
					МассивПечатныхФорм.Добавить(СтруктураДанныхВМассив);
						Прервать;
					КонецЕсли;
				КонецЦикла;
			КонецЕсли;
			ПостроитьДУМ = Неопределено;
			ЧитатьХМЛ.Закрыть();
		Исключение
		КонецПопытки;
	КонецЦикла;	 	
	Возврат МассивПечатныхФорм;
КонецФункции

Тут конечно можно все оптимизировать… но это я оставляю для вашего творчества 😉

3. Этап

Добавляем в  модуль  «_ВнешниеПечатныеФормы» процедуру генерации кнопок «Печать», вызываемую с формы документа на основании полученного массива XML из 2 этапа

Процедура СоздатьКнопкиПечатныхФорм(массивПечФорм, ЭтаФорма, Элементы, Команды) Экспорт
	текПечФорм =  Новый Cтруктура("ТипОбъекта,ВидОбъекта,ФайлПолныйПуть,ИД,ИмяФормы,ИмяВСпискеМеню,ИмяКнопки,ОтображатьКнопку,Иконка");
	СписокДобавленныхКоманд= Новый Массив;
	Если массивПечФорм.ВГраница()>-1 Тогда 
		Для Каждого текПечФорм Из массивПечФорм Цикл
			Если (текПечФорм.ОтображатьКнопку="Всегда") ИЛИ (массивПечФорм.ВГраница()=0) Тогда
				КомандаФормы  =  Команды.Добавить(Строка(текПечФорм.ИД));
				КомандаФормы.Действие = "ПроцедураОбработкиНажатияПечать";       
				ТекКнопка = Элементы.Добавить(Строка(текПечФорм.ИД),Тип("КнопкаФормы"),ЭтаФорма.КоманднаяПанель);       
				ТекКнопка.Заголовок = текПечФорм.ИмяКнопки;  
				Если ЗначениеЗаполнено(текПечФорм.Иконка) Тогда
					ТекКнопка.Картинка = ПолучитьИконкуКнопки(текПечФорм.Иконка);
					ТекКнопка.Отображение = ОтображениеКнопки.КартинкаИТекст;
				Иначе
					ТекКнопка.Отображение = ОтображениеКнопки.Текст;
				КонецЕсли;
				ТекКнопка.ИмяКоманды = Строка(текПечФорм.ИД); 
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	Если массивПечФорм.ВГраница()>0 Тогда 
		ГруппаПечать = Элементы.Добавить("ГруппаПечать",Тип("ГруппаФормы"),ЭтаФорма.КоманднаяПанель);       
		ГруппаПечать.Заголовок="Печать...";
		Для Каждого текПечФорм Из массивПечФорм Цикл
			КомандаФормы  =  Команды.Добавить(Строка(текПечФорм.ИД)+"Список");
			КомандаФормы.Действие = "ПроцедураОбработкиНажатияПечать";       
			ТекКнопка = Элементы.Добавить(Строка(текПечФорм.ИД)+"Список",Тип("КнопкаФормы"),ГруппаПечать);       
			ТекКнопка.Заголовок = текПечФорм.ИмяВСпискеМеню;  
			Если ЗначениеЗаполнено(текПечФорм.Иконка) Тогда
				ТекКнопка.Картинка = ПолучитьИконкуКнопки(текПечФорм.Иконка);
				ТекКнопка.Отображение = ОтображениеКнопки.КартинкаИТекст;
			Иначе
				ТекКнопка.Отображение = ОтображениеКнопки.Текст;
			КонецЕсли;
			ТекКнопка.ИмяКоманды = Строка(текПечФорм.ИД)+"Список"; 
		КонецЦикла;
	КонецЕсли;
КонецПроцедуры

Сюда же прикладываем небольшую заглушку для подхвата иконок на кнопки «Печать»

Функция ПолучитьИконкуКнопки(ИмяИконки)
	Попытка
		Если ИмяИконки="Файл" Тогда
			Возврат БиблиотекаКартинок.Печать;      //Пока так
		Иначе	
			Возврат БиблиотекаКартинок[ИмяИконки];
		КонецЕсли;
	Исключение
		Возврат БиблиотекаКартинок.Печать;
	КонецПопытки;
КонецФункции

4. Этап

Теперь во всех формах документов добавляем следующий код:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	//необходимо для генерации кнопок печать на форме
	МассивПечатныхФорм=_ВнешниеПечатныеФормы.ПолучитьМассивПечатныхФорм("ДокументСсылка",Объект.Ссылка.Метаданные().Имя);
	_ВнешниеПечатныеФормы.СоздатьКнопкиПечатныхФорм(МассивПечатныхФорм,ЭтаФорма,Элементы,Команды);
КонецПроцедуры

//ВНЕШНИЕ ПЕЧАТНЫЕ ФОРМЫ
&НаКлиенте
Функция ПроверкаНаЗаписьПередПечатью(ЭтаФорма) Экспорт
              //тут ваши проверки перед печатью
              //…
	Возврат Истина;  //или Ложь если не разрешить печать
КонецФункции

&НаСервере
Функция ПодключитьВнешнююОбработку(АдресХранилища)
	Возврат ВнешниеОтчеты.Подключить(АдресХранилища,,Ложь);
КонецФункции 

&НаСервере
Функция ПолучитьМассив()
	Возврат _ВнешниеПечатныеФормы.ПолучитьМассивПечатныхФорм("ДокументСсылка",Объект.Ссылка.Метаданные().Имя); 
КонецФункции

&НаКлиенте
Процедура ПроцедураОбработкиНажатияПечать(Элемент)
	Если НЕ Объект.Проведен Тогда
		Сообщить("Перед выводом на печать необходимо провести документ.");
		Возврат;
	КонецЕсли;
	МассивПечатныхФорм =  ПолучитьМассив();
	ИмяВызваннойКнопки = Элемент.Имя;
	АдресХранилища = "";
	Для Каждого элМассиваПечФорм из МассивПечатныхФорм Цикл
		Если (ИмяВызваннойКнопки = элМассиваПечФорм.ИД) или (ИмяВызваннойКнопки = (элМассиваПечФорм.ИД + "Список"))Тогда
			Если НЕ ПроверкаНаЗаписьПередПечатью(ЭтаФорма) Тогда
				Возврат;
			КонецЕсли;
			ДополнительныеПараметры = Неопределено;//В некоторых документах возможно тут нужны дополнительные параметры
			Результат = ПоместитьФайл(АдресХранилища, элМассиваПечФорм.ФайлПолныйПуть, , Ложь);       
			ИмяОбработки = ПодключитьВнешнююОбработку(АдресХранилища);
			ФормаОтчета= ПолучитьФорму("ВнешнийОтчет." + ИмяОбработки + ".Форма");
			Попытка
				ФормаОтчета.Отчет.СсылкаНаОбъект = Объект.Ссылка;
			Исключение
				Сообщить("Не удалось установить ссылку на объект в печатной форме.");
				Возврат;
			КонецПопытки;
			Если  НЕ ДополнительныеПараметры = Неопределено Тогда
				Попытка
					ФормаОтчета.Отчет.ДополнительныеПараметры = ДополнительныеПараметры;
				Исключение
					//ну и не надо значит
				КонецПопытки;
			Конецесли;
			ФормаОтчета.Открыть();
		КонецЕсли;
	КонецЦикла;
КонецПроцедуры
5. Этап

has been added to your cart:
Оформление заказа