пятница, 10 августа 2012 г.

Сохранение запроса в файл консоли отчетов/запросов

       Идея написания данной фичи была давно, но никак не доходили руки. Вдохновением для реализации была небольшая доработка консоли запросов http://infostart.ru/public/143349/.
      
       Данный функционал сохраняет запрос с параметрами в файл с деревом значений, который открывается консолью отчетов и консолью запросов. Имеются четыре основных режима работы функции сохранения - на рабочий стол, в документы, в указанный каталог/файл и используя диалог выбора файла. Также можно сохранить значение каталога файлов запросов и указывать только имя создаваемого файла. Режимы сохранение являются наброской, "допилить" "под себя" займет немного времени.
Функция ЗапросВФайл(Запрос, ВариантСохранения = Неопределено, ИмяЗапроса="") Экспорт
    Перем ИмяКаталога;
    Перем ИмяФайла;

    // Получение имен каталога и файла
    Если ВариантСохранения = 0 Тогда
        ДиалогВыбораФайла = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);

        ДиалогВыбораФайла.Заголовок = "Укажите файл для сохранения запроса";
        ДиалогВыбораФайла.Фильтр = "Файлы запросов (*.sel)|*.sel|Файлы отчетов (*.rcf)|*.rcf|Все файлы (*.*)|*.*";
        ДиалогВыбораФайла.Расширение = "sel";

        Если ДиалогВыбораФайла.Выбрать() Тогда
            ПолучитьКаталогИИмяФайла(ДиалогВыбораФайла.ПолноеИмяФайла, ИмяКаталога, ИмяФайла);;
        КонецЕсли;
    ИначеЕсли ВариантСохранения = 1 Тогда
        WSS=Новый COMОбъект("WScript.Shell");
        ИмяКаталога = Строка(WSS.SpecialFolders().Item("Desktop"));
    ИначеЕсли ВариантСохранения = 2 Тогда
        WSS=Новый COMОбъект("WScript.Shell");
        ИмяКаталога = Строка(WSS.SpecialFolders().Item("MyDocuments"));
    ИначеЕсли ТипЗнч(ВариантСохранения) = Тип("Строка") Тогда
        ПолучитьКаталогИИмяФайла(ВариантСохранения, ИмяКаталога, ИмяФайла);
    Иначе
        Возврат Ложь;
    КонецЕсли;

    Если Не ЗначениеЗаполнено(ИмяКаталога) Тогда
        КаталогСохраненияФайлов = ВосстановитьЗначение("КаталогСохраненияФайлов");
        Если КаталогСохраненияФайлов = Неопределено Тогда
            WSS=Новый COMОбъект("WScript.Shell");
            ИмяКаталога = Строка(WSS.SpecialFolders().Item("Desktop")) + "\";
        Иначе
            ИмяКаталога = КаталогСохраненияФайлов;
        КонецЕсли;
    КонецЕсли;

    Если Не ЗначениеЗаполнено(ИмяФайла) Тогда
        ИмяФайла = "Запрос.sel"
    ИначеЕсли Найти(ИмяФайла, ".") = 0 Тогда
        ИмяФайла = ИмяФайла + ".sel";
    КонецЕсли;

    // {{ Если файл сущетвует
    //      - это файл запросов - добавление строки в дерево запосов
    //      - если это не файл запросов - перезаписывание файла
    Файл = Новый Файл(ИмяКаталога + "\" + ИмяФайла);
    ЗначениеФайла = Неопределено;
    Если файл.Существует() Тогда
        ЗначениеФайла = ЗначениеИзФайла(ИмяКаталога + "\" + ИмяФайла)
    КонецЕсли;

    // {{ Создание структурированого дерева значений
    Если ТипЗнч(ЗначениеФайла) = Тип("ДеревоЗначений") Тогда
        ДеревоЗапросов = ЗначениеФайла;
    Иначе
        ДеревоЗапросов = Новый ДеревоЗначений;
        ДеревоЗапросов.Колонки.Добавить("Запрос");
        ДеревоЗапросов.Колонки.Добавить("ТекстЗапроса");
        ДеревоЗапросов.Колонки.Добавить("ПараметрыЗапроса");
        //ДеревоЗапросов.Колонки.Добавить("СпособВыгрузки");
        ДеревоЗапросов.Колонки.Добавить("ТипОформления");
    КонецЕсли;

    // Инициализация параметор запроса
    ПараметрыЗапроса = Новый ТаблицаЗначений;
    ПараметрыЗапроса.Колонки.Добавить("ИмяПараметра");
    ПараметрыЗапроса.Колонки.Добавить("ЭтоВыражение");
    ПараметрыЗапроса.Колонки.Добавить("ЗначениеПараметра");

    Для Каждого Параметр Из Запрос.Параметры Цикл
        ПараметрЗапроса = ПараметрыЗапроса.Добавить();
        ПараметрЗапроса.ИмяПараметра = Параметр.Ключ;
        ПараметрЗапроса.ЭтоВыражение = Ложь;
        Если ТипЗнч(Параметр.Значение) = Тип("Массив") Тогда
            СписокЗначения = Новый СписокЗначений;
            СписокЗначения.ЗагрузитьЗначения(Параметр.Значение);
            ПараметрЗапроса.ЗначениеПараметра = СписокЗначения;
        Иначе
            ПараметрЗапроса.ЗначениеПараметра = Параметр.Значение;
        КонецЕсли;
    КонецЦикла;

    // Добавление запроса в дерево запросов
    ИмяЗапроса = ?(ЗначениеЗаполнено(ИмяЗапроса), ИмяЗапроса, "Запрос");
    ИтоговоеИмяЗапроса = ИмяЗапроса; Итерация = 1;
    Пока Не ДеревоЗапросов.Строки.Найти(ИтоговоеИмяЗапроса) = Неопределено Цикл
        ИтоговоеИмяЗапроса = ИмяЗапроса + Строка(Итерация);
        Итерация = Итерация + 1;
    КонецЦикла;

    // Добавление текущего запроса
    СтрокаЗапрос = ДеревоЗапросов.Строки.Добавить();
    СтрокаЗапрос.Запрос = ИтоговоеИмяЗапроса;
    СтрокаЗапрос.ПараметрыЗапроса = ПараметрыЗапроса;
    СтрокаЗапрос.ТекстЗапроса = Запрос.Текст;
    //СтрокаЗапрос.СпособВыгрузки = ?(Найти(Запрос.Текст, "ИТОГИ")>0, 2, 1);
    СтрокаЗапрос.ТипОформления = СтандартноеОформление.Классика;

    // Сохранение файла
    Возврат ЗначениеВФайл(ИмяКаталога + "\" + ИмяФайла, ДеревоЗапросов)

КонецФункции

Процедура ПолучитьКаталогИИмяФайла(Знач ПолноеИмяФайла, ИмяКаталога, ИмяФайла) Экспорт

    // находим последний с конца "\" все что до него - это путь, после - имя
    НомерПозиции = СтрДлина(ПолноеИмяФайла);
    Пока НомерПозиции <> 0 Цикл
        Если Сред(ПолноеИмяФайла, НомерПозиции, 1) = "\" Тогда
            ИмяКаталога = Сред(ПолноеИмяФайла, 1, НомерПозиции - 1);
            ИмяФайла = Сред(ПолноеИмяФайла, НомерПозиции + 1);
            Возврат;
        КонецЕсли;
        НомерПозиции = НомерПозиции - 1;
    КонецЦикла;

    // так и не нашли слешей, значит все- это имя файла
    ИмяФайла = ПолноеИмяФайла;
    ИмяКаталога = "";

КонецПроцедуры 
P.S. После сохранения не забывайте удалять строку в табло отладки :)

четверг, 10 мая 2012 г.

Локализация стандартных текстов интерфейсов в управляемом приложении

В рабочей базе существуют русскоязычные пользователи (восточный и южный регион) и украиноязычные (западный регион и тру украинцы). При украинизации текстов интерфейсов столкнулся с проблемою редактирования надписей на стандартных элементах интерфейсов форм (Записать и закрыть, сохранить, сформировать и т.д.). Нашел 2 выхода из ситуации - устанавливать язык приложения при установке украинским или динамически изменять надписи и всплывающие подсказки при создании форм. Если кому будет полезно - второй способ решения проблемы описан ниже. 1. Документы и справочники. Для документов и справочников необходимо украинизировать заголовки стандартных действий объекта и действия в табличных частях:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

    Если Не ОбщийМодульСервер.ЯзыкПриложения() = Метаданные.Языки.Русский Тогда
        // Локализация заголовков кнопок
        ОбщийМодульСервер.ЛокализацияЗаголовковВОбъекте(ЭтаФорма, Объект);
        ОбщийМодульСервер.ЛокализацияЗаголовковТабличныхЧастей(ЭтаФорма, ЭтаФорма.Элементы.Таблица1);
        ОбщийМодульСервер.ЛокализацияЗаголовковТабличныхЧастей(ЭтаФорма, ЭтаФорма.Элементы.Таблица2);
    КонецЕсли;

КонецПроцедуры
Для форм списка документов и справочников украинизация немного отличается но объединена в одну процедуру. Различия составляет только проведение документов, отбор документов по периоду и иерархичность справочников.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

    Если ОбщийМодульСервер.ЯзыкПриложения() = Метаданные.Языки.Русский Тогда
        ОбщийМодульСервер.ЛокализацияЗаголовковВСписке(ЭтаФорма);
    КонецЕсли;

КонецПроцедуры
2. Отчеты. Локализация отчетов предусматривает изменение заголовков стандартных действий и отборов СКД. К сожалению без решения остается локализация контекстного меню табличного документа.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

    Если ОбщийМодульСервер.ЯзыкПриложения() = Метаданные.Языки.Русский Тогда
        ОбщийМодульСервер.ЛокализацияЗаголовковВОтчете(ЭтаФорма);
        ОбщийМодульСервер.ЛокализацияЗаголовковОтбораСКД(ЭтаФорма);
    КонецЕсли;

КонецПроцедуры
Описание общего модуля ОбщийМодульСервер (Сервер, Вызов сервера):

&НаСервере
Процедура ЛокализацияЗаголовковВОбъекте(Форма, Объект) Экспорт

    Если ЯзыкПриложения() = Метаданные.Языки.Русский Тогда
        Возврат;
    КонецЕсли;

    ВидОбъектаМетаданных = ПолучитьВидОбъектаМетаданных(Объект.Ссылка);

    // Командная панель табличной части
    // Кнопки для всех объектов - документы и справочники
    СтруктураКнопок = Новый Структура;
    СтруктураКнопок.Вставить("Записать"     , НСтр("Ukr = 'Записати'"));
    СтруктураКнопок.Вставить("Перечитать"   , НСтр("Ukr = 'Перечитати'"));
    СтруктураКнопок.Вставить("Скопировать"  , НСтр("Ukr = 'Скопіювати'"));
    СтруктураКнопок.Вставить("ИзменитьФорму", НСтр("Ukr = 'Змінити форму'"));
    СтруктураКнопок.Вставить("Справка"      , НСтр("Ukr = 'Довідка'"));
    СтруктураКнопок.Вставить("Удалить"      , НСтр("Ukr = 'Видалити'"));
    СтруктураКнопок.Вставить("УстановитьПометкуУдаления", НСтр("Ukr = 'Встановити помітку видаленя'"));

    // Кнопки документов
    Если ВидОбъектаМетаданных = "Документ" Или ВидОбъектаМетаданных = Неопределено Тогда
        СтруктураКнопок.Вставить("Проведение"       , НСтр("Ukr = 'Проведення'"));
        СтруктураКнопок.Вставить("Провести"         , НСтр("Ukr = 'Провести'"));
        СтруктураКнопок.Вставить("ПровестиИЗакрыть" , НСтр("Ukr = 'Провести та закрити'"));
        СтруктураКнопок.Вставить("ОтменаПроведения" , НСтр("Ukr = 'Відміна проведення'"));
        СтруктураКнопок.Вставить("СоздатьНаОсновании", НСтр("Ukr = 'Створити на підставі'"));
    КонецЕсли;

    // Кнопки справочников
    Если ВидОбъектаМетаданных = "Справочник" Или ВидОбъектаМетаданных = Неопределено Тогда
        СтруктураКнопок.Вставить("ЗаписатьИЗакрыть" , НСтр("Ukr = 'Записати та закрити'"));
    КонецЕсли;

    // Установка заголовков
    Для Каждого Кнопка Из СтруктураКнопок Цикл
        ЛокализацияЗаголовка(Форма.Элементы, "Форма"+Кнопка.Ключ, Кнопка.Значение);
    КонецЦикла;

КонецПроцедуры

&НаСервере
Процедура ЛокализацияЗаголовковТабличныхЧастей(Форма, ТабличнаяЧасть) Экспорт

    Если ЯзыкПриложения() = Метаданные.Языки.Русский Тогда
        Возврат;
    КонецЕсли;

    // Командная панель табличной части
    СтруктураКнопок = Новый Структура;
    СтруктураКнопок.Вставить("Добавить"     ,НСтр("Ukr = 'Додати'"));
    СтруктураКнопок.Вставить("Скопировать"  ,НСтр("Ukr = 'Скопіювати'"));
    СтруктураКнопок.Вставить("Изменить"     ,НСтр("Ukr = 'Змінити'"));
    СтруктураКнопок.Вставить("Удалить"      ,НСтр("Ukr = 'Видалити'"));
    СтруктураКнопок.Вставить("Найти"        ,НСтр("Ukr = 'Знайти'"));
    СтруктураКнопок.Вставить("ОтменитьПоиск",НСтр("Ukr = 'Відмінити пошук'"));
    СтруктураКнопок.Вставить("Переместить"  ,НСтр("Ukr = 'Перемістити'")); //Группа
    СтруктураКнопок.Вставить("Сортировка"   ,НСтр("Ukr = 'Сортування'")); // Группа
    СтруктураКнопок.Вставить("ВывестиСписок",НСтр("Ukr = 'Вивести список...'"));
    СтруктураКнопок.Вставить("ПереместитьВниз",НСтр("Ukr = 'Перемістити вниз'"));
    СтруктураКнопок.Вставить("ПереместитьВверх",НСтр("Ukr = 'Перемістити вгору'"));
    СтруктураКнопок.Вставить("ЗакончитьРедактирование",НСтр("Ukr = 'Закінчить редагування'"));
    СтруктураКнопок.Вставить("СортироватьСписокПоУбыванию",НСтр("Ukr = 'Сортувати за зменшенням'"));
    СтруктураКнопок.Вставить("СортироватьСписокПоВозрастанию",НСтр("Ukr = 'Сортувати за збільшенням'"));

    Для Каждого Кнопка Из СтруктураКнопок Цикл
        ЛокализацияЗаголовка(Форма.Элементы, ТабличнаяЧасть.Имя+Кнопка.Ключ, Кнопка.Значение);
    КонецЦикла;

    // Контекстное меню табличной части
    СтруктураКнопок = Новый Структура;
    СтруктураКнопок.Вставить("Добавить"     ,НСтр("Ukr = 'Додати'"));
    СтруктураКнопок.Вставить("Изменить"     ,НСтр("Ukr = 'Змінити'"));
    СтруктураКнопок.Вставить("ВыделитьВсе"  ,НСтр("Ukr = 'Копіювати все'"));
    СтруктураКнопок.Вставить("Переместить"  ,НСтр("Ukr = 'Перемістити'")); //Группа
    СтруктураКнопок.Вставить("Скопировать"  ,НСтр("Ukr = 'Скопіювати'"));
    СтруктураКнопок.Вставить("Удалить"      ,НСтр("Ukr = 'Видалити'"));
    СтруктураКнопок.Вставить("ПереместитьВниз",НСтр("Ukr = 'Перемістити вниз'"));
    СтруктураКнопок.Вставить("ПереместитьВверх",НСтр("Ukr = 'Перемістити вгору'"));
    СтруктураКнопок.Вставить("КопированиеИВыделение",НСтр("Ukr = 'Копіювання та видалення'")); // Группа
    СтруктураКнопок.Вставить("КопироватьВБуферОбмена",НСтр("Ukr = 'Копіювати в буфер обімну'"));

    Для Каждого Кнопка Из СтруктураКнопок Цикл
        ЛокализацияЗаголовка(Форма.Элементы, ТабличнаяЧасть.Имя+"КонтекстноеМеню"+Кнопка.Ключ, Кнопка.Значение);
    КонецЦикла;

КонецПроцедуры

&НаСервере
Процедура ЛокализацияЗаголовка(Элементы, ИмяЭлемента, Заголовок) Экспорт

    ТекущийЭлемент = Элементы.Найти(ИмяЭлемента);
    Если Не ТекущийЭлемент = Неопределено Тогда
        ТекущийЭлемент.Заголовок = Заголовок;
        Если ТипЗнч(Элементы.Найти(ИмяЭлемента)) = Тип("ГруппаФормы") Тогда
            ТекущийЭлемент.Подсказка = Заголовок;
        КонецЕсли;
    КонецЕсли;

КонецПроцедуры

&НаСервере
Функция ПолучитьВидОбъектаМетаданных(Ссылка) Экспорт

    Перем ВидОбъектаМетаданных;

    ИмяОбъектаМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(Ссылка)).Имя;

    Если Не Метаданные.Документы.Найти(ИмяОбъектаМетаданных) = Неопределено Тогда
        ВидОбъектаМетаданных = "Документ";
    ИначеЕсли Не Метаданные.Справочники.Найти(ИмяОбъектаМетаданных) = Неопределено Тогда
        ВидОбъектаМетаданных = "Справочник";
    КонецЕсли;

    Возврат ВидОбъектаМетаданных;

КонецФункции

&НаСервере
Функция ЯзыкПриложения() Экспорт;

    ПользовательИнформационнойБазы = ПользователиИнформационнойБазы.ТекущийПользователь();

    Возврат ПользовательИнформационнойБазы.Язык;

КонецФункции

среда, 21 декабря 2011 г.

Изменение пароля под тонким веб-клиентом

С началом работы пользователей в веб-клиенте появилась нужда изменять пароль пользователя на текущем клиенте, но стандаратных средств нет. Собственно изменить пароль не так и сложно - сложнее идентифицировать пользователя перед выполнением операции. Расшифровывать текущий хеш пароля (sha завернутое в base64) или шифровать его (у меня не получилось) тоже будет не самым оптимальным решением по соотношению затраченное время/полученный результат.

Предлагаю свой вариант алгоритма изменения пароля.

// Если хеш подтверждения пароля совпадает со старым хешем тогда изменяем пароль
ПользовательИнформационнойБазы = ПользователиИнформационнойБазы.ТекущийПользователь();
ХешАвторизации = ПользовательИнформационнойБазы.СохраняемоеЗначениеПароля;

ПользовательИнформационнойБазы.Пароль = Пароль;
ПользовательИнформационнойБазы.Записать();

Пользователь = ПользователиИнформационнойБазы.НайтиПоИмени(ИмяПользователя());
ХешНовогоПароля = Пользователь.СохраняемоеЗначениеПароля;

Если ХешНовогоПароля = ХешАвторизации Тогда
    ПользовательИнформационнойБазы.Пароль = НовыйПароль;
    ПользовательИнформационнойБазы.Записать();
Иначе
    ПользовательИнформационнойБазы.СохраняемоеЗначениеПароля = ХешАвторизации;
    ПользовательИнформационнойБазы.Записать();
КонецЕсли;
 
Скачать обработку 

среда, 5 октября 2011 г.

Пауза в 1С

Столкнулся с проблемою записи табличного документа в pdf файл – виртуальный принтер Bullzip PDF Printer записывает в файл, но при отправлении по почте обработка файл не находит. Оказывается принтер имеет некоторую задержку – нам говорит что файл создан, а на самом деле еще дозаписывает файл. В таких случаях необходимо сделать пазу в коде. Так как 1С своими методами не умеет делать паузу я воспользовался методом Sleep объекта операционной системы Windows Script Host.

Процедура Пауза(ИнтервалОжидания) Экспорт

    Скрипт = Новый ТекстовыйДокумент();
    Скрипт.УстановитьТекст
    (
    "if (WScript.Arguments.Count()==0)
    |    WScript.Quit();
    |else
    |    if (isNaN(parseInt(WScript.Arguments(0))))
    |        WScript.Quit();
    |WScript.Sleep(WScript.Arguments(0));"
    );
    Скрипт.Записать(КаталогВременныхФайлов()+"sleep.js", КодировкаТекста.ANSI);

    WshShell = Новый COMОбъект("WScript.Shell");
    WshShell.Run("WScript.exe """ + КаталогВременныхФайлов() + "sleep.js"" " + Формат(ИнтервалОжидания, "ЧГ=0"), 0, -1);

    УдалитьФайлы(КаталогВременныхФайлов() + "sleep.js");

КонецПроцедуры // Пауза

среда, 28 сентября 2011 г.

Использование СКД вне отчета

Столкнулся с ситуацией когда надо в табличный документ вывести результат выполнения системы компоновки данных - на первый взгляд все просто, но давайте вместе разберемся шаг за шагом.

1. Необходимо получить нужный макет СКД

СхемаКомпоновкиДанных = ПолучитьМакет(ИмяМакетаСКД);

2. Проинициализировать компоновщик настроек.

КомпоновщикНастроек = Новый КомпоновщикНастроекКомпоновкиДанных
    КомпоновщикНастроек.ЗагрузитьНастройки(СхемаКомпоновкиДанных.НастройкиПоУмолчанию);
    ИсточникНастроек = Новый ИсточникДоступныхНастроекКомпоновкиДанных(СхемаКомпоновкиДанных);
    КомпоновщикНастроек.Инициализировать(ИсточникНастроек);

Можно обойтись и без компоновщика, передавая параметры напрямую, но тогда в настройках необходимо их скрыть, и присваивать напрямую
СхемаКомпоновкиДанных.Параметры.Период.Значение = Период

3. Установить параметры компоновщика настроек

Параметр = КомпоновщикНастроек.Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("Период"));
    Если Не Параметр = Неопределено Тогда
        Параметр.Использование = Истина;
        Параметр.Значение = ЗначениеПараметра;
    КонецЕсли;

4. Получить макет компоновки

ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    Настройки = КомпоновщикНастроек.Настройки;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);

5. Инициировать процессор компоновки данных, процессор вывода и вывести в коллекцию значений или в табличный документ

ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки,, ДанныеРасшифровки);

    ЭлементыФормы.ДокументРезультат.Очистить();

    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ЭлементыФормы.ДокументРезультат);

    ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);