Microsoft Dynamics CRM 4.0 | RetrieveMultiple Beispiel – Dauer von Aktivitäten in Anfragen

 

Ein wunderbares Beispiel zum Einsatz der RetrieveMultiple – Methode ist der Einsatz zur Konsolidierung der Dauer-Angaben in einzelnen Aktivitäten einer Anfrage. Sagen wir, dass die Aufgabe darin besteht, alle zu einer Anfrage zugehörigen Aktivitäten ausfindig zu machen und die an den einzelnen Aktivitäten getätigten Dauer-Angaben in einem Feld “Aufgebrachte Gesamtdauer” zu summieren.

Natürlich kann man diese Aufgabe auch mit anderen Methodiken, wie z.B. Plugins oder Workflows lösen. Doch, da in den Foren immer wieder nach Beispielen für die RetrieveMultiple-Methode verlangt wird, möchte ich diese nachfolgend vorstellen.

Was benötigt Ihr?

Zunächst einmal müssen wir uns entscheiden, welche Aktivitätstypen wir zu einer Anfrage konsolidieren wollen (alle?) – Nun ja, Kampagnenreaktion an einer Anfrage wird es wohl nicht geben. Ebenso ist es unrealistisch, dass eine E-Mail Aktivität mit einer sinnvollen Dauer-Angabe gepflegt sein dürfte – oder pflegt Ihr etwa die Zeit, die Ihr zur Erstellung und Versendung der E-Mail benötigt habt? (Wenn doch, ist es natürlich ein Leichtes, auch diese Aktivitätsform abzufragen).

Nachdem wir die Entscheidung getroffen haben, müssen wir wissen, dass es an der Entität Anfrage sowohl offene, als auch abgeschlossene Aktivitäten geben kann. Offene Aktivitäten, aber auch geschlossenen Aktivitäten können jederzeit gelöscht werden, sofern Rechte vorhanden. Natürlich hat dies zur Folge, dass sich unser Summierungsfeld aktualisieren müsste. Also müssen wir entsprechend im OnLoad() und im OnSave()-Event handeln.

Offene- bzw. geschlossene Aktivitäten haben unterschiedliche StatusCodes. Wir benötigen also zunächst von jeder einzelnen Aktivität die verschiedenen StatusCodes, damit wir die unterschiedlichen Stati korrekt abfragen können. Auch hier hilft uns das SDK (am Beispiel der Entität Aufgabe). Wer nicht über das SDK gehen will, kann sich die einzelnen StatusCodes auch direkt via SQL-Statement aus der Datenbank auslesen. Wer es via Programmcode erledigen möchte, findet im SDK ein Beispiel http://msdn.microsoft.com/en-us/library/cc151213.aspx, um sich die Status Codes ausgeben zu lassen.

Ein Sammelattribut auf der Entität Anfrage, welches wir aktualisieren.

Eine Programmroutine “RetrieveMultiple”, die uns die Abfrage unserer Aktivitätstypen zugehörig zur Anfrage X ermöglicht.

 

Warum nehmen wir nicht die Aktivitäten-Entität (activitypointer) zur Auswertung?

Nun ja, sicherlich könnte man auch diese Entität zur Auswertung heranziehen, jedoch wollen wir unter umständen noch ein Benutzerdefiniertes Attribut in unserer Auswertung integrieren und unser Benutzerdefiniertes Attribut befindet sich direkt auf den einzelnen Entitäten, nicht jedoch an der Sammel-Entität “Aktivitäten”, da diese supported nicht um weitere Attribute erweitert werden kann.

 

Nun zur Routine

Entwickelt habe ich mir eine Funktion

RetrieveMultiple(searchregobjid,Entity,FType,statusCode,ActTypeTxt,Filterattr,durationfield,descriptionfield,ordField,ordType,distinct)

searchregobjid = die GUID der aktuellen Anfrage, nach der ich im Bezugsfeld der Aktivitäten suche

Entity = Entitätstyp in denen ich suchen möchte (z.B. “task”, “phonecall”, “appointment”, “serviceappointment”

FType = Wert, den Filterattr haben soll (z.B. 1 = ja, 0 = nein)

statusCode = StatusCode der jeweiligen Aktivitätsentität (bedenkt die unterschiedlichen Stati für offene, geschlossene Aktivitäten)

ActTypeTxt = Textbezeichner, den ich nur für eine Alert-Meldung verwende (z.B. “Termine”)

Filterattr = Ein benutzerdefiniertes Attribut auf den einzelnen Aktivitätsentitäten (z.B. ob die Dauer abrechenbar ist)

durationfield = Unsere Dauer-Angabe, welche wir auslesen wollen

descriptionfield = das jeweilige Beschreibungsfeld der Aktivitätsentität, da ich mir auch dieses kumuliert ausgeben lassen möchte

ordField = Feld für Sortierreihenfolge (z.B. “createdon”)

ordType = Sortierreihenfolge (“ascending” oder “descending”)

distinct = Sollen doppelte Datensätze eingeschlossen werden oder nicht (“true” oder “false”)

 

Nachfolgend die Funktion im Ausführlichen:

function RetrieveMultiple(searchregobjid,Entity,FType,statusCode,ActTypeTxt,Filterattr,durationfield,descriptionfield,ordField,ordType,distinct){
var authenticationHeader=GenerateAuthenticationHeader()
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'>"+
authenticationHeader+
"<soap:Body>"+
"<RetrieveMultiple xmlns='http://schemas.microsoft.com/crm/2007/WebServices'>"+
"<query xmlns:q1='http://schemas.microsoft.com/crm/2006/Query'"+
" xsi:type='q1:QueryExpression'>"+
"<q1:EntityName>"+Entity+"</q1:EntityName>"+
"<q1:ColumnSet xsi:type='q1:ColumnSet'>"+
"<q1:Attributes>"+
"<q1:Attribute>"+durationfield+"</q1:Attribute>"+
"</q1:Attributes>"+
"<q1:Attributes>"+
"<q1:Attribute>subject</q1:Attribute>"+
"</q1:Attributes>"+
"<q1:Attributes>"+
"<q1:Attribute>"+descriptionfield+"</q1:Attribute>"+
"</q1:Attributes>"+
"<q1:Attributes>"+
"<q1:Attribute>actualend</q1:Attribute>"+
"</q1:Attributes>"+
"</q1:ColumnSet>"+
"<q1:Distinct>"+distinct+"</q1:Distinct>"+
"<q1:Criteria>"+
"<q1:FilterOperator>And</q1:FilterOperator>"+
"<q1:Conditions>"+
"<q1:Condition>"+
"<q1:AttributeName>"+Filterattr+"</q1:AttributeName>"+
"<q1:Operator>Equal</q1:Operator>"+
"<q1:Values>"+
"<q1:Value xsi:type='xsd:string'>"+FType+"</q1:Value>"+
"</q1:Values>"+
"</q1:Condition>"+
"<q1:Condition>"+
"<q1:AttributeName>regardingobjectid</q1:AttributeName>"+
"<q1:Operator>Equal</q1:Operator>"+
"<q1:Values>"+
"<q1:Value xsi:type='xsd:string'>"+searchregobjid+"</q1:Value>"+
"</q1:Values>"+
"</q1:Condition>"+
"<q1:Condition>"+
"<q1:AttributeName>statuscode</q1:AttributeName>"+
"<q1:Operator>Equal</q1:Operator>"+
"<q1:Values>"+
"<q1:Value xsi:type='xsd:string'>"+statusCode+"</q1:Value>"+
"</q1:Values>"+
"</q1:Condition>"+
"</q1:Conditions>"+
"</q1:Criteria>"+
"<q1:Orders>"+
"<q1:Order>"+
"<q1:AttributeName>"+ordField+"</q1:AttributeName>"+
"<q1:OrderType>"+ordType+"</q1:OrderType>"+
"</q1:Order>"+
"</q1:Orders>"+
"</query>"+
"</RetrieveMultiple>"+
"</soap:Body>"+
"</soap:Envelope>"
var xHReq=new ActiveXObject("Msxml2.XMLHTTP")
xHReq.Open("POST","/mscrmservices/2007/CrmService.asmx",false)
xHReq.setRequestHeader("SOAPAction","http://schemas.microsoft.com/crm/2007/WebServices/RetrieveMultiple")
xHReq.setRequestHeader("Content-Type","text/xml; charset=utf-8")
xHReq.setRequestHeader("Content-Length",xml.length)
xHReq.send(xml)
var resultXml=xHReq.responseXML
var hours
var errorCount=resultXml.selectNodes('//error').length
if(errorCount !=0){
var msg=resultXml.selectSingleNode('//description').nodeTypedValue
alert(msg)}
else{
var results=resultXml.getElementsByTagName('BusinessEntity')
var nodeslst=resultXml.selectNodes('//BusinessEntity')
var msg=''
var msg2=''
var overallduration=0
if(results.length==0){
msg2="Es wurden keine abgeschlossenen Aktivitäten vom Typ "+ActTypeTxt+" gefunden."
hours=0
return{hours : hours,msg : msg}}
else{
msg=''
for(i=0;i<results.length;i++){
if(nodeslst[i].childNodes[0].nodeName=="q1:"+durationfield+""){
var durationNode=results[i].selectSingleNode('./q1:'+durationfield+'').nodeTypedValue}
else{
var durationNode='0'}
var durationint=parseInt(durationNode)
overallduration=overallduration+durationint
}
var hours=overallduration/60
if(hours<=0){
hours=0}
return{hours : hours,msg : msg}}}}

 

Jetzt fehlt eigentlich nur noch der Aufruf der jeweiligen Routine, die z.B. so

var searchregobjid=(crmForm.ObjectId)

var stdvtask=RetrieveMultiple(searchregobjid,"task","1","5","Aufgaben","mscrm_bbtype","actualdurationminutes","description", "createdon", "ascending", false)

var stdotask=RetrieveMultiple(searchregobjid,"task","1","2","Aufgaben","mscrm_bbtype","actualdurationminutes","description", "createdon", "ascending", false)

aussehen kann.

Und das aufsummieren funktioniert dann mit dem Aufruf

var sum = stdvtask.hours + stdotask.hours //bzw.

var descsum = stdvtask.msg + stdotask.msg

// Übergabe an das crmForm-Feld

crmForm.all.mscrm_customField.DataValue = sum;

Aber das kennt Ihr ja schon. So, damit habe ich Euch hoffentlich eine interessante Möglichkeit aufgezeigt, die RetrieveMultiple – Methodik in Euren Installationen zu nutzen und Eure Anforderungen mit diesem Code-Beispiel zu realisieren. Ich wünsche viel Spaß und freue mich auf Eure Kommentare.

Weitere Beispiele findet Ihr auch unter http://crmentropy.blogspot.com/2009/11/easy-to-use-javascript-retrieve-and.html oder

http://knrs.blogspot.com/2009/12/ms-crm-40-call-retrievemultiple.html

 

Schreibe einen Kommentar

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s