Кастомизация
17
Авг
12

Запуск бизнес-процессов с помощью JavaScript

Даже при том, что механизм бизнес-процессов в CRM 4.0 поддерживает массу способов срабатывания, могут быть случаи, когда треуется более сложная логика их запуска (чем простые события) или более простая – по кнопке на форме или в представлении (что предпочтительно для рутинных задач).

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

Бизнес-процесс

Создайте бизнес-процесс для объекта Обращение, единственным шагом которого будет изменение статуса на Закрыто! Публикуйте.

Откройте окно настройки бизнес-процесса снова (если Вы его уже закрыли) и нажмите Ctrl + N, откроется новое окно браузера, в котором будет все то же окно настройки бизнес-процесса плюс адресная строка, в которой, в свою очередь, будет GUID бизнес-процесса. Скопируйте его куда-нибудь – он нам позже понадобится (также нужный GUID можно посмотреть в табличке WorkflowBase)!


Вызов с формы

Для этого воспользуемся CRM’ной функцией launchOnDemandWorkflowForm. Добавим кнопку на форму объекта Обращение:

  • Выгрузите файл ISV.Config и откройте его в каком-нибудь тектовом редакторе;
  • Добавьте в него следующий код:
    <Entity name="incident">
    	<ToolBar ValidForCreate="0" ValidForUpdate="1">
    		<Button Icon="/_imgs/bar_bottom_ico_home.gif" JavaScript="launchOnDemandWorkflowForm('', '112','{82F70D59-8FBA-4809-8178-A3161173440E}');" PassParams="1" WinParams="" WinMode="0">
    			<Titles>
    				<Title LCID="1049" Text="Инцидент решен" />
    			</Titles>
    			<ToolTips>
    				<ToolTip LCID="1049" Text="Инцидент решен" />
    			</ToolTips>
    		</Button>
    	</ToolBar>
    </Entity>
    

    Пояснение… функции launchOnDemandWorkflowForm мы передали три параметра: первый пустой (всегда), второй это id объекта на который настроен бизнес-процесс (в данном случаи это Обращение), а последний это id самого бизнес-процесса!

  • Экспортируйте ISV.Config обратно!
  • Если Вы этого еще не сделали, то включите отображение настраеваемых меню в CRM системе: Параметры — Администрирование — Системные параметры — вкладка Настройка — секция Настраиваемые меню и панели инструментов – добавьте те клиенты, в которых хотите показывать кастомные кнопки!
  • Откройте какое-нибудь активное Обращение и нажмите на новую кнопку! Появится вопрос с подтверждением, жмите ОК – запусится бизнес-процес (Вы можете наблюдать есо в Системных заданиях или в разделе Бизнес-процессы на левой навигационной панели). Через некоторое время (после того как бизнес-процесс отработает) обращение перейдет в неактивное состояние!



Вызов из представления

Также используем стандартную CRM’ную функцию, но на этот раз она называется launchOnDemandWorkflow! В отличие от предыдущей первый парметр у нее всегда должен быть равен crmGrid (остальные такие же):

  • Снова выгрузите ISV.Config и добавьте в него следующий код:
    <Entity name="incident">
    	<Grid>
    		<MenuBar>
    			<Buttons>
    				<Button Icon="/_imgs/bar_bottom_ico_home.gif" JavaScript="launchOnDemandWorkflow('crmGrid', '112','{82F70D59-8FBA-4809-8178-A3161173440E}');" PassParams="1" WinParams="" WinMode="0">
    					<Titles>
    						<Title LCID="1049" Text="Инцидент решен" />
    					</Titles>
    					<ToolTips>
    						<ToolTip LCID="1049" Text="Инцидент решен" />
    					</ToolTips>
    				</Button>
    			</Buttons>
    		</MenuBar>
    	</Grid>
    </Entity>
    
  • Импортируйте обратно ISV.Config и наблюдает новую кнопочку на панели инструментов представленя объекта Обращения! Там же и протестируйте!

Как Вы понимаете, в представлении можно выбрать несколько записей и применить к ним всем нужный воркфлоу по одной кнопке!

Вызов с помощью Web-сервиса

Использование вышеописанных функции является не поддерживаемым методом, т.к. используются не документированные функции. Поэтому Вы можете воспользоваться вызовом web-сервиса (который является абсолютно поддерживаемым, но более гроздким). Итак, предположим, мы хотим закрыть Обращение после того, как изменили поле Степень удовлетворенности. Добавьте на событие поля Степень удовлетворенности следующий код:

/* объявляем функцию */
ExecuteWorkflow = function(entityId, workflowId) {

var xml = "" +
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" + GenerateAuthenticationHeader() +
"	<soap:Body>" +
"		<Execute xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices\">" +
"			<Request xsi:type=\"ExecuteWorkflowRequest\">" +
"				<EntityId>" + entityId + "</EntityId>" +
"				<WorkflowId>" + workflowId + "</WorkflowId>" +
"			</Request>" +
"		</Execute>" +
"	</soap:Body>" +
"</soap:Envelope>" +
"";

var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
xmlHttpRequest.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
xmlHttpRequest.setRequestHeader("SOAPAction","http://schemas.microsoft.com/crm/2007/WebServices/Execute");
xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlHttpRequest.setRequestHeader("Content-Length", xml.length);
xmlHttpRequest.send(xml);

var resultXml = xmlHttpRequest.responseXML;
return(resultXml.xml);

}

// вызываем бизнес-процесс
ExecuteWorkflow(crmForm.ObjectId, "82F70D59-8FBA-4809-8178-A3161173440E"); // измените на Id Вашего бизнес-процесса

Тестируем: создайте новое обращение, введите обязательные поля, сохраните (если не сохраним не будет записи, а не будет записи не сможем применить к ней бизнес-процесс), измените поле Степень удовлетворенности. Все 🙂 на связанном представлении можете любоваться как постепенно закрывается Вам инцидент!



Этот же скрипт можно встроить и в ISV.Config (для любителей саппорта 🙂 )! Например, так (измените только id бизнес-процесса в третьей переменной):

<Entity name="incident">
	<ToolBar ValidForCreate="0" ValidForUpdate="1">
		<Button JavaScript="
		var caseid = crmForm.ObjectId;
		var authenticationHeader = GenerateAuthenticationHeader();
		var workflowid = &quot;82F70D59-8FBA-4809-8178-A3161173440E&quot;;
		var xml = &quot;&lt;?xml version=&apos;1.0&apos; encoding=&apos;utf-8&apos;?&gt;&quot;+
		&quot;&lt;soap:Envelope xmlns:soap=&apos;http://schemas.xmlsoap.org/soap/envelope/&apos;&quot;+
		&quot; xmlns:xsi=&apos;http://www.w3.org/2001/XMLSchema-instance&apos;&quot;+
		&quot; xmlns:xsd=&apos;http://www.w3.org/2001/XMLSchema&apos;&gt;&quot;+
		authenticationHeader+
		&quot;&lt;soap:Body&gt;&quot;+
		&quot;&lt;Execute xmlns=&apos;http://schemas.microsoft.com/crm/2007/WebServices&apos;&gt;&quot; +
		&quot;&lt;Request xsi:type=&apos;ExecuteWorkflowRequest&apos;&gt;&quot; +
		&quot;&lt;EntityId&gt;&quot; + caseid + &quot;&lt;/EntityId&gt;&quot; +
		&quot;&lt;WorkflowId&gt;&quot; + workflowid + &quot;&lt;/WorkflowId&gt;&quot; +
		&quot;&lt;/Request&gt;&quot; +
		&quot;&lt;/Execute&gt;&quot; +
		&quot;&lt;/soap:Body&gt;&quot; +
		&quot;&lt;/soap:Envelope&gt;&quot;
		var xHReq = new ActiveXObject(&quot;Msxml2.XMLHTTP&quot;);
		xHReq.Open(&quot;POST&quot;, &quot;/mscrmservices/2007/CrmService.asmx&quot;, false);
		xHReq.setRequestHeader(&quot;SOAPAction&quot;,&quot;http://schemas.microsoft.com/crm/2007/WebServices/Execute&quot;);
		xHReq.setRequestHeader(&quot;Content-Type&quot;, &quot;text/xml; charset=utf-8&quot;);
		xHReq.setRequestHeader(&quot;Content-Length&quot;, xml.length);
		xHReq.send(xml);
		" ValidForCreate="0" ValidForUpdate="1">
		<Titles>
			<Title LCID="1049" Text="Закрываем инцидент"/>
		</Titles>
		</Button>
	</ToolBar>
</Entity>



Обратите внимание, что все служебные символы для xml-файла заменены, так называемыми, ссылками на сущность (т.е., например, левая угловая скобка < заменена на &lt; и т.д. с дргими заменителями и, вообще, более подробно с форматом xml можете ознакомится в педивикии).

Комментарии (12)
  • oikcom 17.08.2009

    А нельзя ли что ни будь добавить в скрипт (кнопка на форме) чтобы запись еще и обновилась, в моем workflow запись меняет statuscode и соответственно устаревает, по этому нужно нажать на кнопку, закрыть запись, снова открыть запись, при таком кол-ве действий, убивается актуальность самой кнопки, просто вроде как у Вас где то были скрипты, для действий с записями, ни как не найду где…. 🙂
    Спасибо

  • slivka_83 17.08.2009

    нужно использовать что-то вроде:

    window.location.reload();
    

    или

    history.go(0);
    

    или

    window.location.href = window.location.href;
    
  • oikcom 17.08.2009

    Простите за навязчивость наверно уже не в тему — работает — history.go(0); причем очень быстро, workflow не успевает за этим, а есть ли возможность вставить перед это функцией задержку на пару сек.

  • oikcom 17.08.2009

    Я так думаю сегодня мы создали полноценный пост — по поводу открытия возможности редактирования завершенных действий электропочты с помощью кнопки на форме
    Большое Вам спасибо.

  • slivka_83 17.08.2009

    Пару сек не поможет 🙂 Точнее не обязательно поможет. Бизнес-процессы работают асинхронно и скорость их выполнения зависит от нагрузки на сервер. Может быть и две секунды а может и 10 🙂
    Задержку можно сделать так:

    setTimeout('history.go(0)', 1000);
    

    где 1000 это в милисекундах 🙂 а 1000 милисекунд = 1 секуда

  • oikcom 17.08.2009

    Даже при задержке в одну сек все работает на всякий случай поставил 3
    Спасибо

  • oikcom 17.08.2009

    Здравствуйте.
    А не подскажите, можно с помощью js, откруть запись, созданную с помощью данного бизнес процеса, запускаемого кнопкой на форме, ну то есть, как бы, — кнопка преобразовать запись, js создает новую запись, соответственно старая (на которой кнопка) закрывается со статусом дезактивировано, а новая (созданная) открывается, здесь собственно вся более менее понятно, кроме того как найти новую запись, чтобы открыть? Если это вообще можно…
    Спасибо.

  • slivka_83 17.08.2009

    Добрый день… очень непонятно описано 🙂
    Если я правильно понял, то Вам нужно узнать GUID записи созданную бизнес-процессом, который запускается по кнопке? если да, то ответ никак! Точнее точно узнать нельзя. Бизнес-процессы работают асинхронно. Соттветственно Вы его запустили а он может выполниться через час, когда юзвер уже комп выключит 🙂 Поэтому разве что выполнить какой-нить апосредственный поиск…

  • oikcom 17.08.2009

    Да все правильно, я просто хотел дописать JS кнопки, запускающий бизнес процес, который в свою очередь, создает новую запись, так, чтобы по нажатию этой кнопки, запись с кнопкой закрывалась, а новая созданная открывалась. Но при этом, не понимал, как вызвать (найти) новую запись. Хорошо что спросил, а тоб дальше бы искал.
    Спасибо Слава, еще раз отдельное спасибо за ваш сайт (проект) по мелкомягкому. Если нужно как то поддержать всегда рад, пишите.

  • Александр 17.08.2009

    Добрый день, подскажите пожалуйста, а можно как то БП или еще чем то толкать зависшие БП, которые при отработке падают с ошибкой и зависают в стадии ожидание.

  • Александр 17.08.2009

    С помощью трассировки выяснил что возникает такая ошибка.
    Transaction (Process ID 68) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
    Как ее можно побороть?

  • slivka_83 17.08.2009

    Вот один из способов поборот ее: http://ersinozturk.blogspot.com/2009/11/deadlocks-in-ms-crm-database.html
    Но мне если честно не нравятся такие изменения в БД.

*

code