Записки на лету

С версии 2013 появилось несколько новых методов нотификации пользователя при работе на форме. Расскажу про них и в каких случаях можно их использовать.

1. Поддерживаемая версия alert().

Раньше мы использовали стандартный alert("Сообщение!");

Теперь у нас есть два варианта:

  1. Простое сообщение: Xrm.Utility.alertDialog(message,onCloseCallback);
    где onCloseCallback колбэк функция выполняемая после нажатия кнопки ОК окошка сообщения.
    Пример использования (Проверять на загрузке формы заполнение поля и если оно не заполнено то просить его заполнить и ставить в него фокус):

    function formOnLoad() {
        /// <summary>Функция, вызываемая при загрузки формы</summary>
        if (Xrm.Page.getAttribute("mobilephone") && !Xrm.Page.getAttribute("mobilephone").getValue()) {
            Xrm.Utility.alertDialog("Не заполнен мобильный телефон",
                function () {
                    Xrm.Page.getControl("mobilephone").setFocus();
                });
        }
    }

    AlertMessage

  2. Диалог подтверждения: Xrm.Utility.confirmDialog(message,yesCloseCallback,noCloseCallback);
    где yesCloseCallback колбэк функция выполняемая после нажатия кнопки ОК окошка сообщения и noCloseCallback колбэк функция выполняемая после нажатия кнопки ОК окошка сообщения.
    Пример использования (Проверять на сохранении формы заполнение поля и если оно не заполнено то предложить его заполнить и ставить в него фокус):

    function formOnSave(context) {
        /// <summary>Функция, вызываемая при сохранении формы</summary>  
        if (Xrm.Page.getAttribute("mobilephone") && !Xrm.Page.getAttribute("mobilephone").getValue()) {
            Xrm.Utility.confirmDialog("Не заполнен мобильный телефон. Заполнить?",
                // Если нажали ОК
                function () {
                    // Ставим фокус
                    Xrm.Page.getControl("mobilephone").setFocus();
                    //Отменяем сохранение
                    var eventArgs = context.getEventArgs();
                    eventArgs.preventDefault();
                },
                // Если нажали Cancel
                function () {
                    // Ничего не делаем
                });
        }
    }

    AlertDialogMessage

2. Панель нотификации.

Тоже самое можно реализовать с помощью панели нотификации.

Xrm.Page.ui.setFormNotification(message, level, uniqueId);

где:

  • message (string) — сам текст сообщения.
  • level (string) — тип иконки, возможные варианты: «ERROR» , «WARNING», «INFO».
  • uniqueId (string) — идентификатор сообщения (используется для убирания конкретного сообщения).

При добавлении исполнении следующих строк:

Xrm.Page.ui.setFormNotification('Произошла ошибка...!', 'ERROR');
Xrm.Page.ui.setFormNotification('Предупреждение...', 'WARNING');
Xrm.Page.ui.setFormNotification('Для информации', 'INFORMATION');

Мы увидим следующее.

NotificationMessages

Но тут необходимо помнить, что свое сообщение необходимо скрывать явно, т.к. иначе оно будет висеть до перезагрузки формы. Для чего нам и необходим третий параметр uniqueId, без него мы сможем только скрыть все сообщения, а на форме могут быть еще другие сообщения, как наши так и системные.

Скрываются сообщения так:

Xrm.Page.ui.clearFormNotification();          // Все сообщения
Xrm.Page.ui.clearFormNotification(uniqueId);  // Сообщение с идентификатором uniqueId

Попробуем реализовать пример выше с использованием понели нотификации. Нам понадобятся две функции, на загрузку формы formOnLoad() и на изменение поля Мобильный телефон mobilePhoneOnChange().

function formOnLoad() {
    /// <summary>Функция, вызываемая при загрузки формы</summary>
    if (Xrm.Page.getAttribute("mobilephone") && !Xrm.Page.getAttribute("mobilephone").getValue()) {
        Xrm.Page.ui.setFormNotification("Не заполнен мобильный телефон", 'WARNING', "mobilephoneAlert");
    }
}

function mobilePhoneOnChange() {
    /// <summary>Функция, вызываемая при изменении поля телефон</summary>
    if (Xrm.Page.getAttribute("mobilephone") && !Xrm.Page.getAttribute("mobilephone").getValue()) {
        Xrm.Page.ui.setFormNotification("Не заполнен мобильный телефон", 'WARNING', "mobilephoneAlert");
    } else {
        Xrm.Page.ui.clearFormNotification("mobilephoneAlert");
    }
}

Выглядеть будет так.NotificationMessages2

3. Нотификация поля.

Третий вариант, который мы можем использовать это нотификация непосредственно на поле, что актуально при сообщении касающегося какого-то конкретного поля. Это очень похоже на предыдущий вариант:

Xrm.Page.getControl(fieldName).setNotification(message, uniqueId);  // Показать сообщение
Xrm.Page.getControl(fieldName).clearNotification(uniqueId);         // Скрыть сообщение

где:

  • fieldName (string) — имя поля.
  • message (string) — текст сообщния.
  • uniqueId (string) — идентификатор сообщения (используется для убирания конкретного сообщения).

Выглядит так:NotificationMessages3

Кстати, пока Вы видите такое сообщение CRM не даст Вам сохранить форму.

Соответственно, наш пример будет выглядеть так:

function formOnLoad() {
    /// <summary>Функция, вызываемая при загрузки формы</summary>
    if (Xrm.Page.getAttribute("mobilephone") && !Xrm.Page.getAttribute("mobilephone").getValue()) {
        Xrm.Page.getControl("mobilephone").setNotification("Не заполнен мобильный телефон", "EmptyMobilephoneAlert");
    }
    else {
        Xrm.Page.getControl("mobilephone").clearNotification("EmptyMobilephoneAlert");
    }
}

function mobilePhoneOnChange() {
    /// <summary>Функция, вызываемая при изменении поля телефон</summary>
    if (Xrm.Page.getAttribute("mobilephone")) {
        if (!Xrm.Page.getAttribute("mobilephone").getValue()) {
            Xrm.Page.getControl("mobilephone").setNotification("Не заполнен мобильный телефон", "EmptyMobilephoneAlert");
        } else {
            Xrm.Page.getControl("mobilephone").clearNotification("EmptyMobilephoneAlert");
        }
    }
}

Такого же результата мы можем достигнуть создав «Бизнес-правило».AlertBusinessRule

В результате, CRM также добавит скрипт на форму, сгенеренный по этому правилу. Если кому интересно, ниже скрипт сгенеренный для приведенного правила.

 

function pbl_eb4eb395d711e61180ce00155de610f8() {
    try {
        var v0 = Xrm.Page.data.entity.attributes.get('mobilephone');
        var v2 = '';
        if ((v0 == undefined || v0 == null || v0 === ""))
        { return; }
        var v1 = v0.getValue();
        if ((v1) == undefined || (v1) == null || (v1) === "") {
            v0.controls.forEach(function (c, i) {
                c.setNotification(Mscrm.BusinessRulesScript.GetResourceString('e59db157-30ca-9aa2-05c3-d3da4ac312c0', 'Не заполнен мобильный телефон'), 'eb4eb395-d711-e611-80ce-00155de610f8SetMessageStep4');
            });
            v2 = v2 + 'eb4eb395-d711-e611-80ce-00155de610f8SetMessageStep4\x3b';
        }
        var v3 = [{ 'CId': 'mobilephone', 'SId': 'eb4eb395-d711-e611-80ce-00155de610f8SetMessageStep4' }];
        for (var i = 0; i < v3.length; i++) {
            var l1 = v3[i];
            if (v2.indexOf(l1.SId + '\x3b') === -1) {
                Xrm.Page.data.entity.attributes.get(l1.CId).controls.forEach(function (c, i) { c.clearNotification(l1.SId); });
            }
        }
    } catch (e) {
        Mscrm.BusinessRules.ErrorHandlerFactory.getHandler(e, arguments.callee).handleError();
    }
}
Mscrm.BusinessRulesScript.Initialize = function () {
    Mscrm.BusinessRulesScript.AttributesOnChangeHandlers = {};
    (function () {
        var onchangehandler = function () {
            pbl_eb4eb395d711e61180ce00155de610f8();
        };
        Mscrm.BusinessRulesScript.AttributesOnChangeHandlers['mobilephone'] = onchangehandler;
        var attributeObject = Xrm.Page.data.entity.attributes.get('mobilephone');
        if (attributeObject != null && attributeObject != undefined) {
            attributeObject.addOnChange(onchangehandler);
        }
    })(); pbl_eb4eb395d711e61180ce00155de610f8();
};

4. Всплывающая подсказка tooltip.

Также, следует помнить, что всплывающие подсказки для полей в CRM уже реализованы. По-умолчанию всплывающей подсказкой для поля является описание в настройках поля.AlertTooltipSettings

AlertTooltip

 

Вышла очередная версия MS Dynamics CRM версия 2016. Хотя кое-что в ней до сих пор от 2011 версии, диалоги например.

Но сегодня речь пойдет не об этом. А о том с какими сложностями я встретился при переносе решения с 2013/2015 на 2016.

Начнем с той части где оказалось больше всего проблем, а именно, с форм. Начиная с версии 2015 Update 1 в CRM появился новый движок рендеринга форм (подробнее здесь Microsoft Dynamics CRM Online 2015 Update 1 – New Form Rendering Engine) на котором перестал работать почти весь «Unsupported» код, который я использовал еще с версии 2011. А кому сейчас легко, клиент всегда прав и если он говорит — «Хочу так!», то приходится делать как говорят.

Для тех, кто не хочет вникать в детали и хочет просто чтобы все работало как раньше скажу сразу, что есть волшебная галочка которая отключает новые формы и возвращает старые.

Находится она по такому пути: Параметры -> Администрирование -> Системные параметры Вкладка Общие сведения где в самом низу есть секция Использовать отображение форм предыдущих версий где есть единственный пункт Для совместимости использовать подсистему отображения форм предыдущих версий. Учтите, что это может отрицательно влиять на производительность вот напротив него ставим Да.

Перво наперво с форм пропал jQuery. И почти на каждой странице я стал получать ошибку: «ReferenceError: $ is not defined»

Оказалось, что кастомные скрипты теперь грузятся в отдельном фрейме и jQuery на самом деле есть но уровнем выше.

Лечится так:

 

if (typeof($) === 'undefined') {
    $ = parent.$;
    jQuery = parent.jQuery;
}

Так же исчезла внутренняя функция Mscrm.InlineDialogUtility.createInlineDialog(), которую я использовал для создания кастомных диалогов. Пример использования такой:

 

var url = Mscrm.CrmUri.create(String.format("$webresource:{0}", "gz_/html/datainputdialog.html"));
var dlgOptions = {};
dlgOptions.param1 = "Some param";   
var url = Mscrm.CrmUri.create(String.format("$webresource:{0}", "YouWebResourceName")

Mscrm.InlineDialogUtility.createInlineDialog(url, dlgOptions, width, height, left, top, zindex);

Но, осталась функция Xrm.Internal.openDialog(), пример использования такой:

 

var url = Mscrm.CrmUri.create(String.format("$webresource:{0}", "gz_/html/datainputdialog.html"));
var dlgOptions = {};
params.sl_contact = { id: Xrm.Page.data.entity.getId(), typename: 'contact' };       
var DialogOption = new Xrm.DialogOptions;
DialogOption.width = 640; DialogOption.height = 440;
Xrm.Internal.openDialog(url.toString(), DialogOption, params, null, CallbackFunction);
function CallbackFunction(returnValue){
}

И в диалоге, если надо вернуть параметр в колбэк фунцию то это делается с помощью следующего скрипта:

 

var oReturn = {};
oReturn.smeparam = ""someparam;
Mscrm.Utilities.setReturnValue(oReturn);
 try {
    closeWindow(true);
}
catch (e) { }

И в самом веб-ресурсе необходимо добавить ссылку на ClientGlobalContext:

 

<script src="../../ClientGlobalContext.js.aspx" type="text/javascript"></script>

Еще есть у меня функция, которая пробегалась по полям формы и проверяла заполнены ли обязательные поля. Она стала возвращать false когда такого быть не должно. Исходная функция ниже:

 

function checkIfAllFieldsFilled() {
    var attributes = Xrm.Page.data.entity.attributes.get();
    for (var i = 0; i > attributes.length; i++) {
        if (attributes[i].getRequiredLevel() == "required") {
            if (attributes[i].getValue() == null) {
                return false;
            }
        }
    }
    return true;
}

Как оказалось, функция Xrm.Page.data.entity.attributes.get() теперь возвращает поля не только текущей сущности но и связных сущностей тоже, т.е. для Возможной сделки, например, я получил еще и поля связных звонков и т.д.
Решается дополнительной проверкой родителя у поля:

 

function checkIfAllFieldsFilled() {
    var isOk = true;
    Xrm.Page.data.entity.attributes.forEach(function (attribute, index) {
        if (attribute.getParent() 
            && attribute.getParent().getEntityName() === "opportunity" 
            && attribute.getRequiredLevel() === "required") {
            if (attribute.getValue() === null) {
                isOk = false;
            }
        }
    });
    return isOk;
}

Изменилась вестка гридов и объектная модель работы с ними. Про новые методы можно посмотреть здесь Grid objects and methods (client-side reference).

Соответственно, старые «Unsupported» скрипты по подучению выбранных записей не работают. А вот по фильтрации работают, надо только грид надо теперь получать через parent, как и jQuery.

Но зато теперь, получить все или выбранные записи в гриде весьма легко. :-)

В связи со всем вышеперечисленным возникает вопрос: — «А как я пойму включены ли новые формы или нет из самого скрипта?». Ведь получается, что местами придется писать два варианта кода, для новых форм и старых.

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

 

Xrm.Internal.isTurboForm()

Это, что касается скриптов.

С плагинами и процессами проблем почти не было.

Единственное на что я пока наткнулся это ошибка «Method not found: ‘!!0[] System.Array.Empty()’.»

Появилаcь она из-за того что я обновил dll с плагинами ипользуя SDK v.8.0.2 а в нем используется .NET Framework 4.6.1.1 а при установке CRM 2016 ставится 4.6.0.

Лечится установкой .NET Framework 4.6.1.1 на сервере CRM.

Продолжение следует…

На днях очередной раз столкнулся с тем, что Plugin Registration Tool последней версии SDK не работает, не возможно зарегистрировать Custom Workflow или плагин от имени админа.

Проблема решается использованием Plugin Registration Tool более ранней версии SDK (6.0.4).

В связи с чем, выложил у себя все версии SDK в разделе Ресурсы MS Dynamics CRM 2013.

Наконец-то вышел релиз Visual Studio 2015 и Team Foundation Server 2015  соответственно.

О том, что новенького читаем статью на Хабре Релиз Visual Studio 2015 и .NET 4.6.

CRM 2013 QuickStartВышла книга CRM 2013 QuickStart.

Книга описывает, что нового появилось в CRM 2013, а появилось немало. Но, все это не для разработчика. :-)

Что до разработки, то самые большие изменения коснулись форм, т.е. их разметки, она теперь не табличная, и JScript, расширилась объектная модель и jQuery теперь встроен по умолчанию.

Написано все по делу. Авторы мне нравятся.

Microsoft Dynamics Sure Step CoverВышла еще одна книга по MS Dynamics CRM Customer Success with Microsoft Dynamics Sure Step.

Книга о том как правильно внедрять CRM с помощью технологии Sure Step, пока не собираюсь ее читать ибо уже потерял веру в то, что можно делать внедрение по каким-то правилам. Какие-то основы конечно можно будет взять на вооружение но в жизни все совсем не так красиво как в кино и книжках с картинками.

Вышел накопительный пакет обновлений №1 (KB 2891271) для Microsoft Dynamics CRM 2013.
Скачать можно здесь http://www.microsoft.com/ru-ru/download/details.aspx?id=41546.

Ошибки, исправленные в накопительном пакете обновления 1 для Microsoft Dynamics CRM 2013:

  • Сбой публикации CRM отчета уже ссылки родительского отчета в другой отчет с таким же именем.
  • Недопустимый аргумент при переходе для просмотра при поиске связанной сущности.
  • Диаграмма (для любой другой сущности) не отображаются на корейском языке из-за System.ArgumentException: «Из»Malgun Gothic, Segoe UI, 9.5px»значение недопустимо для»единицы».»
  • При переходе от формы, возникает ошибка сценария. «Не удается получить свойство «get_filterType» не определено или значение null, ссылки»
  • Отключение поля флажок, с помощью API-интерфейса JavaScript не работает.
  • Создание рабочего процесса для обновления встречу с полями из о сбое поле интереса. «Произошла непредвиденная ошибка».
  • Скрытие раздела последнего поля не скрывает раздел. Скрытие последнего поля на вкладке вкладке не сворачивается.
  • Не удается создать автоматический полный адрес поля рабочих процессов, как пробелы и знаки табуляции, удаляются, если отсутствуют символы, такие как запятая.
  • Использование быстрого поиска в Outlook, а после этого выбрать расширенный поиск справа, несоответствующие условиям заполняется фильтра расширенного поиска.
  • Повторно импортировать существующие решения не с меткой для не задан код базового языка 1033.
  • Пользователей нельзя связать несколько записей одновременно для связи N:N.
  • CRM 2013 больше не предупреждает, что если вы собираетесь удалить родительскую запись что дочерние записи с набором delete cascade на их отношения к родительскому элементу, также будут удалены.
  • Не удается задать веб-ресурса для видимой в сценарии если Visible по умолчанию не задано в конструкторе.
  • You´ve создаются новые потоки бизнес-процессов и назначена роль безопасности «менеджер по продажам», «администратор» и «настройщик системы», поток процесса. Опубликовать данное изменение и ожидается, что процесс отображается только для этих ролей безопасности.Вместо этого ПФ скрыт для всех пользователей.Вместо этого ПФ скрыт для всех пользователей.
  • При вводе данных в форму кнопки «Сохранить» можно выбрать несколько раз что приводит к несколько из одной записи.
  • Настраиваемая длительность поля Xrm.Page.getAttribute(«durationfield»).getValue() метода возвращает форматированное значение минут like30, вместо 30, как ожидается.
  • При организации удаляется и затем немедленно импортировать обратно, мастер импорта организации неожиданно отображается предупреждение о несоответствие версий.
  • Автосохранение off: форму потеряет панель команд после перехода от и повторном открытии.
  • Рассмотрим созданный бизнес-процесс в случаях наличия в рабочей области задач, связанных с несколько шагов и вы хотите перевести все этапы для другого языка. Решение содержит задачи и случай сущности, а также бизнес-процесса. Экспорт файлов перевода и попробовать изменить их. Вы найдете все имена рабочей области из регистра сущности, но не удается найти те подзадачи, связанной с ней задачей. Поэтому не удается преобразовать их.
  • «Отправить ссылку» не перейти URL-адрес для указанной сущности, при открытии в существующую вкладку браузера.
  • Ошибки возникают при использовании другой стране форматов с атрибутами валюты.
  • При переходе на различные места в CRM, JavaScript исключения, сообщает «Объект».
  • Функция javascript .addCustomFilter не работает должным образом.
  • Вызвана событием, прежде чем удалить рабочий процесс нельзя импортировать в новую организацию.
  • Когда действие электронной почты с неразрешенными электронной почты получателя создается и сохраняется при загрузке по электронной почте, скрытые значения в ПОЛЕ, поле остается пустым.
  • Не удается увидеть «Индекс страницы» на subgrids из панели мониторинга.
  • Опубликованные настройки, изменения не развернуть мобильный клиент постоянно.
  • Возможная сделка закрыта, как реализовано не принимает пользовательские состояния во время закрытия.
  • Заметки элемент управления показывает время, но не Дата заметки, созданные до вчерашнего дня.
  • Мобильные клиенты сбой ошибка пользовательского интерфейса: «Приносим извинения. К сожалению что-то пошло не так во время инициализации приложения. Повторите попытку или перезапустите приложение»
  • Группа доступа не использует правильные метаданные, определяется представление расширенного поиска и таким образом происходит сбой в мобильных клиентов.
  • При создании нового сообщения электронной почты в веб-приложении Microsoft Dynamics CRM 2013 выясняется, невозможно изменить в поле Описание при использовании последней версии Google Chrome.

Вчера был запуск Visual Studio 2013, видео доступно здесь http://events.visualstudio.com/rus/launch-2013-event/

Завтра будет Запуск в Москве в Digital October, можно будет посмотреть онлайн  http://events.techdays.ru/VisualStudio-Launch/2013-11/

.

Скотт Хансельман опубликовал у себя в блоге серию скринкастов о том, что нового в Visual Studio 2013 для веб разработчика SCREENCASTS: What’s New in Visual Studio 2013 — learn over lunch!.

Так же командой ASP.NET опубликован полный список изменений в новой студии касательно ASP.NET и средств веб-разработки ASP.NET and Web Tools for Visual Studio 2013 Release Notes .

В Москве 15 ноября 2013 г. в бизнес-центре Digital October состоится Запуск Visual Studio 2013, регистрация на событие здесь.

Microsoft Dynamics CRM 2013 уже стала доступна в версии он-лайн!

Можно получить доступ прямо сейчас на 30 дней бесплатно.