APDEX: Замеры производительности

Встала задача замерить производительность открытия документов, отчетов и пр.

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

Добавляем в серверный модуль

#Область ОценкаПроизводительности
Функция ОП_СодержитСвойство(Переменная, ИмяСвойства)
	// Инициализируем структуру для теста с ключом (значение переменной "ИмяСвойства") и значением NULL
	СтруктураПроверка = Новый Структура;
	СтруктураПроверка.Вставить(ИмяСвойства, NULL);
	// Заполняем созданную структуру из переданного значения переменной
	ЗаполнитьЗначенияСвойств(СтруктураПроверка, Переменная);
	// Если значение для свойства структуры осталось NULL, то искомое свойство не найдено, и наоборот.
	Если СтруктураПроверка[ИмяСвойства] = NULL Тогда
		Возврат Ложь;
	Иначе
		Возврат Истина;
	КонецЕсли;
КонецФункции
 
Процедура ОП_НачатьЗамерФорма(Форма) Экспорт
	Если НЕ ОП_СодержитСвойство(Форма, "ИМС_ЗамерПроизводительности") Тогда
		ОписаниеТипа = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(14, 0, ДопустимыйЗнак.Неотрицательный));
		Реквизиты = Новый Массив;
		Реквизиты.Добавить(Новый РеквизитФормы("ИМС_ЗамерПроизводительности", ОписаниеТипа));
		Форма.ИзменитьРеквизиты(Реквизиты);
	КонецЕсли;
 
	Форма.ИМС_ЗамерПроизводительности = ОценкаПроизводительности.НачатьЗамерВремени();
КонецПроцедуры
 
Процедура ОП_ЗавершитьЗамерФорма(Форма, Операция = ".Открытие") Экспорт
	Объект = Форма.РеквизитФормыВЗначение("Объект");
 
	ИмяОбъекта = Объект.Метаданные().Имя;
	ОценкаПроизводительности.ЗакончитьЗамерВремени("Имс:"+ИмяОбъекта+Операция,Форма.ИМС_ЗамерПроизводительности);
КонецПроцедуры
 
#КонецОбласти

Дальше, добавляем новое расширение конфигурации. В расширение добавляем требуемые формы документов и на форме:

 
&НаСервере
Процедура ОП_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	РУ.ОП_НачатьЗамерФорма(ЭтаФорма);
КонецПроцедуры
 
 
&НаКлиенте
Процедура ОП_ПриОткрытии(Отказ)
	ОП_ПриОткрытииНаСервере();
КонецПроцедуры
 
 
&НаСервере
Процедура ОП_ПриОткрытииНаСервере()
	РУ.ОП_ЗавершитьЗамерФорма(ЭтаФорма);
КонецПроцедуры
 
 
&НаСервере
Процедура ОП_ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
	Если ПараметрыЗаписи.РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
		РУ.ОП_НачатьЗамерФорма(ЭтаФорма);
	КонецЕсли;
КонецПроцедуры
 
 
&НаСервере
Процедура ОП_ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)
	Если ПараметрыЗаписи.РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
		РУ.ОП_ЗавершитьЗамерФорма(ЭтаФорма,".Проведение");
	КонецЕсли;
КонецПроцедуры

Главное, не забыть снять флаг «Безопасный режим» с расширения. Замеры производительности в безопасном режиме не работают.

Публикация календарей 1С Документооборота в формате ICS

Календари в формате ICS для Документооборота или интеграция документооборота с Outlook.
При внедрени мероприятий в документообороте, всегда вставал вопрос: а в Outlook календарь можно импортировать? Стандартный документооборот не позволяет этого. Пришлось сделать расширение реализующее календарь в виде http сервиса.

Тестировался на Документооборот 8 КОРП, редакция 2.1 (2.1.9.3) и 1С:Предприятие 8.3 (8.3.8.2197)

По аналогии можно сделать и для других платформ.

Путь к календарям: http[s]://{веб-сервер 1С}/{Имя базы}/hs/ical?room={Имя помещения (переговорной)}

Календарь ICS

Динамические роли в Документообороте 1С через Автоподстановки

Меня всегда удивляло что в 1С Документообороте не работает автоматическая подстановка ролей по объектам адресации. Небольшая доработка и вуаля — теперь работает.

В модуле ШаблоныБизнесПроцессовПереопределяемый

// Возвращает список пользовательских функций для автоподстановки исполнителей в шаблонах бизнес-процессов
// Параметры:
//	ИменаПредметовДляФункций - массив - массив имен предметов для функций автоподстановки
//
Функция ПолучитьСписокДоступныхФункций(ИменаПредметовДляФункций) Экспорт
 
	ДоступныеФункции = Новый СписокЗначений;
	//ДоступныеФункции.Добавить("ШаблоныБизнесПроцессовПереопределяемый.<ИмяФункции>(Объект)", "<Представление функции>");
	rudm_ДобавитьАвтоподстановки(ДоступныеФункции);
 
        Возврат ДоступныеФункции;
 
КонецФункции
 
 
Процедура rudm_ДобавитьАвтоподстановки(ДоступныеФункции)
	ДоступныеФункции.Добавить("ШаблоныБизнесПроцессовПереопределяемый.rudm_ПолучитьРеквизитПредметаБизнесПроцесса((Объект)", "Ответственный за предмет");
 
	Выборка = Справочники.РолиИсполнителей.Выбрать();
	Пока Выборка.Следующий() Цикл
		Если Выборка.ИспользуетсяСОбъектамиАдресации И Выборка.ИспользуетсяБезОбъектовАдресации Тогда
			ДоступныеФункции.Добавить("ШаблоныБизнесПроцессовПереопределяемый.rudm_РольСбъектамиАдресации(Объект,"""+Выборка.Код+""")", Выборка.Наименование);
		КонецЕсли;
	КонецЦикла;
КонецПроцедуры
 
Функция rudm_ПредметОтветственный(БизнесПроцессОбъект) Экспорт
	Возврат rudm_ПолучитьРеквизитПредметаБизнесПроцесса(БизнесПроцессОбъект, "Ответственный");
КонецФункции
 
Функция rudm_ПолучитьОбъектАдресации(БизнесПроцессОбъект, ТипОбъектаАдресации) Экспорт
	Если ТипОбъектаАдресации = ПланыВидовХарактеристик.ОбъектыАдресацииЗадач.Организация Тогда
		возврат ШаблоныБизнесПроцессовПереопределяемый.ПолучитьРеквизитПредметаБизнесПроцесса(БизнесПроцессОбъект, "Организация");
	ИначеЕсли ТипОбъектаАдресации = ПланыВидовХарактеристик.ОбъектыАдресацииЗадач.Контрагент Тогда
		возврат ШаблоныБизнесПроцессовПереопределяемый.ПолучитьРеквизитПредметаБизнесПроцесса(БизнесПроцессОбъект, "Контрагент");
	ИначеЕсли ТипОбъектаАдресации = ПланыВидовХарактеристик.ОбъектыАдресацииЗадач.Подразделение Тогда
		возврат ШаблоныБизнесПроцессовПереопределяемый.ПолучитьРеквизитПредметаБизнесПроцесса(БизнесПроцессОбъект, "Подразделение");
	ИначеЕсли ТипОбъектаАдресации = ПланыВидовХарактеристик.ОбъектыАдресацииЗадач.Проект Тогда
		возврат ШаблоныБизнесПроцессовПереопределяемый.ПолучитьРеквизитПредметаБизнесПроцесса(БизнесПроцессОбъект, "Проект");
	КонецЕсли;
 
	Возврат Неопределено;
КонецФункции
 
Функция rudm_ПолучитьПолнуюРоль(Роль, ОсновнойОбъектАдресации, ДополнительныйОбъектАдресации) Экспорт
 
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	ПолныеРоли.Ссылка  ПолнаяРоль
		|ИЗ
		|	Справочник.ПолныеРоли КАК ПолныеРоли
		|ГДЕ
		|	ПолныеРоли.Владелец = &РольИсполнителя
		|	И ПолныеРоли.ОсновнойОбъектАдресации = &ОсновнойОбъектАдресации
		|	И ПолныеРоли.ДополнительныйОбъектАдресации = &ДополнительныйОбъектАдресации";
 
	Запрос.УстановитьПараметр("ДополнительныйОбъектАдресации", ДополнительныйОбъектАдресации);
	Запрос.УстановитьПараметр("ОсновнойОбъектАдресации", ОсновнойОбъектАдресации);
	Запрос.УстановитьПараметр("РольИсполнителя", Роль);
 
	РезультатЗапроса = Запрос.Выполнить();
 
	ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
 
	Если ВыборкаДетальныеЗаписи.Следующий() Тогда
		Возврат  ВыборкаДетальныеЗаписи.ПолнаяРоль;
	Иначе
		//Если не найдена роль с объектами адресации, ищем роль без них
		Запрос.УстановитьПараметр("ДополнительныйОбъектАдресации", Неопределено);
		Запрос.УстановитьПараметр("ОсновнойОбъектАдресации", Неопределено);
		Запрос.УстановитьПараметр("РольИсполнителя", Роль);
		РезультатЗапроса = Запрос.Выполнить();
		ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
		Если ВыборкаДетальныеЗаписи.Следующий() Тогда
			Возврат  ВыборкаДетальныеЗаписи.ПолнаяРоль;
		КонецЕсли;
	КонецЕсли;
 
	Возврат Неопределено;
КонецФункции // ()	
 
 
Функция rudm_РольСбъектамиАдресации(БизнесПроцессОбъект, КодРоли) Экспорт
	Роль = Справочники.РолиИсполнителей.НайтиПоКоду(КодРоли);
 
	ОсновнойОбъектАдресации = rudm_ПолучитьОбъектАдресации(БизнесПроцессОбъект, Роль.ТипыОсновногоОбъектаАдресации);
	ДополнительныйОбъектАдресации = rudm_ПолучитьОбъектАдресации(БизнесПроцессОбъект, Роль.ТипыДополнительногоОбъектаАдресации);  
 
	СтруктураАдресации = Новый Структура;
	СтруктураАдресации.Вставить("РольИсполнителя", rudm_ПолучитьПолнуюРоль(Роль, ОсновнойОбъектАдресации, ДополнительныйОбъектАдресации));	
 
	СтруктураАдресации.Вставить("ОсновнойОбъектАдресации", ОсновнойОбъектАдресации);
	СтруктураАдресации.Вставить("ДополнительныйОбъектАдресации", ДополнительныйОбъектАдресации);  
 
	Возврат СтруктураАдресации;
 
КонецФункции
 
 
Функция rudm_ПолучитьРеквизитПредметаБизнесПроцесса(БизнесПроцессОбъект, НазваниеРеквизита) Экспорт
 
	Если БизнесПроцессОбъект.Предметы.Количество() > 0 Тогда
		Предмет = БизнесПроцессОбъект.Предметы[0].Предмет;
		Попытка	
			Возврат Предмет[НазваниеРеквизита];
		Исключение
		КонецПопытки;	
	КонецЕсли;
	Возврат  Неопределено;
КонецФункции

Custom segue

Промучился вечер с настраиваемыми Segue. На новое окно переходило, а обратно — никак. Возвращаешь стандартный Segue — все работает. Фишка оказалась в порядке вызова функции present.

Изначальный вариант выглядел так:

class FlipSegue: UIStoryboardSegue {
 
    override func perform() {
        let fromViewController = self.source
        let toViewController = self.destination
 
        UIView.transition(from: fromViewController.view, to: toViewController.view, duration: 0.5, options: .transitionFlipFromLeft ) {
            fromViewController.present(toViewController, animated: false, completion: nil)
        }
    }
}

а правильный так:

class FlipSegue: UIStoryboardSegue {
 
    override func perform() {
        let fromViewController = self.source
        let toViewController = self.destination
 
        fromViewController.present(toViewController, animated: false, completion: nil)
        UIView.transition(from: fromViewController.view, to: toViewController.view, duration: 0.5, options: .transitionFlipFromLeft )
    }
}

притом unwind segue должно быть таким:

class UnFlipSegue: UIStoryboardSegue {
    override func perform() {
        let fromViewController = self.source
        let toViewController = self.destination
 
 
        UIView.transition(from: fromViewController.view, to: toViewController.view, duration: 0.5, options: .transitionFlipFromRight) { _ in
            fromViewController.dismiss(animated: false, completion: nil )
        }
    }
 
}

Интересная статистика

Divination под Android делит установки, практически поровну, между 4, 5 и 6 версией. Установок на 7-й версии — мизер.

А вот Apple, статистику распределения по версиям, не дает. Зато дает распределение между планшетом и телефоном 10% к 90%. На Android, распределение между телефонами и планшетами, аналогичное.

Сравнивать доходность между двумя платформами пока нельзя, слишком разное количество установок. Но вот доход на тысячу показов у iOS версии в 10 раз больше чем у Android.

Реклама

Рекламный сервис Apple iAD приказал долго жить.  Это сподвигло меня перейти на Google Admob и теперь я могу сравнить эти две рекламные площадки.

  1. Интеграция iAD в приложение намного проще. Для Admob надо не только подключить сам фреймворк, но и добавить в проект кучу фреймворков от которых он зависит. iAD вытащил на форму и забыл, а для Admob надо еще прописать запрос на получение рекламы.
  2. По возможности кастомизации лидирует Admob. Ему можно указать ключевые слова, местоположение, пол, возраст…  Учитывает ли данные пользователя и местоположение iAD — не знаю. Но ключевые слова он точно не учитывал, а жаль.
  3. Доходы iAD и Admob давали сопоставимые. Правда сравнивать можно только первые месяцы размещения рекламы. Под конец использования iAD сильно «сдулся». А Admob еще не так долго эксплуатировался, что бы делать какие-то выводы.

В общем и целом, могу сказать что реклама себя оправдывает. Если не лениться, делать качественные приложение, рекламировать их, поддерживать, развивать (а не почивать на лаврах) мобильной рекламой вполне можно жить.

Хотя создать одно приложение и разбогатеть, это скорее исключение чем правило.

Получить целые числа языком запросов 1С

Интересная задачка с собеседования — получить средствами языка запросов числа от -500 до 500. Само решение тривиально, но для него нужно получить перечень чисел от 0 до… ну хотя бы до 500. А это уже интереснее. Одно из возможных решений приведено ниже. Продолжая подставляя степени двойки можно получить очень длинную последовательность целых чисел.

ВЫБРАТЬ
0 КАК Числа
ПОМЕСТИТЬ Шаг0
 
ОБЪЕДИНИТЬ ВСЕ
 
ВЫБРАТЬ
1
;
 
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Лево.Числа * 2 + Право.Числа КАК Числа
ПОМЕСТИТЬ Шаг2
ИЗ
Шаг0 КАК Лево,
Шаг0 КАК Право
;
 
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Лево.Числа * 4 + Право.Числа КАК Числа
ПОМЕСТИТЬ Шаг4
ИЗ
Шаг2 КАК Лево,
Шаг2 КАК Право
;
 
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Лево.Числа * 8 + Право.Числа КАК Числа
ПОМЕСТИТЬ Шаг8
ИЗ
Шаг4 КАК Лево,
Шаг4 КАК Право
;
 
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Лево.Числа * 16 + Право.Числа КАК Числа
ПОМЕСТИТЬ Шаг16
ИЗ
Шаг8 КАК Лево,
Шаг8 КАК Право
;
 
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Лево.Числа * 32 + Право.Числа КАК Числа
ИЗ
Шаг16 КАК Лево,
Шаг16 КАК Право

IIS & 1C

Если веб-интерфейс у 1С не работает, не отображает элементы,  выходят ошибки  и т.п. можно попробовать отредактировать web.config на сервере IIS:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
   <system.webServer>
      <handlers>
         <remove name="ISAPI-dll" />
         <add name="1C Web-service Extension" path="*" verb="*" modules="IsapiModule" scriptProcessor="C:\Program Files\1cv8\8.3.5.1443\bin\wsisapi.dll" resourceType="Unspecified" requireAccess="None" />
         <add name="ISAPI-dll" path="*" verb="*" modules="IsapiModule" scriptProcessor="C:\Program Files\1cv8\8.3.5.1443\bin\wsisapi.dll" resourceType="File" requireAccess="Execute" allowPathInfo="true" preCondition="bitness64" />
      </handlers>
   </system.webServer>
</configuration>