Идея родилась из общения с крайне малограмотными клиентами, для которых в БП 3.0 добраться до справочника «Дополнительные отчёты и обработки» было нереально. Удалённого администрирования добиться не удалось. И тогда я подумал — а пусть внешка сама себя регистрирует. Уж проделать стандартное «Файл» — «Открыть» нынче всякий сможет.
И вот, стало быть, надо просто из «ПриОткрытии» основной формы отчёта/обработки что-то вызывать. Ниже приведено, что именно. Единственно, важно, чтобы в форме были параметр «ОбъектыНазначения» (произвольный) — ну, он-то для многих случаев необходим согласно требованиям БСП; и придуманный мной параметр «НезависимоеОткрытие» (булев, ключевой), он позволяет отличить, как вызвана внешка — через «Файл» — «Открыть» или уже штатно самой конфой. А если хотите, придумайте другие признаки, по которым в ПриОткрытии надо дёргать «ОбновлениеИзФайлаПомещениеНаКлиенте».
Проверялось для всех 36 случаев настроек регистрации внешки, на БСП 2.2.3.36 и 2.2.4.43; пока без прибамбасов вроде автоперезаполнения «Назначения» или расписания вызова команд (где оно возможно); но это тоже планирую сделать.
Особенно эта штука полезна, когда идут мелкие частые правки и надо отдавать все эти варианты клиенту на тест; например, печатные формы. Словом, вставьте вот это в код модуля формы и будет сразу легче.
#Область СобытияФормы
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если ТипЗнч(ЭтаФорма.Параметры.ОбъектыНазначения)<>Тип(«Массив») Тогда
ЭтаФорма.Параметры.НезависимоеОткрытие=Истина;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Если ЭтаФорма.Параметры.НезависимоеОткрытие Тогда
ОбновлениеИзФайлаПомещениеНаКлиенте();
КонецЕсли;
КонецПроцедуры
#КонецОбласти
#Область ОбслуживаниеАвторегистрацииПриОткрытииФормы
// Внимание! Все сообщения выдаются только из расчёта на русский язык, без использования НСтр!
&НаСервере
Процедура ОбновлениеИзФайлаМеханикаНаСервере(ПараметрыРегистрации)
//=============================================================================
// Определяемся с самим объектом
// Подключение и получение имени, под которым объект будет подключаться
Менеджер=?(ПараметрыРегистрации.ЭтоОтчет,ВнешниеОтчеты,ВнешниеОбработки);
// исходим из того, что у нас только тонкий или веб-клиент, получаем имя подключённой ВПФ
ИмяРегистрируемогоОбъекта=СокрЛП(Менеджер.Подключить(ПараметрыРегистрации.АдресДанныхОбработки,,Истина)); // в безопасном
// проверим, есть ли уже такой объект (по ИмяОбъекта и Вид); будем считать, что блок используется (т.к. только это даёт конфликт имён)
тз=«ВЫБРАТЬ ПЕРВЫЕ 1
| ТаблицаСправочника.Ссылка КАК ВПФ
|ИЗ
| Справочник.ДополнительныеОтчетыИОбработки КАК ТаблицаСправочника
|ГДЕ
| ТаблицаСправочника.ИмяОбъекта = &УслИмяОбъекта
| И ТаблицаСправочника.Публикация = ЗНАЧЕНИЕ(Перечисление.ВариантыПубликацииДополнительныхОтчетовИОбработок.Используется)
| И ТаблицаСправочника.ПометкаУдаления = Ложь»;
//
Если ПараметрыРегистрации.ЭтоОтчет Тогда
тз=тз+«
| И ТаблицаСправочника.Вид В (
| ЗНАЧЕНИЕ(Перечисление.ВидыДополнительныхОтчетовИОбработок.ДополнительныйОтчет),
| ЗНАЧЕНИЕ(Перечисление.ВидыДополнительныхОтчетовИОбработок.Отчет))»;
Иначе
тз=тз+«
| И НЕ (ТаблицаСправочника.Вид В (
| ЗНАЧЕНИЕ(Перечисление.ВидыДополнительныхОтчетовИОбработок.ДополнительныйОтчет),
| ЗНАЧЕНИЕ(Перечисление.ВидыДополнительныхОтчетовИОбработок.Отчет)))»;
КонецЕсли;
//
з=Новый Запрос(тз);
з.УстановитьПараметр(«УслИмяОбъекта»,ИмяРегистрируемогоОбъекта);
//
УстановитьПривилегированныйРежим(Истина);
трез=з.Выполнить().Выгрузить(ОбходРезультатаЗапроса.Прямой);
УстановитьПривилегированныйРежим(Ложь);
//
Если трез.Количество()=0 Тогда // создаём новый объект в корне
ОбъектСправочника=Справочники.ДополнительныеОтчетыИОбработки.СоздатьЭлемент();
// считаю правильным проставить сразу же
ОбъектСправочника.ИспользоватьДляФормыСписка=Истина;
ОбъектСправочника.ИспользоватьДляФормыОбъекта=Истина;
Иначе
ОбъектСправочника=трез[0].ВПФ.ПолучитьОбъект();
КонецЕсли;
//=============================================================================
// Обрабатываем объект справочника
КомандыСохраненные=ОбъектСправочника.Команды.Выгрузить(); // запомним команды
//
// запомним состояние реквизита Публикация и выключим временно, чтобы в регистрации обработки не делался поиск (мы уже его сделали)
ПубликацияСохраненная=ОбъектСправочника.Публикация;
ОбъектСправочника.Публикация=Перечисления.ВариантыПубликацииДополнительныхОтчетовИОбработок.Отключена;
// Разрешения используются для всех, кроме глобальных обработок и отчётов, т.е. кроме ВидДопОбработка и ВидДопОтчет
// Назначения используются для всех, кроме глобальных обработок и отчётов, т.е. кроме ВидДопОбработка и ВидДопОтчет
// Единожды указанные Назначения не изменяются, если сведения о них не были переданы (т.е. удалённое — остаётся).
// чтобы они перечитались, надо так: ОбъектСправочника.Назначение.Очистить(); // причём именно ДО вызова ЗарегистрироватьОбработку
// собственно выполним большинство штатных действий по считыванию рег.сведений и регистрации в системе
РезультатРегистрации=ДополнительныеОтчетыИОбработки.ЗарегистрироватьОбработку(ОбъектСправочника,ПараметрыРегистрации);
// закинем данные из РезультатРегистрации в ПараметрыРегистрации и дальше будем работать с ней
ОбщегоНазначенияКлиентСервер.ДополнитьСтруктуру(ПараметрыРегистрации,РезультатРегистрации,Истина);
Если не ПараметрыРегистрации.Успех Тогда
Если не ПустаяСтрока(ПараметрыРегистрации.КраткоеПредставлениеОшибки) Тогда
Сообщить(«Ошибка регистрации внешнего блока: «+СокрЛП(ПараметрыРегистрации.КраткоеПредставлениеОшибки),СтатусСообщения.Важное);
Иначе
// считаем, что «занявших» имя не существует, и неуспех произошёл по другой причине:
// а) не хватило прав на подключения обработки, запускаемой в небезопасном режиме;
// б) не удалось сменить вид (обработка/отчёт итд) для уже имеющегося эл-та спр-ка;
// в) вид ВПФ, указанный в регистрационных данных, противоречит расширению файла.
Сообщить(«Общая недиагностированная ошибка регистрации внешнего блока!»,СтатусСообщения.ОченьВажное);
КонецЕсли;
Возврат;
КонецЕсли;
ОбъектСправочника.Публикация=ПубликацияСохраненная; // восстановим значение реквизита Публикация
// занимаемся таб.частью Команды
тз=«ВЫБРАТЬ
| ДанныеРегистра.ИдентификаторКоманды,
| ДанныеРегистра.Пользователь
|ИЗ
| РегистрСведений.ПользовательскиеНастройкиДоступаКОбработкам КАК ДанныеРегистра
|ГДЕ
| ДанныеРегистра.ДополнительныйОтчетИлиОбработка = &УслСсылка
| И ДанныеРегистра.Доступно = Истина»;
з=Новый Запрос(тз);
з.УстановитьПараметр(«УслСсылка»,ОбъектСправочника.Ссылка);
УстановитьПривилегированныйРежим(Истина);
БыстрыйДоступ=з.Выполнить().Выгрузить(ОбходРезультатаЗапроса.Прямой);
УстановитьПривилегированныйРежим(Ложь);
рАдресРазрешений=ПоместитьВоВременноеХранилище(ОбъектСправочника.Разрешения.Выгрузить(),ЭтотОбъект.УникальныйИдентификатор);
тКоманд=ОбъектСправочника.Команды.Выгрузить();
тКоманд.Сортировать(«Представление»);
// изменить вид единожды созданного элемента уже нельзя, таково положение БСП (см.перед записью объекта)
ВидДополнительнаяОбработка=Перечисления.ВидыДополнительныхОтчетовИОбработок.ДополнительнаяОбработка;
ВидДополнительныйОтчет=Перечисления.ВидыДополнительныхОтчетовИОбработок.ДополнительныйОтчет;
ВидОбъекта=ОбъектСправочника.Вид;
ПредставлениеПустогоРасписания=Строка(Новый РасписаниеРегламентногоЗадания);
// в таблице Команды нужны колонки, которых нет как реквизитов табчасти Команды, добавим
тКоманд.Колонки.Добавить(«РегламентноеЗаданиеИспользование»,Новый ОписаниеТипов(«Булево»));
тКоманд.Колонки.Добавить(«РегламентноеЗаданиеПредставление»); // строка0
тКоманд.Колонки.Добавить(«РегламентноеЗаданиеРазрешено»,Новый ОписаниеТипов(«Булево»));
тКоманд.Колонки.Добавить(«РегламентноеЗаданиеРасписание»,Новый ОписаниеТипов(«СписокЗначений»)); // обычно 1 элемент типа «РасписаниеРегламентногоЗадания»
тКоманд.Колонки.Добавить(«БыстрыйДоступПредставление»); // строка0
Для каждого строКоманд Из тКоманд Цикл
строКоманд.РегламентноеЗаданиеИспользование=Ложь; // по умолчанию
строКоманд.РегламентноеЗаданиеРазрешено=Ложь; // по умолчанию
//
Если ВидОбъекта=ВидДополнительнаяОбработка или ВидОбъекта=ВидДополнительныйОтчет Тогда
// сделаем представление строки в зависимости от количества пользователей, найденных по этой команде в регистре доступа
мНайденных=БыстрыйДоступ.НайтиСтроки(Новый Структура(«ИдентификаторКоманды»,строКоманд.Идентификатор));
Если мНайденных.Количество()=0 Тогда
строКоманд.БыстрыйДоступПредставление=«Нет»;
Иначе // схалявим — незачем красивости разводить
строКоманд.БыстрыйДоступПредставление=«Пользователей: «+СокрЛП(мНайденных.Количество());
КонецЕсли;
КонецЕсли;
//
Если ВидОбъекта=ВидДополнительнаяОбработка
И (строКоманд.ВариантЗапуска=Перечисления.СпособыВызоваДополнительныхОбработок.ВызовСерверногоМетода
ИЛИ строКоманд.ВариантЗапуска=Перечисления.СпособыВызоваДополнительныхОбработок.СценарийВБезопасномРежиме)
Тогда
строКоманд.РегламентноеЗаданиеРазрешено=Истина;
//
РегламентноеЗаданиеGUID=строКоманд.РегламентноеЗаданиеGUID;
НайденнаяСтрока=КомандыСохраненные.Найти(строКоманд.Идентификатор,«Идентификатор»);
Если НайденнаяСтрока<>Неопределено Тогда
РегламентноеЗаданиеGUID=НайденнаяСтрока.РегламентноеЗаданиеGUID;
КонецЕсли;
//
Если ЗначениеЗаполнено(РегламентноеЗаданиеGUID) Тогда // ID задания есть, разбираемся с самим заданием
РегламентноеЗадание=ДополнительныеОтчетыИОбработкиРегламентныеЗадания.НайтиЗадание(РегламентноеЗаданиеGUID);
Если РегламентноеЗадание<>Неопределено Тогда
ПараметрыЗадания=ДополнительныеОтчетыИОбработкиРегламентныеЗадания.ПолучитьПараметрыЗадания(РегламентноеЗадание);
// ставим параметры задания в строку команд
строКоманд.РегламентноеЗаданиеGUID=РегламентноеЗаданиеGUID;
строКоманд.РегламентноеЗаданиеПредставление=Строка(ПараметрыЗадания.Расписание);
строКоманд.РегламентноеЗаданиеИспользование=ПараметрыЗадания.Использование;
строКоманд.РегламентноеЗаданиеРасписание.Вставить(0,ПараметрыЗадания.Расписание);
// выключаем, если надо
Если строКоманд.РегламентноеЗаданиеПредставление=ПредставлениеПустогоРасписания Тогда
строКоманд.РегламентноеЗаданиеИспользование=Ложь;
КонецЕсли;
КонецЕсли;
КонецЕсли;
//
Если Не строКоманд.РегламентноеЗаданиеИспользование Тогда
строКоманд.РегламентноеЗаданиеПредставление=«Расписание не задано»;
КонецЕсли;
Иначе
// если это не глобальная доп.обработка
строКоманд.РегламентноеЗаданиеПредставление=«Неприменимо для команд с вариантом запуска «»»+СокрЛП(строКоманд.ВариантЗапуска)+«»»!»;
КонецЕсли;
КонецЦикла; // по таблице команд
ОбъектСправочника.Команды.Загрузить(тКоманд);
// обратно включим использование
ОбъектСправочника.Публикация=Перечисления.ВариантыПубликацииДополнительныхОтчетовИОбработок.Используется;
Если ДополнительныеОтчетыИОбработки.ВозможнаЗагрузкаОбработкиИзФайла(ОбъектСправочника.Ссылка) Тогда
ддОбработки=ПолучитьИзВременногоХранилища(ПараметрыРегистрации.АдресДанныхОбработки);
ОбъектСправочника.ХранилищеОбработки=Новый ХранилищеЗначения(ддОбработки,Новый СжатиеДанных(9));
КонецЕсли;
Если ВидОбъекта=ВидДополнительнаяОбработка или ВидОбъекта=ВидДополнительныйОтчет Тогда
ОбъектСправочника.ДополнительныеСвойства.Вставить(«АктуальныеКоманды»,тКоманд);
Иначе
БыстрыйДоступ.Очистить();
КонецЕсли;
ОбъектСправочника.ДополнительныеСвойства.Вставить(«БыстрыйДоступ»,БыстрыйДоступ);
ОбъектСправочника.Разрешения.Загрузить(ПолучитьИзВременногоХранилища(рАдресРазрешений));
ОбъектСправочника.Ответственный=ПараметрыСеанса.ТекущийПользователь;
// собственно запишем
Попытка
ОбъектСправочника.Записать();
ПараметрыРегистрации.Вставить(«СсылкаНаОбъект»,ОбъектСправочника.Ссылка);
Исключение
Сообщить(«Ошибка финальной записи регистрации: «+ОписаниеОшибки(),СтатусСообщения.ОченьВажное);
ПараметрыРегистрации.Вставить(«Успех»,Ложь);
КонецПопытки;
КонецПроцедуры
&НаСервере
Функция ОпределитьИмяИспользуемогоФайла()
рОбъект=РеквизитФормыВЗначение(«Объект»);
Возврат рОбъект.ИспользуемоеИмяФайла;
КонецФункции
&НаКлиенте
Процедура ОбновлениеИзФайлаПомещениеНаКлиенте()
рПутьИмяФайла=ОпределитьИмяИспользуемогоФайла();
// помещаем файл в хранилище на сервере
рДопПараметры=Новый Структура(«Успешность»,Истина); // предполагаем, что так
рОбработчик=Новый ОписаниеОповещения(«ПомещениеФайлаНаСерверЗавершение»,ЭтотОбъект,рДопПараметры);
//
Если ПодключитьРасширениеРаботыСФайлами() Тогда
мПомещенныхФайлов=Новый Массив;
Если не ПоместитьФайлы(,мПомещенныхФайлов,рПутьИмяФайла,Ложь,ЭтаФорма.УникальныйИдентификатор) Тогда
Сообщить(«Ошибка при помещении файла внешнего отчёта/обработки на сервер!»,СтатусСообщения.Важное);
рДопПараметры.Вставить(«Успешность»,Ложь);
Иначе
// мПомещенныхФайлов содержит элемент — служебку вида Имя (путь) и Хранение (GUID)
рДопПараметры.Вставить(«Успешность»,Истина);
КонецЕсли;
ВыполнитьОбработкуОповещения(рОбработчик,мПомещенныхФайлов);
Иначе
НачатьПомещениеФайла(рОбработчик,,рПутьИмяФайла,Ложь,ЭтаФорма.УникальныйИдентификатор);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПомещениеФайлаНаСерверЗавершение(мПомещенныхФайлов,рПараметрыРегистрации) Экспорт
рОписаниеФайла=мПомещенныхФайлов.Получить(0);
//
мстро=СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(рОписаниеФайла.Имя,«»);
рПараметрыРегистрации.Вставить(«ИмяФайла»,мстро.Получить(мстро.ВГраница()));
рПараметрыРегистрации.Вставить(«АдресДанныхОбработки»,рОписаниеФайла.Хранение);
//
// выясним тип, исходя из расширения (если бы не веб-клиент, можно было бы через объект «Файл»)
рРасширение=ВРег(Прав(рПараметрыРегистрации.ИмяФайла,3));
Если рРасширение=«ERF» Тогда
рПараметрыРегистрации.Вставить(«ЭтоОтчет»,Истина);
ИначеЕсли рРасширение=«EPF» Тогда
рПараметрыРегистрации.Вставить(«ЭтоОтчет»,Ложь);
Иначе
Сообщить(«Расширение файла не соответствует расширению внешнего отчёта (ERF) или обработки (EPF)!»,СтатусСообщения.Важное);
рПараметрыРегистрации.Вставить(«Успешность»,Ложь);
Возврат;
КонецЕсли;
//
рПараметрыРегистрации.Вставить(«ОтключатьПубликацию»,Ложь);
рПараметрыРегистрации.Вставить(«ОтключатьКонфликтующие»,Ложь);
рПараметрыРегистрации.Вставить(«Конфликтующие»,Новый СписокЗначений);
// Подготовка к вызову сервера.
//ОбработчикРезультата = ПараметрыРегистрации.ОбработчикРезультата;
//ПараметрыРегистрации.Удалить(«ОбработчикРезультата»);
//============================================================================
// Вызов сервера.
ОбновлениеИзФайлаМеханикаНаСервере(рПараметрыРегистрации);
//============================================================================
Если рПараметрыРегистрации.Успех Тогда
Если рПараметрыРегистрации.Свойство(«СсылкаНаОбъект») и ЗначениеЗаполнено(рПараметрыРегистрации.СсылкаНаОбъект) Тогда
гипСсылка=ПолучитьНавигационнуюСсылку(рПараметрыРегистрации.СсылкаНаОбъект);
ПоказатьОповещениеПользователя(«Авторегистрация выполнена»,гипСсылка,«Для перехода к регистрационной карточке щёлкните по ссылке.»,гипСсылка);
ЭтаФорма.Закрыть();
//парф=Новый Структура(«Ключ»,рПараметрыРегистрации.СсылкаНаОбъект);
//ОткрытьФорму(«Справочник.ДополнительныеОтчетыИОбработки.Форма.ФормаЭлемента»,парф);
Иначе
ПоказатьОповещениеПользователя(«При завершении авторегистрации внешнего блока произошла ошибка!»);
КонецЕсли;
Иначе
ПоказатьОповещениеПользователя(«Авторегистрация внешнего блока не удалась!»);
КонецЕсли;
КонецПроцедуры
#КонецОбласти
Кто найдёт ошибки — пожалуйста, сообщайте, буду исправлять. Вообще, заранее оговорюсь, что развитие БСП в любой момент может сделать любую из вышеприведённых строк неактуальной, но, по идее, капитальных изменений идеологии быть уже не должно.
P.S. Если будет время, попробую разобрать каждый вариант подключения и использования внешки в отдельной статье, т.к. там есть весьма любопытные и нетривиальные заморочки.
Всё давно придуманоhttp://infostart.ru/public/181707/ , а сама идея идёт со времён расцвета УТ 10.3 http://infostart.ru/public/75166/
М-да!! Люди БСП юзают, тонкие клиенты всякие .. а я сижу в древней УПП 1.2, толстый клиент .. гоняю! 🙁
(1), Поручик, спасибо. Конечно, были подозрения, что идея — баян) В данном случае делюсь с коллегами исключительно реализацией под нынешние БСП, никак не «ноу-хау»))) Пардон, сбаянил)
(2) Так и я по основной работе сижу на режиме совместимости 8.1 в очень толстом клиенте… Это так, результат небольших левых работ.
М-да!! два раза! А в старой доброй 8.2 с обычным НЕ управляемым интерфейсом всё намного проще…
Почему используешь «Сообщить» вместо «СообщениеПользователю» (или БСП-шной процедуры ОбщегоНазначенияКлиентСервер.СообщитьПользователю)?
Понимаю не критично, но все-таки. Из-за возможности использовать статус сообщения?
Цитата «Методические рекомендации 1С»
(5) vandalsvq, да просто привычка. В БСП-то эта функция есть, а я уж привык делать универсалы. Только и всего.
(2) DoctorRoza, прямо так и напрашивается дополнить фразой «И бед не знаю, в отличие от вас!» :)))))
По здравому размышлению советую добавить
в условие вызова всего механизма в ПриОткрытии, т.к. иначе глобальная обработка в режиме открытия формы будет почём зря вызывать автообновление.
(7) mbreaker, не соглашусь! Нет! Конечно, намного меньше проблем и заморочек с решением задач. Но, новые технологии нужно изучать, тем более 8.3.6 на подходе. 😐
(9) DoctorRoza, да ктож вам мешает то? Вместо вас никто этого делать не будет 😉
Ну или … идите во франч, они загрузят по самое …любят они ставить изощрённые задачи. )))
Ну если уже
то точно с такими клиентами беда.
(0) Для очень ленивых предлагаюhttp://infostart.ru/public/343316/
(11) Я все свои внешние формы с авторегистрацией делаю. Не потому, что лень или малограмотный, а для ускорения отладки. Ну и для удобства. Открыл и ВПФ зарегистрировалась сама.