Saturday, April 18, 2009

MS CRM и Skype

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


Для того чтобы чудо состоялось и можно было позвонить из MS CRM контакту при помощи Skype иду по адресу и скачиваю обёртку для Skype. Кроме того для реализации презенса потребуются иконки состояний скайп. Их можно скачать (как я и сделал) по этой ссылке

Для начала добавлю в карточку контакта (contact) поле, в которое будет заносится имя человека в Skype - например new_skypename и вынесу это поле в карточку контакта. Карточка будет выглядеть примерно так, как показано на скриншоте далее:



Далее выполню экспорт ISV Config. Для этого нужно перейти Settings - Customization - Export Customizations - выбрать в перечне ISV Config, нажать Export Selected Customizations, сохранить полученный файл, разархивировать, открыть его на редактирование. Дальше ищу элемент Entities, в нём - Contact, добавляю в карточку новую кнопку. Полученный XML:

<ImportExportXml version="4.0.0.0" languagecode="1033" generatedBy="OnPremise">
<Entities>
</Entities>
<Roles>
</Roles>
<Workflows>
</Workflows>
<IsvConfig>
<configuration version="3.0.0000.0">
<Root/>
<Entities>
<Entity name="account" />
<Entity name="contact">
<ToolBar ValidForCreate="0" ValidForUpdate="1">
<Button Icon="/ISV/Skype/img/Off.gif" JavaScript="var skypeName = crmForm.all.new_skypename.DataValue; if (skypeName != null &amp;&amp; skypeName != ''){try{Skype.PlaceCall(skypeName);}catch(err){}}">
<Titles>
<Title LCID="1049" Text="Call" />
<Title LCID="1033" Text="Call" />
</Titles>
<ToolTips>
<ToolTip LCID="1049" Text="Call" />
<ToolTip LCID="1033" Text="Call" />
</ToolTips>
</Button>
</ToolBar>
</Entity>
<Entity name="lead" />
<Entity name="opportunity" />
<Entity name="list" />
<Entity name="campaign" />
<Entity name="campaignactivity" />
<Entity name="campaignresponse" />
<Entity name="incident" />
<Entity name="quote" />
<Entity name="salesorder" />
<Entity name="invoice" />
</Entities>
<ServiceManagement>
<AppointmentBook>
<SmoothScrollLimit>2000</SmoothScrollLimit>
<TimeBlocks>
<!-- All CSS Class mapping for Service activities -->
<TimeBlock EntityType="4214" StatusCode="1" CssClass="ganttBlockServiceActivityStatus1" />
<TimeBlock EntityType="4214" StatusCode="2" CssClass="ganttBlockServiceActivityStatus2" />
<TimeBlock EntityType="4214" StatusCode="3" CssClass="ganttBlockServiceActivityStatus3" />
<TimeBlock EntityType="4214" StatusCode="4" CssClass="ganttBlockServiceActivityStatus4" />
<TimeBlock EntityType="4214" StatusCode="6" CssClass="ganttBlockServiceActivityStatus6" />
<TimeBlock EntityType="4214" StatusCode="7" CssClass="ganttBlockServiceActivityStatus7" />
<TimeBlock EntityType="4214" StatusCode="8" CssClass="ganttBlockServiceActivityStatus8" />
<TimeBlock EntityType="4214" StatusCode="9" CssClass="ganttBlockServiceActivityStatus9" />
<TimeBlock EntityType="4214" StatusCode="10" CssClass="ganttBlockServiceActivityStatus10" />
<!-- All CSS Class mapping for Appointments -->
<TimeBlock EntityType="4201" StatusCode="1" CssClass="ganttBlockAppointmentStatus1" />
<TimeBlock EntityType="4201" StatusCode="2" CssClass="ganttBlockAppointmentStatus2" />
<TimeBlock EntityType="4201" StatusCode="3" CssClass="ganttBlockAppointmentStatus3" />
<TimeBlock EntityType="4201" StatusCode="4" CssClass="ganttBlockAppointmentStatus4" />
<TimeBlock EntityType="4201" StatusCode="5" CssClass="ganttBlockAppointmentStatus5" />
<TimeBlock EntityType="4201" StatusCode="6" CssClass="ganttBlockAppointmentStatus6" />
</TimeBlocks>
</AppointmentBook>
</ServiceManagement>
</configuration>
</IsvConfig>
<EntityMaps />
<EntityRelationships />
<Languages>
<Language>1033</Language>
<Language>1049</Language>
</Languages>
</ImportExportXml>


В скрипте по нажатию на создаваемую кнопку - используется объект Skype. О нём - далее.

Открываю форму контакта на редактирование. Открываю скрипт OnLoad карточки. Добавляю туда такой код:

var sk = document.createElement("object");
sk.setAttribute('id', 'Skype');
sk.setAttribute('name', 'Skype');
sk.setAttribute('height', '0');
sk.setAttribute('width', '0');
sk.setAttribute('classid', 'clsid:830690FC-BF2F-47A6-AC2D-330BCB402664');
sk.setAttribute('codebase', '/ISV/Skype/Skype4COM.dll');
document.body.appendChild(sk);

setInterval(function()
{
var userName = crmForm.all.new_skypename.DataValue;
if (userName == null || userName == "")
return;

var res = 0;

for (var i = 1; i <= Skype.Friends.count; i++)
{
if (Skype.Friends.Item(i).Handle == userName)
res = Skype.Friends.Item(i).OnlineStatus;
}

var imgSrc = '/ISV/Skype/img/';

if (res == 1)
imgSrc += 'On.gif';
else if (res == 4)
imgSrc += 'dnd.gif';
else if (res == 2)
imgSrc += 'away.gif';
else if (res == 3)
imgSrc += 'notAvailable.gif';
else
imgSrc += 'off.gif';

var liobj = document.getElementsByTagName('li');
for (var i=0; i < liobj.length; i++)
if (liobj[i].getAttribute('title') == "Call")
{
liobj[i].firstChild.firstChild.firstChild.src = imgSrc;
}
}, 500);


Его суть - в форму путём HTML инъекции добавляется новый объект Skype, который выполняет роль прокси к клиенту Skype, установленного на ПК пользователя и подвешивается таймер, который будет будет каждые полсекунды проверять состояние контакта и отображать его.

Карточку контакта нужно сохранить и опубликовать.
Завершающий штрих - это размещение на сервере библиотеки Skype4COM.dll и изображений статусов на веб-сервере MS CRM. Я разместил библиотеку по пути их по пути C:\Inetpub\wwwroot\ISV\Skype\Skype4COM.dll, а для картинок создал каталог C:\Inetpub\wwwroot\ISV\Skype\img\ и в него поместил картинки состояний.

В результате чего получилась такая форма контакта:



При изменении статуса - картинка на кнопке звонка перерисовывалась в соответствии со статусом, в который перешёл человек. При нажатии на кнопку - выполняется звонок контакту.

Ограничения - для того, чтобы отображение текущего статуса работало корректно необходимо, чтобы человек был в списке контактов.