gifts2017

Авторегистрация внешних отчётов/обработок средствами БСП

Опубликовал Яков Коган (Yashazz) в раздел Администрирование - Системное

Вы сделали клиенту красивую печатную форму, или доп.обработку, или заполнение таб.части; но надо ещё зарегистрировать её. Клиенту это не всегда объяснишь, дистанционно не всегда сделаешь. А дальше её ещё обновлять каждый раз... Предлагаю код, который исключительно штатным образом "сделает всё сам".

Идея родилась из общения с крайне малограмотными клиентами, для которых в БП 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. Если будет время, попробую разобрать каждый вариант подключения и использования внешки в отдельной статье, т.к. там есть весьма любопытные и нетривиальные заморочки.

См. также

PowerTools от 1 000
Подписаться Добавить вознаграждение

Комментарии

1. Сергей Ожерельев (Поручик) 11.02.15 07:20
Всё давно придумано http://infostart.ru/public/181707/ , а сама идея идёт со времён расцвета УТ 10.3 http://infostart.ru/public/75166/
2. Алексей Роза (DoctorRoza) 11.02.15 08:25
М-да!! Люди БСП юзают, тонкие клиенты всякие .. а я сижу в древней УПП 1.2, толстый клиент .. гоняю! :(
Gureev; smit1c; +2 Ответить 1
3. Яков Коган (Yashazz) 11.02.15 09:40
(1), Поручик, спасибо. Конечно, были подозрения, что идея - баян) В данном случае делюсь с коллегами исключительно реализацией под нынешние БСП, никак не "ноу-хау"))) Пардон, сбаянил)

(2) Так и я по основной работе сижу на режиме совместимости 8.1 в очень толстом клиенте... Это так, результат небольших левых работ.
4. DAnry (DAnry) 11.02.15 17:53
М-да!! два раза! А в старой доброй 8.2 с обычным НЕ управляемым интерфейсом всё намного проще...
5. Александр Анисков (vandalsvq) 12.02.15 01:35
Почему используешь "Сообщить" вместо "СообщениеПользователю" (или БСП-шной процедуры ОбщегоНазначенияКлиентСервер.СообщитьПользователю)?
Понимаю не критично, но все-таки. Из-за возможности использовать статус сообщения?

Цитата "Методические рекомендации 1С"
При использовании в конфигурации Библиотеки стандартных подсистем рекомендуется использовать процедуру СообщитьПользователю общего модуля ОбщегоНазначенияКлиентСервер, которая работает с объектом СообщениеПользователю.

6. Яков Коган (Yashazz) 12.02.15 10:10
(5) vandalsvq, да просто привычка. В БСП-то эта функция есть, а я уж привык делать универсалы. Только и всего.
7. Константин Хрипков (mbreaker) 12.02.15 15:44
(2) DoctorRoza, прямо так и напрашивается дополнить фразой "И бед не знаю, в отличие от вас!" :)))))
8. Яков Коган (Yashazz) 12.02.15 18:51
По здравому размышлению советую добавить
и не Параметры.Свойство("ИдентификаторКоманды")
в условие вызова всего механизма в ПриОткрытии, т.к. иначе глобальная обработка в режиме открытия формы будет почём зря вызывать автообновление.
9. Алексей Роза (DoctorRoza) 13.02.15 08:26
(7) mbreaker, не соглашусь! Нет! Конечно, намного меньше проблем и заморочек с решением задач. Но, новые технологии нужно изучать, тем более 8.3.6 на подходе. :|
10. Светлана Юсубуллина (Swetlana) 13.02.15 09:00
(9) DoctorRoza, да ктож вам мешает то? Вместо вас никто этого делать не будет ;)
Ну или ... идите во франч, они загрузят по самое ...любят они ставить изощрённые задачи. )))
11. Константин Юрин (kostyaomsk) 16.02.15 21:32
Ну если уже
из общения с крайне малограмотными клиентами, для которых в БП 3.0 добраться до справочника "Дополнительные отчёты и обработки" было нереально
то точно с такими клиентами беда.
12. Матвей Кудашкин (Patriot1S) 16.04.15 13:45
(0) Для очень ленивых предлагаю http://infostart.ru/public/343316/
kostyaomsk; +1 Ответить
13. Сергей Ожерельев (Поручик) 16.04.15 14:09
(11) Я все свои внешние формы с авторегистрацией делаю. Не потому, что лень или малограмотный, а для ускорения отладки. Ну и для удобства. Открыл и ВПФ зарегистрировалась сама.
kostyaomsk; +1 Ответить
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа