CRM 2016 - The provided uri did not return any Service Endpoints!

Bazen crme visual studio gibi ortamlardan bağlanmaya çalıştığımızda "The provided uri did not return any Service Endpoints!" hatasını vermektedir.

Çözüm

Hizmeleri açalım.


Microsoft Dynamics Asenkron Servisleri  restart edilmelidir.




CRM - Aktivite Tipinde Varlık Tanımlama

Create a Custom Activity

Varlıklar oluşturulurken standart yada custom aktivite olarak açılabilirler.

 Custom aktivite tanımlarken aşağıdaki ekran görüntüsündeki seçim alanlarını seçmelisiniz.


Varığımızı oluşturduktan sonra etkinlikler kısmında görebileceğiz.

Custom aktiviteler oluşturulurken bilinmesi gerekilenler

  • Custom varlıklar ilk yaratıldığında sadece System Administrator ve System Customizer rolundeki kullanıcılar görebilir. Bunun haricindeki  kullanıcıların rollerıne yetkı verilmelidir.
  • Entity aktivite tipinde yaratıldıktan sonra geri alınamaz.
  • Custom etkinlik varlığı, diğer etkinlik varlıklarına erişimi olan kullanıcılar tarafından kullanılabilir

CRM 2016 - Custom Actions

Kod yazılımı plugın gibi olup sadece sdk nın desteklediği mesajlar üzerinden çağrılmazlar. Yeni mesajlar tanımlanıp bu mesajlar uzerınden cagrılabılırler.Bunun haricinde giriş ve çıkış parametreleri tanımlanabilir . Bu şekilde dışarıdan veri gönderilebilir veya dışarıya veri gönderieblir.

Ayarlar altından Process i seçelim.

Gelen ekrandan yeni bir process oluşturmak için Yeni butonuna tıklayalım.

Açıan pencerede processin adını , category olarak Actionı ve Entity olarak da None(Global) değerini seçelim ve Tamam butonuna basalım.

Açılan pencere üzerinde giriş çıkış parametreleri tanmlayabiliriz.

Parametre olarak aşağıdaki tiplerde parametre tanımlanabilir.

Daha sonra yaptığıız işlemleri kaydedelim ve actionımızı kullanmak için Activated butonuna basalım.


Gelen ekranda Activate butonuna basarak processimizi aktif duruma getirelim.

Daha sonra actionımızın kodlarını yazalım.


 private void ExecuteCreateInterestOrderAction(LocalPluginContext localContext)
        {
            try
            {
                #region Plugin Tanımlamaları
                IPluginExecutionContext context = localContext.PluginExecutionContext;
                IOrganizationService crmService = localContext.OrganizationService;

                if (!context.InputParameters.Contains("OrderId"))
                    return;
                #endregion

                #region Main Code
                Guid newOrderId = Guid.Empty;
                EntityReference orderRef = (EntityReference)context.InputParameters["OrderId"];

                if (orderRef.LogicalName != "salesorder") { return; }
                string[] orderColumns = { "salesorderid", "new_faturano", "new_interestorderamount", "customerid", "new_accountnameid" };

                Entity order = crmService.Retrieve("salesorder", orderRef.Id, new ColumnSet(orderColumns));
                if (order != null && order.Id != Guid.Empty)
                {
                    EntityReference customer = order.GetAttributeValue<EntityReference>("customerid");
                    EntityReference accountName = order.GetAttributeValue<EntityReference>("new_accountnameid");

                    string orderNumber = order.GetAttributeValue<string>("new_faturano");
                    decimal? interestOrderAmount = order.GetAttributeValue<decimal?>("new_interestorderamount");

                    #region Create Interest Order

                    #region Order Fields
                    Entity newOrder = new Entity("salesorder");
                    newOrder["customerid"] = customer;
                    newOrder["new_accountnameid"] = accountName;
                    newOrder["ownerid"] = new EntityReference("systemuser", new Guid(appSetting.GetZaferErtasSystemUserId));
                    newOrder["name"] = "Vade Farkı Faturası";
                    newOrder["new_faturano"] = orderNumber;
                    newOrder["new_productid"] = new EntityReference("product", new Guid(appSetting.GetOtherProductId));
                    newOrder["new_territoryid"] = new EntityReference("territory", new Guid(appSetting.GetTurkeyTerritoryId));
                    newOrder["pricelevelid"] = new EntityReference("pricelevel", new Guid(appSetting.GetTLPesinPrieLevelId));
                    newOrder["new_mainorderid"] = orderRef;
                    #endregion

                    #region Add Order Product
                    EntityCollection cl = new EntityCollection();
                    cl.EntityName = "salesorderdetail";

                    Entity orderProduct = new Entity("salesorderdetail");
                    orderProduct["productid"] = new EntityReference("product", new Guid(appSetting.GetOtherProductId));
                    orderProduct["uomid"] = new EntityReference("uom", new Guid(appSetting.GetPieceUomId));
                    // orderProduct["defaultuomscheduleid"] = new EntityReference("uomschedule", new Guid(appSetting.GetDefaultUomScheduleId));

                    if (interestOrderAmount != null)
                        orderProduct["priceperunit"] = new Money(interestOrderAmount.Value);
                    else
                        orderProduct["priceperunit"] = new Money(0);

                    orderProduct["quantity"] = Convert.ToDecimal(1);
                    orderProduct["ispriceoverridden"] = true;
                    orderProduct["new_ordertip"] = new OptionSetValue((int)OrderTypes.Other);
                    orderProduct["transactioncurrencyid"] = new EntityReference("transactioncurrency", new Guid(appSetting.GetTLCurencyId));

                    cl.Entities.Add(orderProduct);

                    if (cl.Entities.Count > 0)
                        newOrder.RelatedEntities.Add(new Relationship("order_details"), cl);
                    #endregion

                    newOrderId = crmService.Create(newOrder);
                    //crmService.AssignTeamorUser(new EntityReference("systemuser", new Guid()), new EntityReference("salesorder", newOrderId));
                    #endregion
                }

                if (newOrderId != Guid.Empty)
                    context.OutputParameters["InterestOrderId"] = new EntityReference("salesorder", newOrderId);
                #endregion
            }
            catch (Exception ex){
                throw new InvalidPluginExecutionException("An error occured in new_CreateInterestOrder Action" + Environment.NewLine + ex.Message);
            }
        }

Projemizi plugin registration tool üzerinden register edelim ve actionımıza yeni bir step girelim.

Bu kısımda sdk nın mesajları haricinde kendi oluşturduğumuz processimizi seçelim.


Sıra geldi actionımızı nasıl çağıracağımıza .Bunun için 2 yol vardır .

C# kodu üzerinden çağırma

  OrganizationRequest req = new OrganizationRequest("new_CreateInterestOrder");
  req.Parameters.Add("OrderId", new EntityReference("salesorder", new Guid("B5A899C7-0792-E611-80F8-5065F38BE401")));
   OrganizationResponse response = crmService.Execute(req);

    if (response.Results.Contains("InterestOrderId")){
        EntityReference er = (EntityReference)response.Results["InterestOrderId"];
     }

Javascript kod üzerinden çağırma

Bunun için aşağıdaki Process.js kütüphanesini kullanacağız. Kullanımı oldukça basit olup her tarayıcıda sornsuz çalışmaktadır.


Process.js Kullanımı

function CallCreateInterestOrderAction() {
    try {
        // Call an Action
        Process.callAction("new_CreateInterestOrder",
        [{
            key: "OrderId",
            type: Process.Type.EntityReference,
            value: new Process.EntityReference("salesorder", Xrm.Page.data.entity.getId())
        }],

        function (outputParams) {
            // Success
            var formLangId = Xrm.Page.context.getUserLcid();
            if (formLangId != 1055)
                alert("Interest order created.");
            else
                alert("Vade farkı faturası oluşturuldu.");


            if (outputParams != null) {
                if (outputParams["InterestOrderId"] != null && outputParams["InterestOrderId"].id != null) {
                    var options = {
                        openInNewWindow: true
                    };
                    Xrm.Utility.openEntityForm(outputParams["InterestOrderId"].entityType, outputParams["InterestOrderId"].id, null, options);
                }
            }

            Xrm.Utility.openEntityForm("salesorder", Xrm.Page.data.entity.getId());
        },

        function (e, t) {
            // Error
            alert(e);

            // Write the trace log to the dev console
            if (window.console && console.error) {
                console.error(e + "\n" + t);
            }
        });
    }
    catch (e) {
        alert("An error occured in CallCreateInterestOrderAction Function.\nError" + e.message);
    }
}

Process.js

var Process = Process || {};

// Supported Action input parameter types
Process.Type = {
    Bool: "c:boolean",
    Float: "c:double", // Not a typo
    Decimal: "c:decimal",
    Int: "c:int",
    String: "c:string",
    DateTime: "c:dateTime",
    Guid: "c:guid",
    EntityReference: "a:EntityReference",
    OptionSet: "a:OptionSetValue",
    Money: "a:Money",
    Entity: "a:Entity",
    EntityCollection: "a:EntityCollection"
}

// inputParams: Array of parameters to pass to the Action. Each param object should contain key, value, and type.
// successCallback: Function accepting 1 argument, which is an array of output params. Access values like: params["key"]
// errorCallback: Function accepting 1 argument, which is the string error message. Can be null.
// Unless the Action is global, you must specify a 'Target' input parameter as EntityReference
// actionName is required
Process.callAction = function (actionName, inputParams, successCallback, errorCallback, url) {
    var ns = {
        "": "http://schemas.microsoft.com/xrm/2011/Contracts/Services",
        ":s": "http://schemas.xmlsoap.org/soap/envelope/",
        ":a": "http://schemas.microsoft.com/xrm/2011/Contracts",
        ":i": "http://www.w3.org/2001/XMLSchema-instance",
        ":b": "http://schemas.datacontract.org/2004/07/System.Collections.Generic",
        ":c": "http://www.w3.org/2001/XMLSchema",
        ":d": "http://schemas.microsoft.com/xrm/2011/Contracts/Services",
        ":e": "http://schemas.microsoft.com/2003/10/Serialization/",
        ":f": "http://schemas.microsoft.com/2003/10/Serialization/Arrays",
        ":g": "http://schemas.microsoft.com/crm/2011/Contracts",
        ":h": "http://schemas.microsoft.com/xrm/2011/Metadata",
        ":j": "http://schemas.microsoft.com/xrm/2011/Metadata/Query",
        ":k": "http://schemas.microsoft.com/xrm/2013/Metadata",
        ":l": "http://schemas.microsoft.com/xrm/2012/Contracts",
        //":c": "http://schemas.microsoft.com/2003/10/Serialization/" // Conflicting namespace for guid... hardcoding in the _getXmlValue bit
    };

    var requestXml = "<s:Envelope";

    // Add all the namespaces
    for (var i in ns) {
        requestXml += " xmlns" + i + "='" + ns[i] + "'";
    }

    requestXml += ">" +
          "<s:Body>" +
            "<Execute>" +
              "<request>";

    if (inputParams != null && inputParams.length > 0) {
        requestXml += "<a:Parameters>";

        // Add each input param
        for (var i = 0; i < inputParams.length; i++) {
            var param = inputParams[i];

            var value = Process._getXmlValue(param.key, param.type, param.value);

            requestXml += value;
        }

        requestXml += "</a:Parameters>";
    }
    else {
        requestXml += "<a:Parameters />";
    }

    requestXml += "<a:RequestId i:nil='true' />" +
                "<a:RequestName>" + actionName + "</a:RequestName>" +
              "</request>" +
            "</Execute>" +
          "</s:Body>" +
        "</s:Envelope>";

    Process._callActionBase(requestXml, successCallback, errorCallback, url);
}

// Runs the specified workflow for a particular record
// successCallback and errorCallback accept no arguments
// workflowId, and recordId are required
Process.callWorkflow = function (workflowId, recordId, successCallback, errorCallback, url) {
    if (url == null) {
        url = Xrm.Page.context.getClientUrl();
    }

    var request = "<s:Envelope xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'>" +
          "<s:Body>" +
            "<Execute xmlns='http://schemas.microsoft.com/xrm/2011/Contracts/Services' xmlns:i='http://www.w3.org/2001/XMLSchema-instance'>" +
              "<request i:type='b:ExecuteWorkflowRequest' xmlns:a='http://schemas.microsoft.com/xrm/2011/Contracts' xmlns:b='http://schemas.microsoft.com/crm/2011/Contracts'>" +
                "<a:Parameters xmlns:c='http://schemas.datacontract.org/2004/07/System.Collections.Generic'>" +
                  "<a:KeyValuePairOfstringanyType>" +
                    "<c:key>EntityId</c:key>" +
                    "<c:value i:type='d:guid' xmlns:d='http://schemas.microsoft.com/2003/10/Serialization/'>" + recordId + "</c:value>" +
                  "</a:KeyValuePairOfstringanyType>" +
                  "<a:KeyValuePairOfstringanyType>" +
                    "<c:key>WorkflowId</c:key>" +
                    "<c:value i:type='d:guid' xmlns:d='http://schemas.microsoft.com/2003/10/Serialization/'>" + workflowId + "</c:value>" +
                  "</a:KeyValuePairOfstringanyType>" +
                "</a:Parameters>" +
                "<a:RequestId i:nil='true' />" +
                "<a:RequestName>ExecuteWorkflow</a:RequestName>" +
              "</request>" +
            "</Execute>" +
          "</s:Body>" +
        "</s:Envelope>";

    var req = new XMLHttpRequest();
    req.open("POST", url + "/XRMServices/2011/Organization.svc/web", true);

    req.setRequestHeader("Accept", "application/xml, text/xml, */*");
    req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
    req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
    req.onreadystatechange = function () {
        if (req.readyState == 4) {
            if (req.status == 200) {
                if (successCallback) {
                    successCallback();
                }
            }
            else {
                if (errorCallback) {
                    errorCallback();
                }
            }
        }
    };

    req.send(request);
}

// Pops open the specified dialog process for a particular record
// dialogId, entityName, and recordId are required
// callback fires even if the dialog is closed/cancelled
Process.callDialog = function (dialogId, entityName, recordId, callback, url) {
    tryShowDialog("/cs/dialog/rundialog.aspx?DialogId=%7b" + dialogId + "%7d&EntityName=" + entityName + "&ObjectId=" + recordId, 600, 400, callback, url);

    // Function copied from Alert.js v1.0 https://alertjs.codeplex.com
    function tryShowDialog(url, width, height, callback, baseUrl) {
        width = width || Alert._dialogWidth;
        height = height || Alert._dialogHeight;

        var isOpened = false;

        try {
            // Web (IE, Chrome, FireFox)
            var Mscrm = Mscrm && Mscrm.CrmDialog && Mscrm.CrmUri && Mscrm.CrmUri.create ? Mscrm : parent.Mscrm;
            if (Mscrm && Mscrm.CrmDialog && Mscrm.CrmUri && Mscrm.CrmUri.create) {
                // Use CRM light-box (unsupported)
                var crmUrl = Mscrm.CrmUri.create(url);
                var dialogwindow = new Mscrm.CrmDialog(crmUrl, window, width, height);

                // Allows for opening non-webresources (e.g. dialog processes) - CRM messes up when it's not a web resource (unsupported)
                if (!crmUrl.get_isWebResource()) {
                    crmUrl.get_isWebResource = function () { return true; }
                }

                // Open the lightbox
                dialogwindow.show();
                isOpened = true;

                // Make sure when the dialog is closed, the callback is fired
                // This part's all pretty unsupported, hence the try-catches
                // If you can avoid using a callback, best not to use one
                if (callback) {
                    try {
                        // Get the lightbox iframe (unsupported)
                        var $frame = parent.$("#InlineDialog_Iframe");
                        if ($frame.length == 0) { $frame = parent.parent.$("#InlineDialog_Iframe"); }
                        $frame.load(function () {
                            try {
                                // Override the CRM closeWindow function (unsupported)
                                var frameDoc = $frame[0].contentWindow;
                                var closeEvt = frameDoc.closeWindow; // OOTB close function
                                frameDoc.closeWindow = function () {
                                    // Bypasses onunload event on dialogs to prevent "are you sure..." (unsupported - doesn't work with 2015 SP1)
                                    try { frameDoc.Mscrm.GlobalVars.$B = false; } catch (e) { }

                                    // Fire the callback and close
                                    callback();
                                    try { closeEvt(); } catch (e) { }
                                }
                            } catch (e) { }
                        });
                    } catch (e) { }
                }
            }
        } catch (e) { }

        try {
            // Outlook
            if (!isOpened && window.showModalDialog) {
                // If lightbox fails, use window.showModalDialog
                baseUrl = baseUrl || Xrm.Page.context.getClientUrl();
                var params = "dialogWidth:" + width + "px; dialogHeight:" + height + "px; status:no; scroll:no; help:no; resizable:yes";

                window.showModalDialog(baseUrl + url, window, params);
                if (callback) {
                    callback();
                }

                isOpened = true;
            }
        } catch (e) { }

        return isOpened;
    }
}

Process._emptyGuid = "00000000-0000-0000-0000-000000000000";

// This can be used to execute custom requests if needed - useful for me testing the SOAP :)
Process._callActionBase = function (requestXml, successCallback, errorCallback, url) {
    if (url == null) {
        url = Xrm.Page.context.getClientUrl();
    }

    var req = new XMLHttpRequest();
    req.open("POST", url + "/XRMServices/2011/Organization.svc/web", true);
    req.setRequestHeader("Accept", "application/xml, text/xml, */*");
    req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
    req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");

    req.onreadystatechange = function () {
        if (req.readyState == 4) {
            if (req.status == 200) {
                // If there's no successCallback we don't need to check the outputParams
                if (successCallback) {
                    // Yucky but don't want to risk there being multiple 'Results' nodes or something
                    var resultsNode = req.responseXML.childNodes[0].childNodes[0].childNodes[0].childNodes[0].childNodes[1]; // <a:Results>

                    // Action completed successfully - get output params
                    var responseParams = Process._getChildNodes(resultsNode, "a:KeyValuePairOfstringanyType");

                    var outputParams = {};
                    for (i = 0; i < responseParams.length; i++) {
                        var attrNameNode = Process._getChildNode(responseParams[i], "b:key");
                        var attrValueNode = Process._getChildNode(responseParams[i], "b:value");

                        var attributeName = Process._getNodeTextValue(attrNameNode);
                        var attributeValue = Process._getValue(attrValueNode);

                        // v1.0 - Deprecated method using key/value pair and standard array
                        //outputParams.push({ key: attributeName, value: attributeValue.value });

                        // v2.0 - Allows accessing output params directly: outputParams["Target"].attributes["new_fieldname"];
                        outputParams[attributeName] = attributeValue.value;

                        /*
                        RETURN TYPES:
                            DateTime = Users local time (JavaScript date)
                            bool = true or false (JavaScript boolean)
                            OptionSet, int, decimal, float, etc = 1 (JavaScript number)
                            guid = string
                            EntityReference = { id: "guid", name: "name", entityType: "account" }
                            Entity = { logicalName: "account", id: "guid", attributes: {}, formattedValues: {} }
                            EntityCollection = [{ logicalName: "account", id: "guid", attributes: {}, formattedValues: {} }]
 
                        Attributes for entity accessed like: entity.attributes["new_fieldname"].value
                        For entityreference: entity.attributes["new_fieldname"].value.id
                        Make sure attributes["new_fieldname"] is not null before using .value
                        Or use the extension method entity.get("new_fieldname") to get the .value
                        Also use entity.formattedValues["new_fieldname"] to get the string value of optionsetvalues, bools, moneys, etc
                        */
                    }

                    // Make sure the callback accepts exactly 1 argument - use dynamic function if you want more
                    successCallback(outputParams);
                }
            }
            else {
                // Error has occured, action failed
                if (errorCallback) {
                    var message = null;
                    var traceText = null;
                    try {
                        message = Process._getNodeTextValueNotNull(req.responseXML.getElementsByTagName("Message"));
                        traceText = Process._getNodeTextValueNotNull(req.responseXML.getElementsByTagName("TraceText"));
                    } catch (e) { }
                    if (message == null) { message = "Error executing Action. Check input parameters or contact your CRM Administrator"; }
                    errorCallback(message, traceText);
                }
            }
        }
    };

    req.send(requestXml);
}

// Get only the immediate child nodes for a specific tag, otherwise entitycollections etc mess it up
Process._getChildNodes = function (node, childNodesName) {
    var childNodes = [];

    for (var i = 0; i < node.childNodes.length; i++) {
        if (node.childNodes[i].tagName == childNodesName) {
            childNodes.push(node.childNodes[i]);
        }
    }

    // Chrome uses just 'Results' instead of 'a:Results' etc
    if (childNodes.length == 0 && childNodesName.indexOf(":") !== -1) {
        childNodes = Process._getChildNodes(node, childNodesName.substring(childNodesName.indexOf(":") + 1));
    }

    return childNodes;
}

// Get a single child node for a specific tag
Process._getChildNode = function (node, childNodeName) {
    var nodes = Process._getChildNodes(node, childNodeName);

    if (nodes != null && nodes.length > 0) { return nodes[0]; }
    else { return null; }
}

// Gets the first not null value from a collection of nodes
Process._getNodeTextValueNotNull = function (nodes) {
    var value = "";

    for (var i = 0; i < nodes.length; i++) {
        if (value === "") {
            value = Process._getNodeTextValue(nodes[i]);
        }
    }

    return value;
}

// Gets the string value of the XML node
Process._getNodeTextValue = function (node) {
    if (node != null) {
        var textNode = node.firstChild;
        if (textNode != null) {
            return textNode.textContent || textNode.nodeValue || textNode.data || textNode.text;
        }
    }

    return "";
}

// Gets the value of a parameter based on its type, can be recursive for entities
Process._getValue = function (node) {
    var value = null;
    var type = null;

    if (node != null) {
        type = node.getAttribute("i:type") || node.getAttribute("type");

        // If the parameter/attribute is null, there won't be a type either
        if (type != null) {
            // Get the part after the ':' (since Chrome doesn't have the ':')
            var valueType = type.substring(type.indexOf(":") + 1).toLowerCase();

            if (valueType == "entityreference") {
                // Gets the lookup object
                var attrValueIdNode = Process._getChildNode(node, "a:Id");
                var attrValueEntityNode = Process._getChildNode(node, "a:LogicalName");
                var attrValueNameNode = Process._getChildNode(node, "a:Name");

                var lookupId = Process._getNodeTextValue(attrValueIdNode);
                var lookupName = Process._getNodeTextValue(attrValueNameNode);
                var lookupEntity = Process._getNodeTextValue(attrValueEntityNode);

                value = new Process.EntityReference(lookupEntity, lookupId, lookupName);
            }
            else if (valueType == "entity") {
                // Gets the entity data, and all attributes
                value = Process._getEntityData(node);
            }
            else if (valueType == "entitycollection") {
                // Loop through each entity, returns each entity, and all attributes
                var entitiesNode = Process._getChildNode(node, "a:Entities");
                var entityNodes = Process._getChildNodes(entitiesNode, "a:Entity");

                value = [];
                if (entityNodes != null && entityNodes.length > 0) {
                    for (var i = 0; i < entityNodes.length; i++) {
                        value.push(Process._getEntityData(entityNodes[i]));
                    }
                }
            }
            else if (valueType == "aliasedvalue") {
                // Gets the actual data type of the aliased value
                // Key for these is "alias.fieldname"
                var aliasedValue = Process._getValue(Process._getChildNode(node, "a:Value"));
                if (aliasedValue != null) {
                    value = aliasedValue.value;
                    type = aliasedValue.type;
                }
            }
            else {
                // Standard fields like string, int, date, money, optionset, float, bool, decimal
                // Output will be string, even for number fields etc
                var stringValue = Process._getNodeTextValue(node);

                if (stringValue != null) {
                    switch (valueType) {
                        case "datetime":
                            value = new Date(stringValue);
                            break;
                        case "int":
                        case "money":
                        case "optionsetvalue":
                        case "double": // float
                        case "decimal":
                            value = Number(stringValue);
                            break;
                        case "boolean":
                            value = stringValue.toLowerCase() === "true";
                            break;
                        default:
                            value = stringValue;
                    }
                }
            }
        }
    }

    return new Process.Attribute(value, type);
}

Process._getEntityData = function (entityNode) {
    var value = null;

    var entityAttrsNode = Process._getChildNode(entityNode, "a:Attributes");
    var entityIdNode = Process._getChildNode(entityNode, "a:Id");
    var entityLogicalNameNode = Process._getChildNode(entityNode, "a:LogicalName");
    var entityFormattedValuesNode = Process._getChildNode(entityNode, "a:FormattedValues");

    var entityLogicalName = Process._getNodeTextValue(entityLogicalNameNode);
    var entityId = Process._getNodeTextValue(entityIdNode);
    var entityAttrs = Process._getChildNodes(entityAttrsNode, "a:KeyValuePairOfstringanyType");

    value = new Process.Entity(entityLogicalName, entityId);

    // Attribute values accessed via entity.attributes["new_fieldname"]
    if (entityAttrs != null && entityAttrs.length > 0) {
        for (var i = 0; i < entityAttrs.length; i++) {

            var attrNameNode = Process._getChildNode(entityAttrs[i], "b:key")
            var attrValueNode = Process._getChildNode(entityAttrs[i], "b:value");

            var attributeName = Process._getNodeTextValue(attrNameNode);
            var attributeValue = Process._getValue(attrValueNode);

            value.attributes[attributeName] = attributeValue;
        }
    }

    // Formatted values accessed via entity.formattedValues["new_fieldname"]
    for (var j = 0; j < entityFormattedValuesNode.childNodes.length; j++) {
        var foNode = entityFormattedValuesNode.childNodes[j];

        var fNameNode = Process._getChildNode(foNode, "b:key")
        var fValueNode = Process._getChildNode(foNode, "b:value");

        var fName = Process._getNodeTextValue(fNameNode);
        var fValue = Process._getNodeTextValue(fValueNode);

        value.formattedValues[fName] = fValue;
    }

    return value;
}

Process._getXmlValue = function (key, dataType, value) {
    var xml = "";
    var xmlValue = "";

    var extraNamespace = "";

    // Check the param type to determine how the value is formed
    switch (dataType) {
        case Process.Type.String:
            xmlValue = Process._htmlEncode(value) || ""; // Allows fetchXml strings etc
            break;
        case Process.Type.DateTime:
            xmlValue = value.toISOString() || "";
            break;
        case Process.Type.EntityReference:
            xmlValue = "<a:Id>" + (value.id || "") + "</a:Id>" +
                  "<a:LogicalName>" + (value.entityType || "") + "</a:LogicalName>" +
                  "<a:Name i:nil='true' />";
            break;
        case Process.Type.OptionSet:
        case Process.Type.Money:
            xmlValue = "<a:Value>" + (value || 0) + "</a:Value>";
            break;
        case Process.Type.Entity:
            xmlValue = Process._getXmlEntityData(value);
            break;
        case Process.Type.EntityCollection:
            if (value != null && value.length > 0) {
                var entityCollection = "";
                for (var i = 0; i < value.length; i++) {
                    var entityData = Process._getXmlEntityData(value[i]);
                    if (entityData !== null) {
                        entityCollection += "<a:Entity>" + entityData + "</a:Entity>";
                    }
                }
                if (entityCollection !== null && entityCollection !== "") {
                    xmlValue = "<a:Entities>" + entityCollection + "</a:Entities>" +
                        "<a:EntityName i:nil='true' />" +
                        "<a:MinActiveRowVersion i:nil='true' />" +
                        "<a:MoreRecords>false</a:MoreRecords>" +
                        "<a:PagingCookie i:nil='true' />" +
                        "<a:TotalRecordCount>0</a:TotalRecordCount>" +
                        "<a:TotalRecordCountLimitExceeded>false</a:TotalRecordCountLimitExceeded>";
                }
            }
            break;
        case Process.Type.Guid:
            // I don't think guid fields can even be null?
            xmlValue = value || Process._emptyGuid;

            // This is a hacky fix to get guids working since they have a conflicting namespace :(
            extraNamespace = " xmlns:c='http://schemas.microsoft.com/2003/10/Serialization/'";
            break;
        default: // bool, int, double, decimal
            xmlValue = value || null;
            break;
    }

    xml = "<a:KeyValuePairOfstringanyType>" +
            "<b:key>" + key + "</b:key>" +
            "<b:value i:type='" + dataType + "'" + extraNamespace;

    // nulls crash if you have a non-self-closing tag
    if (xmlValue === null || xmlValue === "") {
        xml += " i:nil='true' />";
    }
    else {
        xml += ">" + xmlValue + "</b:value>";
    }

    xml += "</a:KeyValuePairOfstringanyType>";

    return xml;
}

Process._getXmlEntityData = function (entity) {
    var xml = null;

    if (entity != null) {
        var attrXml = "";

        for (field in entity.attributes) {
            var a = entity.attributes[field];
            var aXml = Process._getXmlValue(field, a.type, a.value);

            attrXml += aXml;
        }

        if (attrXml !== "") {
            xml = "<a:Attributes>" + attrXml + "</a:Attributes>";
        }
        else {
            xml = "<a:Attributes />";
        }

        xml += "<a:EntityState i:nil='true' />" +
            "<a:FormattedValues />" +
            "<a:Id>" + entity.id + "</a:Id>" +
            "<a:KeyAttributes />" +
            "<a:LogicalName>" + entity.logicalName + "</a:LogicalName>" +
            "<a:RelatedEntities />" +
            "<a:RowVersion i:nil='true' />";
    }

    return xml;
}

Process._htmlEncode = function (s) {
    if (typeof s !== "string") { return s; }

    return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}

Process.Entity = function (logicalName, id, attributes) {
    this.logicalName = logicalName || "";
    this.attributes = attributes || {};
    this.formattedValues = {};
    this.id = id || Process._emptyGuid;
}

// Gets the value of the attribute without having to check null
Process.Entity.prototype.get = function (key) {
    var a = this.attributes[key];
    if (a != null) {
        return a.value;
    }

    return null;
}

Process.EntityReference = function (entityType, id, name) {
    this.id = id || Process._emptyGuid;
    this.name = name || "";
    this.entityType = entityType || "";
}

Process.Attribute = function (value, type) {
    this.value = value || null;
    this.type = type || "";
}



CRM Customization - Teklif Ürününden Sipariş Ürününe Mapping

Mapping MSCRM fields from Quote Product to Sales Order Product


Teklifi siparişe dönüştürdüğümüzde teklif ürününden sipariş ürününe custom alanların eşlenmediğini görürüz. 

Kullanıcı Geliştirme Arayüzüne baktığımızda  Teklif Ürünü entitisinin ilişkilerine baktığımızda Sipariş Ürünü ile ilgili bir ilişki olmadığını görüyoruz. Bu gibi durumlarda aşağıdaki yöntemle mapping işlemini yapıyoruz.

İlk olarak teklif ürünü ile sipariş ürünü arasındakı mappingin guid değerini bulmamız gerekecek . Bunun için aşağıdaki sql sorgusu sonucu aralarındakı mapping işleminin idsini buluruz.

 
select E.TargetEntityName , E.SourceEntityName , E.EntityMapId
from  EntityMap as E
where E.TargetEntityName='salesorderdetail' 
  and E.SourceEntityName='quotedetail'

Bulduğumuz EntityMapId değerini aşağıdaki linke veriyoruz ve tarayıcıda açıyoruz.


Örnek URL



Açılan sayfada New butonuna basalım ve mapping olacak custom alanların mappinglerini yapalım.
 
Son olarak yaptığımız işlemleri publish yapalım.


Fırsat Ürünü Teklif Ürünü MappingId

select E.TargetEntityName , E.SourceEntityName , E.EntityMapId
from  EntityMap as E
where E.TargetEntityName='quotedetail'

  and E.SourceEntityName='opportunityproduct'

Sipariş Ürünü Fatura Ürünü MappingId

select E.TargetEntityName , E.SourceEntityName , E.EntityMapId
from  EntityMap as E
where E.TargetEntityName='invoicedetail'
  and E.SourceEntityName='salesorderdetail'