Communardo Software GmbH, Kleiststraße 10 a, D-01129 Dresden

Die Integration von Microsoft Dynamics 365 in Jira Data Center

Sie möchten Microsoft Dynamics und Ihr Atlassian Jira miteinander verbinden? Lesen Sie, wie uns die Integration gelungen ist.

Die Ablösung unse­res bis­he­ri­gen Customer-Relationship-Management (CRM) Systems durch Microsoft Dynamics war ein gro­ßes Unterfangen. Ein Projektteam aus Mitgliedern ver­schie­de­ner Abteilungen stellte sicher, dass es einen mög­lichst rei­bungs­lo­sen Übergang für unsere Mitarbeiter gab.  Ein wich­ti­ger Aspekt dabei war, dass unsere Kollegen wei­ter­hin wie bis­her gewohnt ihre Kundendaten direkt in den Jira-Tickets nut­zen kön­nen, z.B. die Kontaktdaten eines Kunden oder wich­tige ver­trieb­li­che Informationen zu Aufträgen oder Lizenzen. Da wir keine für unsere Zwecke pas­sende Marketplace-App gefun­den haben, ent­wi­ckel­ten wir eine eigene Jira-App, wel­che die Kommunikation mit Dynamics übernimmt.

Im Folgenden möchte ich Ihnen auf­zei­gen, wel­che Voraussetzungen dafür erfüllt sein muss­ten, wie die tech­ni­sche Umsetzung erfolgte und wel­chen Herausforderungen wir uns dabei stel­len mussten.

blank

Bevor es los­ge­hen kann

Damit unsere Jira-App die Microsoft Dynamics Services nut­zen kann, ist eine Registrierung der Anwendung im Microsoft Azure Portal nötig.

blank

Dort bekommt die Jira-Anwendung ein­deu­tige IDs zuge­ord­net. Dadurch wird sicher­ge­stellt, dass Dynamics Anfragen von unse­rem Jira akzep­tiert. Denn die Kommunikation zwi­schen den bei­den Anwendungen läuft aus­schließ­lich über die Common Data Service Web API von Dynamics, eine RESTful API. Da die Web API auf offe­nen Standards auf­baut, kann sie mit ver­schie­de­nen Programmiersprachen und Plattformen ver­wen­det wer­den. In unse­rem Fall erfol­gen die Anfragen an Dynamics durch eine JavaScript-Lösung.

Komponenten der Jira-App

Unsere Jira-App besteht aus zwei Teilen: einem Konfigurationsteil (umge­setzt mit­tels Atlassian SDK) und dem Kommunikationsteil (umge­setzt mit­tels JavaScript). 

Im Konfigurationsteil erzeu­gen wir eine Konfigurationsseite in der Jira-Administration und tra­gen dort die im vor­he­ri­gen Abschnitt erwähn­ten ein­deu­ti­gen Identifikatoren aus dem Azure Portal ein. Somit kann sich unsere App spä­ter bei Dynamics authentifizieren.

blank

Der JavaScript-Part ist für die Kommunikation zwi­schen Jira und Dynamics zustän­dig und stellt die Verbindung zwi­schen bei­den Welten her. Wir haben uns für eine client-seitige Umsetzung via JavaScript ent­schie­den, um Berechtigungsprüfungen im Client zu ermög­li­chen und die Last auf dem Jira-Server so gering wie mög­lich zu halten. 

Authentifizierung bei Dynamics

Damit die Dynamics-Daten in Jira genutzt wer­den kön­nen, muss sich der User zunächst via Popup-Dialog in sein Microsoft-Online-Konto ein­log­gen und authen­ti­fi­zie­ren. Dabei wird nur OAuth als Authentifizierung unter­stützt. Als Antwort erhält Jira einen Token. Dieser wird nun bei jeder Anfrage an Dynamics im Response-Header mit­ge­schickt. Solange der Token gül­tig ist, erfolgt die Anmeldung bei Dynamics im Hintergrund, ohne dass der Nutzer sich erneut ein­log­gen muss. Für das Authentifizierungshandling ver­wen­den wir die Microsoft Authentication Library und im spe­zi­el­len des­sen JavaScript-Framework MSAL.js

Daten abfra­gen

Die Abfragen der Daten von Dynamics erfol­gen mit­hilfe der oben bereits erwähn­ten RESTful Common Data Service Web API. Da es sich um eine recht kom­plexe API han­delt, stellt Microsoft eine aus­führ­li­che Dokumentation mit vie­len Beispielen zur Verfügung. Grundlage bil­den soge­nannte Entitäten, in unse­rem Fall z.B. account (Firmendaten) und con­tact (Personendaten). Um bei­spiels­weise den Namen und die voll­stän­dige Adresse einer bestimm­ten Firma abzu­fra­gen, wird fol­gende GET-Anfrage an die Dynamics Web API geschickt:

https://<dynamics-crm-url>/api/data/v9.1/accounts(8c48716a-05b9-e911-a827-000d3ab08ce9)?$select=name,address1_composite

Dabei stellt der alpha­nu­me­ri­sche Code 8c48716a-05b9-e911-a827-000d3ab08ce9 die ein­deu­tige ID (accoun­tid) des gewünsch­ten Datensatzes in Dynamics dar. Mit $select= kön­nen die ange­for­der­ten Daten auf bestimmte Attribute ein­ge­schränkt wer­den, in unse­rem Fall auf den Namen und die Adresse. Als Antwort erhält unser Jira die ange­for­der­ten Attribute im JSON-Format:

{
"@odata.context": "https://<dynamics-crm-url>/api/data/v9.1/$metadata#accounts(name,address1_composite)/$entity",
"@odata.etag": "W/\"5822819\"",
"name": "Communardo Software GmbH",
"address1_composite": "Kleiststr. 10a\r\n\r\n01129 Dresden\r\nDeutschland",
"address1_line1": "Kleiststr. 10a",
"accountid": "8c48716a-05b9-e911-a827-000d3ab08ce9",
"address1_city": "Dresden",
"address1_postalcode": "01129",
"address1_country": "Deutschland"
}

Die JSON-Antwort wird nun vom Jira aus­ge­wer­tet und der Firmenname in ein Benutzerdefiniertes Feld ein­ge­tra­gen sowie die Adresse als zusätz­li­che Daten ange­zeigt. Auf diese Weise kön­nen belie­bige Daten aus Dynamics vom Jira abge­fragt und im Vorgangsticket ange­zeigt wer­den. Allerdings gilt hier zu beach­ten, dass je nach Dynamics-Datentyp die Datenabfragen auf spe­zi­elle Weise zu erfol­gen haben. Beispielsweise ist eine zusätz­li­che Abfrage erfor­der­lich, wenn man den les­ba­ren Wert einer Option eines Dynamics Select Fields anzei­gen möchte, da man mit der nor­ma­len Datenabfrage (Beispiel oben) nur die Options-ID (z.B. 181410000) erhält. Der Code muss also ent­spre­chend ange­passt werden.

Welche Felder aus Dynamics in Jira als zusätz­li­che Daten ange­zeigt wer­den sol­len, kann in der Konfiguration fest­ge­legt werden:

blank

Dabei wird unter­schie­den zwi­schen nor­ma­len Attributen einer Entität (Company/Contact Details) und soge­nann­ten Expandable Fields. Es han­delt sich um Attribute, die selbst wie­derum auf eine Entität, also eine Firma oder eine Kontaktperson, ver­wei­sen. Zum Beispiel ent­hält das Firmenattribut com_vertriebsbeauftragter einen Verweis auf die Entität Contact, also eine Kontaktperson. Da diese Expandable Fields eine spe­zi­elle Datenabfrage der Web API benö­ti­gen und damit eine Spezialbehandlung im Code, wer­den sie sepa­rat von nor­ma­len Attributen konfiguriert.

Anfragen bün­deln

Durch diese Komplexität sind teil­weise bis zu vier Abfragen an die Dynamics Web API nötig, um alle kon­fi­gu­rier­ten Attribute eines Firmen-Datensatzes abzu­fra­gen. Um die Anzahl an Anfragen zu ver­rin­gern, bie­tet die Web API die Möglichkeit einer soge­nann­ten Batch-Operation, wel­che wir auch in unse­rer App nut­zen. Dabei wer­den meh­rere Anfragen in einer ein­zi­gen HTTP-Anfrage grup­piert. Laut Dokumentation kön­nen Batch-Anfragen bis zu 1000 indi­vi­du­elle Anfragen ent­hal­ten. Einschränkungen dabei sind, dass die URLs für GET-Anfragen inner­halb der Batch-Anfrage auf 32768 Zeichen limi­tiert ist. Weiterhin darf eine Batch-Anfrage keine ande­ren Batch-Anfragen enthalten.

Batch-Anfragen wer­den als POST-Anfrage via https://<dynamics-crm-url>/api/data/v9.1/$batch an Dynamics gesen­det. Die eigent­li­chen Anfragen wer­den im Request Body als Text mit­ge­schickt, wie im Folgenden anhand von vier GET-Anfragen zu sehen:

--1600928734395
Content-Type: application/http
Content-Transfer-Encoding:binary

GET https://<dynamics-crm-url>/api/data/v9.1/accounts(8c48716a-05b9-e911-a827-000d3ab08ce9)?$select=com_jirasearchfield,address1_composite,address1_fax,com_business_line,com_supportdatenblatt,creditlimit,new_sicherheitsstufe,numberofemployees,com_auftraege,com_supportvertraege HTTP/1.1
Host: localhost:8060

--1600928734395
Content-Type: application/http
Content-Transfer-Encoding:binary

GET https://<dynamics-crm-url>/api/data/v9.1/EntityDefinitions(LogicalName='account')?$select=LogicalName&$expand=Attributes($select=LogicalName,AttributeType,DisplayName;$filter=LogicalName eq 'address1_composite' or LogicalName eq 'address1_fax' or LogicalName eq 'com_business_line' or LogicalName eq 'com_supportdatenblatt' or LogicalName eq 'creditlimit' or LogicalName eq 'new_sicherheitsstufe' or LogicalName eq 'numberofemployees' or LogicalName eq 'com_auftraege' or LogicalName eq 'com_supportvertraege' or LogicalName eq 'com_vertriebsbeauftragter' or LogicalName eq 'new_customerservicemanager' or LogicalName eq 'parentaccountid') HTTP/1.1
Host: localhost:8060

--1600928734395
Content-Type: application/http
Content-Transfer-Encoding:binary

GET https://<dynamics-crm-url>/api/data/v9.1/EntityDefinitions(LogicalName='account')/Attributes/Microsoft.Dynamics.CRM.PicklistAttributeMetadata?$select=LogicalName&$expand=OptionSet($select=Options),GlobalOptionSet($select=Options)&$filter=LogicalName eq 'address1_composite' or LogicalName eq 'address1_fax' or LogicalName eq 'com_business_line' or LogicalName eq 'com_supportdatenblatt' or LogicalName eq 'creditlimit' or LogicalName eq 'new_sicherheitsstufe' or LogicalName eq 'numberofemployees' or LogicalName eq 'com_auftraege' or LogicalName eq 'com_supportvertraege' HTTP/1.1
Host: localhost:8060

--1600928734395
Content-Type: application/http
Content-Transfer-Encoding:binary

GET https://<dynamics-crm-url>/api/data/v9.1/accounts(8c48716a-05b9-e911-a827-000d3ab08ce9)?$select=com_vertriebsbeauftragter,new_CustomerServiceManager,parentaccountid&$expand=com_vertriebsbeauftragter,new_CustomerServiceManager,parentaccountid HTTP/1.1
Host: localhost:8060

--1600928734395--

Als Antwort erhält man eben­falls ein Text-Dokument, wel­ches geparst und als JSON abge­spei­chert wer­den kann, z.B.:

--batchresponse_6f7cbc73-6da4-478e-85dc-11a3b5975f27
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1200OK
ETag: W/"18333368"
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; odata.metadata=minimal; odata.streaming=true
OData-Version: 4.0

{"@odata.context":"https://<dynamics-crm-url>/api/data/v9.1/$metadata#accounts(com_jirasearchfield,address1_composite,address1_fax,com_business_line,com_supportdatenblatt,creditlimit,new_sicherheitsstufe,numberofemployees,com_auftraege,com_supportvertraege)/$entity","@odata.etag":"W/\"18333368\"","com_jirasearchfield":"Communardo Software GmbH","address1_composite":"Kleiststr.\r\n\r\n01129 Dresden\r\nDeutschland","address1_fax":null,"com_business_line":181410000,[...]}

--batchresponse_6f7cbc73-6da4-478e-85dc-11a3b5975f27
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1200OK
Content-Type: application/json; odata.metadata=minimal; odata.streaming=true
OData-Version: 4.0

{"@odata.context":"https://<dynamics-crm-url>/api/data/v9.1/$metadata#EntityDefinitions(LogicalName,Attributes(LogicalName,AttributeType,DisplayName))/$entity","LogicalName":"account",
"MetadataId":"70816501-edb9-4740-a16c-6a5efbc05d84","Attributes":[{"@odata.type":"#Microsoft.Dynamics.CRM.PicklistAttributeMetadata","LogicalName":"com_business_line","AttributeType":"Picklist",
"MetadataId":"7af6128f-25e1-ea11-a813-000d3ad8b29c","DisplayName":{"LocalizedLabels":[{"Label":"Business Line (Supportvertrag)","LanguageCode":1031,"IsManaged":false,"MetadataId":"7ff6128f-25e1-ea11-a813-000d3ad8b29c","HasChanged":null}],"UserLocalizedLabel":{"Label":"Business Line (Supportvertrag)","LanguageCode":1031,"IsManaged":false,"MetadataId":"7ff6128f-25e1-ea11-a813-000d3ad8b29c","HasChanged":null}}},[...]]}

--batchresponse_6f7cbc73-6da4-478e-85dc-11a3b5975f27
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1200OK
Content-Type: application/json; odata.metadata=minimal; odata.streaming=true
OData-Version: 4.0

{"@odata.context":"https://<dynamics-crm-url>/api/data/v9.1/$metadata#EntityDefinitions('account')/Attributes/Microsoft.Dynamics.CRM.PicklistAttributeMetadata(LogicalName,OptionSet(Options),GlobalOptionSet(Options))","value":[{"LogicalName":"com_business_line","MetadataId":"7af6128f-25e1-ea11-a813-000d3ad8b29c","OptionSet":{"MetadataId":"81f6128f-25e1-ea11-a813-000d3ad8b29c","Options":[{"Value":181410000,"Color":"#0000ff","IsManaged":false,"ExternalValue":"","ParentValues":[],"MetadataId":null,"HasChanged":null,"Label":{"LocalizedLabels":[{"Label":"Atlassian Solutions","LanguageCode":1031,"IsManaged":false,"MetadataId":"7bf6128f-25e1-ea11-a813-000d3ad8b29c","HasChanged":null}],[...]]}}]}

--batchresponse_6f7cbc73-6da4-478e-85dc-11a3b5975f27
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1200OK
ETag: W/"18333368"
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; odata.metadata=minimal; odata.streaming=true
OData-Version: 4.0

{"@odata.context":"https://<dynamics-crm-url>/api/data/v9.1/$metadata#accounts(com_vertriebsbeauftragter,new_CustomerServiceManager,parentaccountid,com_vertriebsbeauftragter(),new_CustomerServiceManager(),parentaccountid())/$entity",
"@odata.etag":"W/\"18333368\"","accountid":"8c48716a-05b9-e911-a827-000d3ab08ce9","com_vertriebsbeauftragter":{"@odata.etag":"W/\"17591002\"","ownerid":"ab719acb-297f-ea11-a813-000d3ab95ec9",
"address1_fax":"+49 (351) 833 82-299","organizationid":"d47b658d-6df6-43f6-9ef4-8bdac7d6b4a7","address1_postofficebox":null,"accessmode":0,"address1_upszone":null,"photourl":null,"address1_latitude":null,
"address1_shippingmethodcode":1,"address1_utcoffset":null,"_createdonbehalfby_value":null,"homephone":null,"skills":null,"emailrouteraccessapproval":1,"address2_latitude":null,"address1_longitude":null,"governmentid":null,"address2_longitude":null,"_createdby_value":null,"defaultfilterspopulated":false,"address1_telephone3":null,"mobilephone":null,"address2_fax":null,"preferredaddresscode":1,"address2_city":null,
"defaultodbfoldername":"Dynamics365","address2_stateorprovince":null,"address2_line2":null,"userpuid":"10033FFF907B6BDF","firstname":"Bob",[...]}}

--batchresponse_6f7cbc73-6da4-478e-85dc-11a3b5975f27--

Weitere Informationen und Beispiele zu Batch-Anfragen erhal­ten Sie hier: https://docs.microsoft.com/de-de/powerapps/developer/data-platform/webapi/execute-batch-operations-using-web-api

Berechtigungsprüfungen

Was die Datensicherheit betrifft stellt Dynamics selbst sicher, dass jeder nur die Datensätze sehen darf, für die er berech­tigt ist. Fragt ein Nutzer über die Web API einen Datensatz an, den er nicht sehen darf, wird eine Fehlermeldung als Antwort zurück­ge­sen­det, die dem Nutzer als ent­spre­chende Meldung im Benutzerdefinierten Feld ange­zeigt wird.

Fazit

Unsere client-seitige Lösung ermög­licht es, mit­tels der kom­ple­xen Web API von Dynamics, belie­bige Daten aus einem Dynamics CRM im Jira abzu­ru­fen und für Nutzer les­bar dar­zu­stel­len. Bei der Entwicklung der Lösung waren das Authentifizierunghandling und die kom­ple­xen Abfragen an die Web API, um alle gewünsch­ten Daten in Jira anzu­zei­gen, die größ­ten Herausforderungen. Weiterhin geht diese Komplexität mit einer teil­weise hohen Anzahl an REST-Anfragen ein­her, die aber durch das Bündeln in Batch-Operationen redu­ziert wer­den können.

Unsere Jira-Dynamics-Integration-App ist nun seit meh­re­ren Monaten erfolg­reich in unse­rem Communardo-Jira im Einsatz und unter­stützt unsere Mitarbeiter aus Vertrieb und Support bei ihrer täg­li­chen Arbeit. 

Da es sich, abge­se­hen vom Konfigurationsteil, um eine reine JavaScript-Lösung han­delt, ist eine künf­tige Integration in Jira Cloud mit weni­gen Anpassungen mög­lich

Sie nut­zen Microsoft Dynamics 365 und wol­len es in Ihr Jira Data Center integrieren?

Profitieren Sie von unse­ren Erfahrungen. Wir bera­ten Sie gern umfas­send zu Ihren Möglichkeiten.

Related Posts

Kommentar hinterlassen


Pin It on Pinterest