Quantcast
Channel: Web API - Microsoft Dynamics 365 CRM Tips and Tricks
Viewing all 33 articles
Browse latest View live

Execute a workflow using Xrm.WebApi.online.execute method via JavaScript in Dynamics 365 CRM v9

$
0
0

Introduction

In this blog, we are going to create a request using ExecuteWorkflow action and would execute the request that would execute a custom workflow. This approach would eliminate the need to create an Ajax request and is supported across web client, UCI and Mobile.

For demonstration purpose, we have created a custom workflow. This would create a task in our CRM related to the current account when it’s triggered by a JavaScript function.

Note: Make sure to keep your existing custom workflow available to run as an on-demand process.

JavaScript in Dynamics 365 CRM v9

Now with the help of execute request we are going to trigger that workflow.

Solution: Following is the piece of code to achieve the above objective.

javascript

In the above piece of code, we have created a dynamics request object named “ExecuteCustomWorkflowRequest” and we have passed current account id to it along with workflow id. We would recommend to retrieve workflow id dynamically. As of now, we have passed hard coded workflow id for demonstration purpose, which can be found in the URL of workflow as highlighted in blue colour in the following screenshot:

JavaScript in Dynamics 365 CRM v9

Once the “triggerCustomWorkflowRequest” request is built, we would pass it to execute method which would then invoke “ExecuteWorkflow” action. This action will execute our workflow to create task related to the account record whose id was passed in the “triggerCustomWorkflowRequest” request.

Upon execution of our custom workflow via execute method, following task is created.

JavaScript in Dynamics 365 CRM v9

Also, following is a link to execute workflow via HTTP Request: http://www.inogic.com/blog/2016/11/execute-workflow-using-web-api-in-dynamics-365-2/

For more information on execute method visit the following link: https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/clientapi/reference/xrm-webapi/online/execute

You can find complete list of WebApi actions here:  https://docs.microsoft.com/en-us/dynamics365/customer-engagement/web-api/actions?view=dynamics-ce-odata-9

Hope it helps.

Cut short 90% of your manual work and repetitive data entry!

Get 1 Click apps and say goodbye to all repetitive data entry in CRM –
Click2Clone – Clone/Copy Dynamics 365 CRM records in 1 Click
Click2Export – Export Dynamics 365 CRM Report/CRM Views/Word/Excel template in 1 Click
Click2Undo – Undo & Restore Dynamics 365 CRM data in 1 Click


Execute Action with ColumnSet(ComplexType) type parameter Using Xrm.WebApi.online.execute in Dynamics 365 CRM V9.0

$
0
0

Introduction

Microsoft has introduced Xrm.WebApi.online.execute to execute an action in Dynamics CRM version 9.0. In our last blog we have seen how to Execute action using Xrm.WebApi.online.execute in Dynamics CRM. In this blog we will see how to execute action with “ColumnSet(ComplexType)” type property.

Here we are executing “GenerateQuoteFromOpportunity” action for sample purpose as this action contains the “ColumnSet(ComplexType)” type parameter.

Properties of ColumnSet(ComplexType) parameter:

xrm

For these properties we need to add another getMetadata method as shown in the below example.

Syntax:

Xrm.WebApi.online.execute(request).then(successCallback, errorCallback);

successCallback: This function call is for when is action executed successfully.

errorCallback: This function call is for when there is any error while executing action. It returns an error as result in string format.

Given below is the example of how to write the function to execute “GenerateQuoteFromOpportunity” action:

Generate Parameters:

/**

* This function generates quote from opportunity using GenerateQuoteFromOpportunity action

* @param formContext

* @param opportunityID

*/

function executeAction(executionContext) {

let functionName = “executeAction”;

var opportunityID = null;

var formContext = null;

try {

debugger;

//Get form context

formContext = executionContext.getFormContext();

//Get opportunity id

opportunityID = !isValid(executionContext.getFormContext().data)

|| !isValid(executionContext.getFormContext().data.entity)

|| !isValid(executionContext.getFormContext().data.entity.getId)

? null : executionContext.getFormContext().data.entity.getId();

//Set parameters

var GenerateQuoteFromOpportunityReq = function (OpportunityId, ColumnSetVal) {

this.OpportunityId = { “guid”: OpportunityId };

this.ColumnSet = {

“AllColumns”: ColumnSetVal,

“getMetadata”: function () {

return {

boundParameter: null,

operationType: 0,

operationName: “GenerateQuoteFromOpportunity”,

parameterTypes: {

“AllColumns”: {

“typeName”: “Edm.Boolean”, //Primitive Type

“structuralProperty”: 1

}

}

}

}

};

this.getMetadata = function () {

return {

boundParameter: null,

parameterTypes: {

“OpportunityId”: {

“typeName”: “Edm.Guid”, //Primitive Type

“structuralProperty”: 1

},

“ColumnSet”: {

“typeName”: “mscrm.ColumnSet”, //Complex Type

“structuralProperty”: 2

}

},

operationType: 0,

operationName: “GenerateQuoteFromOpportunity”

};

};

};

var generateQuoteFromOpportunityReq = new GenerateQuoteFromOpportunityReq(opportunityID, true);

}

Execute Action:

Xrm.WebApi.online.execute(generateQuoteFromOpportunityReq).then(function (result) {

//Validate result

if (!isValid(result) || !isValid(result[“responseText”])) {

return;

}

else {

//get result in JSON object

var resultJson = JSON.parse(result[“responseText”]);

//Validate JSON

if (isValid(resultJson)) {

//Validating the attributes

if (!isValid(Xrm) || !isValid(Xrm.Navigation)) { return; }

//openAlertDialog

Xrm.Navigation.openAlertDialog({ confirmButtonLabel: “Ok”, text: “Quote with ID: ” + resultJson.quoteid + ” is generated successfully. ” });

}

}

}, function (error) {

throwError(functionName, error);

});

} catch (error) {

throwError(functionName, error);

}

}

On success it returns a promise object with specific attributes.

In above example we have used ‘AllColums’ property of “ColumnSet(ComplexType)” parameter. In the same way we can use ‘Columns’ parameter. We just need to set “Edm.String” as typename in getMetadata method.

Conclusion

In this blog, we have seen how we can execute action with “ColumnSet(ComplexType)” type parameter using Xrm.WebApi.online.execute in Dynamics 365 CRM V9.0.

Click2Clone-One-Click-Productivity-App-to-Copy_clone-Dynamics-365_CRM-Records

Execute Different Web API Operations using PowerApps Portals (Preview)

$
0
0

Introduction

In the recent release, Microsoft has provided the ability using which we can perform different CRUD operations using Portals WEB API. The operations will run at server-side and are similar to Dynamics Web API Operations but the difference is in the way it is written and called in PowerApps Portals.

If you have a custom web page with a page template or web template and you want data displayed in the custom web page to be stored in Dynamics by performing some business logic then you need to use PowerApps Portals API, which will communicate with the Dynamics 365 in the backend and perform the required operation in Dynamics 365.

Let us consider a requirement where we need to record our punch in details, punch out details and if there is any incorrect entry then we need to delete that punch details. For this scenario, we will use PowerApps Portals Web API and see how we can implement the requirement.

So we will execute below four operations,

– Retrieve record
– Create record
– Update record
– Delete record

Before going directly to Web API, we need to first look at what are the configurations we need to do to allow Web API operations in PowerApps Portals.

Please check the below screenshots of the Portal Site Settings to allow Web API Operations in PowerApps Portal.

1. Create Site Setting in PowerApps Portal as below:

a. Enable the entity in PowerApps Portals

Note: new_logindetail is the logical name of the custom entity.

Execute Different WebAPI Operations using PowerApps Portals
b. Enable fields for API Operations

Execute Different WebAPI Operations using PowerApps Portals
c. Show Web API Errors in Portal

Execute Different WebAPI Operations using PowerApps Portals

Note: You need to create a Site Setting for each entity that needs to be enabled for Web API and if you want to enable all fields for Web API operations then you can use “*” or else you can specify the logical name of each field separated by a comma.

2. Create Entity Permission and Create new web role for Web API
You can navigate to Entity Permission entity directly from the navigation pane.

Execute Different WebAPI Operations using PowerApps Portals
Note: The highlighted is the custom entity used for performing Web API Operations. You can select any other entity which you want and give the privileges as shown above for the new Web Role which we will use for performing Web API Operations.

Execute Different WebAPI Operations using PowerApps Portals
Note: You can give any name to the Web Role but make sure to set Authenticated Users Role to Yes. By doing this only portal users i.e. authenticated users will able to perform Portal Web API CRUD Operations.

After our configurations are done, now we will see how we can perform different Web API operations in PowerApps Portal.

For executing Web API, Microsoft has provided a Wrapper AJAX function which we can use for executing any Web API method for any entity. Please check the below link to get and use the Wrapper AJAX function in your code.

https://docs.microsoft.com/en-us/powerapps/maker/portals/web-api-perform-operations#wrapper-ajax-function

As this is a common function which we can use for any Web API operations in the portal, so I will create a new Web Template and simply copy-paste the function code in the created Web Template as below:

AJAX Function Code Snippet:

<script>
(function(webapi, $){
function safeAjax(ajaxOptions) {
var deferredAjax = $.Deferred();

shell.getTokenDeferred().done(function (token) {
// add headers for AJAX
if (!ajaxOptions.headers) {
$.extend(ajaxOptions, {
headers: {
“__RequestVerificationToken”: token
}
});
} else {
ajaxOptions.headers[“__RequestVerificationToken”] = token;
}
$.ajax(ajaxOptions)
.done(function(data, textStatus, jqXHR) {
validateLoginSession(data, textStatus, jqXHR, deferredAjax.resolve);
}).fail(deferredAjax.reject); //AJAX
}).fail(function () {
deferredAjax.rejectWith(this, arguments); // on token failure pass the token AJAX and args
});

return deferredAjax.promise();
}
webapi.safeAjax = safeAjax;
})(window.webapi = window.webapi || {}, jQuery)
</script>

So our Wrapper AJAX template will look as seen from the below screenshot

Execute Different WebAPI Operations using PowerApps Portals

Now, whenever we want to refer to this in any other Web Template, you just need to use the below line of code:
{% include ‘Wrapper AJAX Template’ %}

Note that here I have used my newly created Web Template name i.e. ‘Wrapper Ajax Template’.

Now let us create a new page, which will be visible when the user login the portal and allows the user to punch in from the portal. Remember in the web page we will just add an HTML page using a Page template using which the user can do Punch In. Following are the details of the web page created.

Execute Different WebAPI Operations using PowerApps Portals

In order to render HTML in Web Page, I have use Web Template but you can also use Content Page of Web Page to add your custom HTML in the Web Page. I will perform all CRUD operations in the Web Template. Now let’s understand that in step by step.

1. There is a custom entity created in Dynamics to store the Login/Logout Details in CRM. First, we will retrieve Punch In details created today and if Punch In the record found then we will display that in the table in HTML.

2. We will have 3 buttons “Punch In”, “Punch Out” and “Delete” to perform the respective operations using Portals Web API.

Our final HTML will look like below,

Execute Different WebAPI Operations using PowerApps Portals

To retrieve the data from CRM, we can use normal FetchXml and display data in HTML table by looping through each punch in record if record exist already. Below is the code to retrieve and the data and display it in the HTML Table.

{% fetchxml punchdetails %}
<fetch version=”1.0″ output-format=”xml-platform” mapping=”logical” distinct=”false”>
<entity name=”new_logindetail”>
<attribute name=”new_logindetailid” />
<attribute name=”new_logouttime” />
<attribute name=”new_logintime” />
<attribute name=”createdon” />
<order attribute=”createdon” descending=”false” />
<filter type=”and”>
<condition attribute=”createdon” operator=”today” />
</filter>
</entity>
</fetch>
{% endfetchxml %}

<table>
<tr><th>Login Time</th><th>Logout Time</th><th>Date Created</th><th>Actions</th>
{% for item in punchdetails.results.entities %}
<tr>
<td>{{item.new_logintime}}</td>
<td>{{item.new_logouttime}}</td>
<td>{{item.createdon}}</td>
<td>
<button type=”button” id=”delete” onclick=”deletePunchDetails(‘{{item.new_logindetailid}}’)”>Delete</button>
<button type=”button” id=”punch_out” onclick=”updatePunchDetails(‘{{item.new_logindetailid}}’)”>Punch Out</button>
</td>
</tr>
{% endfor -%}
<tr>
<td><button type=”button” id=”punch_in” onclick=”addPunchDetails()”>Punch In</button></td>
</tr>
</table>

Below is the screenshot of the how web template will look like after adding the code. In the same way, you need to add the code in the Web Template.

Please note “punchdetails” is the name of the fetchXml variable which we need to use to retrieve the results from fetchXml. Also, to update and delete specific entry we need to add Update and Delete buttons in each row dynamically and call the respective function by passing GUID of the record.

We don’t need to add Punch In in each row as Punch In button is used to create a new record of Login/Logout Details in CRM.

Now we will see the code for each of the Web API request.

1. Create Punch In record:

function addPunchDetails()
{
webapi.safeAjax({
type: “POST”,
url: “/_api/new_logindetails”,
contentType: “application/json”,
data: JSON.stringify({
“new_logintime”: new Date(), //Date Time
“new_name”: “Login_”+new Date().toLocaleDateString(), //String
“new_loginattempts”:1, //Whole Number
“new_usertype”:2 //Option Set
“new_user@odata.bind”:”/contacts({{user.Id}})”, //Setting Logged In User(Lookup)
“new_workingday”: “2,3,4” //Multi-Select Option Set
}),
success: function (res, status, xhr) {
}
});
}

When webapi.safeAjax is executed, it calls the AJAX Wrapper class which we already added in another web template and references it in this web template.

Also, fields which I used for create request are based on my requirement but you can use different fields with different data type as well.

2. Update or Punch Out:

function updatePunchDetails(id)
{
webapi.safeAjax({
type: “PATCH”,
url: “/_api/new_logindetails(“+id+”)”,
contentType: “application/json”,
data: JSON.stringify({
“new_logouttime”: new Date()
}),
success: function (res) {
console.log(res);
}
});
}

The id parameter which we pass to this method is the GUID of the record that we pass from the loop above. Similarly, we will have to pass the parameter to DELETE method as well as below:

3. Delete Punch entry from CRM

function deletePunchDetails(id)
{
webapi.safeAjax({
type: “DELETE”,
url: “/_api/new_logindetails(“+id+”)”,
contentType: “application/json”,
success: function (res) {
console.log(res);
}
});
}

Note: Also, when you create record from portal “System” will be set as the Owner of the record.

Records created in CRM:

Execute Different Web API Operations using PowerApps Portals

Also as mentioned above, if the user don’t have permission to access page or anonymous users will not be able to see the page and hence won’t be able to perform Web API Operations as seen from the below screenshot.

For Anonymous Users:

Execute Different Web API Operations using PowerApps Portals

Note: All PowerApps Portal Web API Operations follow OData query syntax and work in the same manner as our Dynamics OData query works.

Conclusion

In this way, you can execute different Web API operations as per your requirement from PowerApps Portals.

How to Perform Basic CRUD Operations using Offline Web API in Mobile Clients

$
0
0

Dynamics 356

Introduction

Microsoft has provided offline ability to use “Dynamics 365 for phones app” or “Field Service (Dynamics 365) App”. Mobile Offline allows users to work with the data in offline mode as well i.e. when they are not connected to the internet. So, in the offline mode, if we want to create or manage the data programmatically, we need to use Microsoft Dynamics Offline Web API methods within the script.

Microsoft Dynamics Offline Web API methods can be used for basic commands while working in offline mode. The basic methods that are available for using the Xrm.WebApi.offline include the following: createRecord,  retrieveRecords, retrieveMultipleRecords, updateRecord and deleteRecord.

Note: These OfflineWebApi methods will work only for tables that are enabled for mobile offline and only basic validation will be performed on the data that is being input.

By using the below method, we can identify whether the entity is available to use in offline mode: Xrm.WebApi.offline.isAvailableOffline(entityLogicalName);

In this blog, I will show the sample codes to create, retrieve, update and delete records using Xrm.WebApi.offline methods in JavaScript.

  1. Create:

It is used to create table record. The required parameters of this function are;

    1. entityLogicalName – Logical name of the table.
    2. data – JSON object of the data to create a new record.

//This function is used to create a contact record
function createContact() {
    var objContact = null;
    try {
          //Create the Json object of contact record
          objContact = new Object();
          objContact["firstname"] = "Jenny";
          objContact["lastname"] = "Smith";
          //Call Create method
          Xrm.WebApi.offline.createRecord("contact", objContact).then(function (result) {
              Xrm.Navigation.openAlertDialog("Contact record has been created successfully.");
          },
        function (error) {
            Xrm.Navigation.openAlertDialog(error.message);
        });
    } catch (e) {
        Xrm.Navigation.openAlertDialog(e.message);
    }

  1. Update:

It is used to update table record. The required parameters of this function are;

    1. entityLogicalName – Logical name of the table.
    2. entityId – GUID of record.
    3. data – JSON object of the data to update record.

//This function is used to update a contact record
function updateContact() {
    var objContact = null;
    try {
        //Create the Json object of contact record
        objContact = new Object();
        objContact["telephone1"] = "18018015012";
        objContact["fax"] = "123456";
        objContact["parentcustomerid_account@odata.bind"] = "/accounts(08f4aca2-9793-eb11-b1ac-0022481cb79b)"
        //Call Update method
        Xrm.WebApi.offline.updateRecord("contact", "fb4231a9-dba4-eb11-b1ac-000d3a4e57c1", objContact).then(function (result) {
            Xrm.Navigation.openAlertDialog("Contact record has been updated successfully.");
        },
      function (error) {
          Xrm.Navigation.openAlertDialog(error.message);
      });
    } catch (e) {
        Xrm.Navigation.openAlertDialog(e.message);
    }
}

  1. Delete:

It is used to delete table record. The required parameters of this function are;

    1. entityLogicalName – Logical name of the table.
    2. entityId – GUID of record.

//This function is used to delete a contact record
function deleteContact() {
    try {
        //Call Delete method
        Xrm.WebApi.offline.deleteRecord("contact", "5d0111d1-bf05-4079-b695-247e4c9acac2").then(function (result) {
            Xrm.Navigation.openAlertDialog("Contact record has been deleted successfully.");
        },
      function (error) {
          Xrm.Navigation.openAlertDialog(error.message);
      });
    } catch (e) {
        Xrm.Navigation.openAlertDialog(e.message);
    }
}

  1. Retrieve:

It is used to retrieve a single record from a table. The required parameters of this function are;

  1. entityLogicalName – Logical name of the table.
  2. entityId – GUID of record.
  3. options – OData Query.

//This function is used to retrieve single contact record
function retrieveContact() {
    try {
        //Call Retrieve method
        Xrm.WebApi.offline.retrieveRecord("contact", "fb4231a9-dba4-eb11-b1ac-000d3a4e57c1", "?$select=firstname,lastname,telephone1").then(function (result) {
            Xrm.Navigation.openAlertDialog("Contact retrieved successfully - FirstName: " + result.firstname + ", LastName: " + result.lastname + " and Telephone: " + result.telephone1);
        },
      function (error) {
          Xrm.Navigation.openAlertDialog(error.message);
      });
    } catch (e) {
        Xrm.Navigation.openAlertDialog(e.message);
    }

  1. RetrieveMultiple:

It is used to retrieve multiple records from the table. The required parameters of this function are;

  1. entityLogicalName – Logical name of the table.
  2. options – we can use OData Query and FetchXML as well.

RetrieveMultiple method with OData Query

//This function is used to retrieve contact records using OData Query
function retrieveContactsWithOdata() {
    try {
        //Call Retrieve method
        Xrm.WebApi.offline.retrieveMultipleRecords("contact", "?$select=firstname,lastname,telephone1&$filter=_parentcustomerid_value ne null").then(function (result) {
            Xrm.Navigation.openAlertDialog("Length: " + result.entities.length);
        },
      function (error) {
          Xrm.Navigation.openAlertDialog(error.message);
      });
    } catch (e) {
        Xrm.Navigation.openAlertDialog(e.message);
    }
}

RetrieveMultiple method with FetchXML – To use a FetchXML, use the fetchXml attribute to specify the query.

//This function is used to retrieve contact records using Fetch XML
function retrieveContactsWithFetch() {
    var fetchXML = null;
    try {
        //Fetch XML to retrieve Contact records
        fetchXML = "<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>" +
        "<entity name='contact'>" +
          "<attribute name='fullname' />" +
          "<attribute name='telephone1' />" +
          "<attribute name='contactid' />" +
          "<order attribute='fullname' descending='false' />" +
          "<filter type='and'>" +
            "<condition attribute='parentcustomerid' operator='not-null' />" +
          "</filter>" +
        "</entity>" +
      "</fetch>";
        //Call Retrieve method
        Xrm.WebApi.offline.retrieveMultipleRecords("contact", "?fetchXml=" + fetchXML).then(function (result) {
            Xrm.Navigation.openAlertDialog("Length: " + result.entities.length);
        },
      function (error) {
          Xrm.Navigation.openAlertDialog(error.message);
      });
    } catch (e) {
        Xrm.Navigation.openAlertDialog(e.message);
    }
}

Conclusion

By using the Offline Web API methods, we can easily create and manage the table record which is available in the offline database for offline use within mobile clients i.e., “Dynamics 365 for phones app” or “Field Service (Dynamics 365) App”.

Maplytics

 

Querying data in Microsoft Dynamics CRM 2016 using Web API

$
0
0

Introduction:

With Microsoft Dynamics CRM 2016, Web API that was in Preview for CRM 2015 is now GA. Web API is really OData V4 which is the later version of OData V2 that was implemented in earlier versions of CRM until CRM 2015.

With CRM 2016, OData V2 is deprecated, this means that though the legacy code written using OData V2 will continue to function, it is not advised to continue to develop using this version of OData starting CRM 2016.

The earlier version of OData was strictly restricted to CRUD operations, how with Web API you can even perform operations that earlier required us to use SOAP requests.

In the earlier post, it was all about executing FetchXML queries using Web API, well that was to some extent because I didn’t have much success querying and applying some very common queries. After spending some more time with WEB API and trying to get things done exclusively using OData V4, I did get quite a few things figured out.

In this post, I am listing out some of the frequently used queries and how these could be generated using Web API.

OData v4 endpoints:

Under Developer Resources, you can now find the endpoint for Web API.

Querying data in Microsoft Dynamics CRM 2016

Notice the change in the URL structure, it is now /api/data/v8.0/

Earlier it was /xrmservices/2011/organizationdata.svc/

Sample Queries:

  1. List accounts starting with A and C

    var qry = “accounts?$filter=startswith(name,’A’) or startswith(name,’C’)”;

    Since field names have not been specified all the columns are listed.

    The entitycollection does not include Set Prefix anymore besides its using the logical name throughout.

  2. List accounts owned by a particular user

    var qry = accounts?$select=name,accountnumber,_primarycontactid_value,createdon,accountcategorycode,revenue&$filter=_ownerid_value%20eq%201ea6fc32-9b2d-47e6-b9ab-b5f23f69e34f;

    Here we had to provide the guid of the user that you need to filter by. Also notice that the ownerid attribute has been mentioned as _ownerid_value

    All lookups are listed in the query result to follow the naming structure

    _<logicalname>_value.

  3. Read account details along with the primary contact phone

    We need to use the $expand clause to request data of the related entity. However, it appears that the $expand clause only works when requesting data of a single record as shown in the below query.

    var qry = “accounts(4ef2c099-bca1-e511-80de-3863bb349a78)?$select=name,accountnumber,_primarycontactid_value,createdon,accountcategorycode,revenue&$filter=contains(name,'(sample)’)&$orderby=name&$expand=primarycontactid($select=fullname,telephone1)”

    If you were to request this for the entire accounts collection, you receive the following error message

    {
    
    "error":{
    
    "code":"","message":"Expansion of navigation properties isn\u2019t supported on entity collections.","innererror":{
    
    "message":"Expansion of navigation properties isn\u2019t supported on entity collections.","type":"Microsoft.Crm.CrmHttpException","stacktrace":" at
  4. List all Phone Calls of an account

    This will display only the subject of the related phone calls.

    var qry = “accounts(4ef2c099-bca1-e511-80de-3863bb349a78)?$expand=Account_Phonecalls($select=subject)”

Understand the Query Results:

Unlike the OData V2 queries, the results here are returned in JSON format

{

"@odata.context":"https://dyn20161.crm5.dynamics.com/api/data/v8.0/$metadata#accounts(name,accountnumber,_primarycontactid_value,createdon,accountcategorycode,revenue)","value":[

"@odata.etag":"W/\"632098\"","name":"Alpine Ski House (sample)","accountnumber":"ABCO9M32","_primarycontactid_value":"1cf3c099-bca1-e511-80de-3863bb349a78","createdon":"2015-12-13T17:12:15Z","accountcategorycode":null,"revenue":90000.0000,"accountid":"4cf2c099-bca1-e511-80de-3863bb349a78","_transactioncurrencyid_value":"5022ed92-bca1-e511-80e1-3863bb345aa8"

},{

"@odata.etag":"W/\"632065\"","name":"A. Datum Corporation (sample)","accountnumber":null,"_primarycontactid_value":"1ef3c099-bca1-e511-80de-3863bb349a78","createdon":"2015-12-13T17:12:15Z","accountcategorycode":null,"revenue":10000.0000,"accountid":"4ef2c099-bca1-e511-80de-3863bb349a78","_transactioncurrencyid_value":"5022ed92-bca1-e511-80e1-3863bb345aa8"

}

]

}

Now if see the results here, the primary contact id only provides the Guid, not really helpful, and for currency data types, it again returns only the number, the currency is provided as transaction guid, so again formatted value missing.

If we want the results to return the formatted values, we need to pass the following in the header tag of the request

odata.include-annotations=”OData.Community.Display.V1.FormattedValue”

I haven’t figured it out how to pass these in the browser url, but here is the code I use to pass the header values.

var qry = url;

var headers = {


'Content-Type': 'application/json',

Accept: 'application/json', 'OData-MaxVersion': 4.0,

Prefer: 'odata.include-annotations="*", odata.maxpagesize=3'

};

var request = {

requestUri: qry,

method: 'GET',

headers: headers,

data: null

};

 
odatajs.oData.request(

request,

successCallback,

errorCallback);

In the above code, you can replace the “*” with “OData.Community.Display.V1.FormattedValue”, the other preferences supported are

Microsoft.Dynamics.CRM.lookuplogicalname

Microsoft.Dynamics.CRM.associatednavigationproperty

Generally, for lookups, we are used to receiving 3 set of data,

The lookup entity name, the guid and the record name. By default we only received the Guid of a lookup field, if we need the record name and the entity name, we need to include the preferences listed above.

If you want all preferences to be applied, pass “*”

With all preferences the applied the result would appear as

Querying data in CRM 2016 using Web API

Lookup field details are available as shown above

_primarycontactid_value: “1ef3c099-bca1-e511-80de-3863bb349a78”

_primarycontactid_value@Microsoft.Dynamics.CRM.associatednavigationproperty: “primarycontactid”

_primarycontactid_value@Microsoft.Dynamics.CRM.lookuplogicalname: “contact”

_primarycontactid_value@OData.Community.Display.V1.FormattedValue: “Rene Valdes (sample)”

And we now also get the revenue formatted with the currency symbol and the date.

Paging:

To handle paging you need to specify the page size, which is now called odata.maxpagesize=n

N stands for the count of records to be returned.

You also receive the paging cookie, which will allow you to request the next set of records.

 Web API

Use the nextlink url to the Web API to request the next set of data. It returns a fully qualified url with the query parameters set that can be used just as is.

Result Count:

When you include the $count=true in your query, you get the total count of the records returned by the query in the query result.

If you query the following,

var qry5 = “https://xxx.crm5.dynamics.com/api/data/v8.0/accounts?$count=true&$top=2”

You get

Querying data in Dynamics CRM 2016 using Web API

The total count is 19 even though the results requested were only top 2

Note, if there are more than 5000 records that the query returns, the count here would still return 5000 only.

Conclusion:

The Web API query still has a few limitations and like the earlier OData V2, there are limitations on what kind of data can be queried. You can find the complete list here.

In this post I have covered queries, in the later blogs hope to cover the other operations supported by WEB API.

Make your Dynamics CRM life easy with Inogic Dynamics CRM Solutions. Read more about our add-ons here.

Cut short 90% of your manual work and repetitive data entry!

Get 1 Click apps and say goodbye to all repetitive data entry in CRM –
Click2Clone – Clone/Copy Dynamics 365 CRM records in 1 Click
Click2Export – Export Dynamics 365 CRM Report/CRM Views/Word/Excel template in 1 Click
Click2Undo – Undo & Restore Dynamics 365 CRM data in 1 Click

The post Querying data in Microsoft Dynamics CRM 2016 using Web API first appeared on Microsoft Dynamics 365 CRM Tips and Tricks.

Executing Predefined Queries in Dynamics CRM using Web API through Scripts

$
0
0

Introduction:

What do you mean by Predefined Query?

System Views created in the CRM contains an inbuilt query which displays the results satisfying the Query mentioned in the view.

For e.g. “Active Contacts” an OOB system view.

Also, Users can create their views in Advance Find by specifying their criteria’s and save it giving any custom name.

These queries are known as Predefined Queries.

Using Web API we can retrieve and execute these Predefined Queries in the below way:

First in order to execute the Query we require the Query ID which we can retrieve in below manner:

There are be 2 types of Query in general:

  1. SavedQuery: Contains the SystemDefined View for an Entity. These views are stored in SavedQuery entity.
  1. UserQuery: Contains the Advanced Find Views created by the user for an Entity. These

Views are stored in UserQuery Entity.

To get the Query ID of System View the syntax is as shown below:

If it is System View then it is:

GET [Organization URI]/api/data/v8.0/savedqueries?$select=name,savedqueryid&$filter=name eq ‘Active Contacts’

If it is Custom View (User created view) then it is:

GET [Organization URI]/api/data/v8.0/userqueries?$select=name,userqueryid&$filter=name eq Custom Filter View’

Where

GET [Organization URI]: https://myorg.crm.dynamics.com [CRM Server Url]

Code to get the Query Id Variable:

//Method to retrieve the Query Id 
function retrieveQueryId(viewName, queryEntity, selectOptions) {
    var functionName = "retrieveQueryId";
    var viewId = "";
    try {
        //Get Client Url
        var clientUrl = Xrm.Page.context.getClientUrl();
        //Declare new XML HttpRequest Object
        var req = new XMLHttpRequest()
        //To Retrieve PreDefinedQuery Query
        req.open("GET", encodeURI(clientUrl + "/api/data/v8.0/" + queryEntity + "?" + selectOptions + "&$filter=name eq '" + viewName + "'"), false);
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.send();

        if (req.status == 200) {

            var data = JSON.parse(req.response);
            var dat = data.value;
            //If record greater than 0 i.e. atleast 1 record found
            if (dat.length > 0) {
                //If it is System View
                if (queryEntity.toLowerCase() == "savedqueries") {
                    //read the first record
                    viewId = dat[0].savedqueryid;
                }//If it ia an User Query [Advanced Find]
                else if (queryEntity.toLowerCase() == "userqueries") {
                    //Read the first record
                    viewId = dat[0].userqueryid;
                }
            }


        }
        else {
            var error = JSON.parse(req.response).error;

        }

        return viewId;
    } catch (e) {
        alert(e.message);
    }
}

Where

  • viewName = View Name For e.g. “Active Contacts”
  • queryEntity = If it is System View then it is “savedqueries”. For Custom View it is “userqueries”
  • selectOptions = Columns which you want to select For e.g. “select=name,savedqueryid” for System View & “select=name,userqueryid

This functions returns the viewId of the Query record.

Now, we will see how to execute this Query after getting the ViewId:

Syntax:

If it is System View then it is:

GET [Organization URI]/api/data/v8.0/contacts?savedQuery=00000000-0000-0000-00aa-000010001002

If it is Custom View (User created view) then it is:

GET [Organization URI]/api/data/v8.0/contacts?userQuery=77444281-0010-1300-00aa-000010001002

Code to Execute the Query:

//Method executes the Query and returns Array of Records
function executeQuery(entityName, queryType, viewid) {
    var functionName = "executeQuery";
    var recordsFromView = null;
    try {

        //Get Client Url
        var clientUrl = Xrm.Page.context.getClientUrl();
        //Declare new XML HttpRequest Object
        var req = new XMLHttpRequest()

        if (viewid == "") {
            return;
        }
        //Sync Operation
        req.open("GET", encodeURI(clientUrl + "/api/data/v8.0/" + entityName + "?" + queryType + "=" + viewid), false);
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.send();
        //If it is executed successfully
        if (req.status == 200) {

            var data = JSON.parse(req.response);
            recordsFromView = data.value;

        }
        else {
            var error = JSON.parse(req.response).error;
        }

        return recordsFromView;

    } catch (e) {
        alert(e.message);
    }
}

Where

  • clientUrl = CRM Server Url
  • entityName = The Entity whose View Id we have found
  • queryType = If it is a System View then queryType = “savedQuery”, For Custom View (user created) it is “userQuery”
  • viewid: ViewId which we retrieved above using retrieveQueryId() method.

Also, we can filter a particular View records based on its parent record.

For e.g.: There is System view “Open Opportunities”. We will filter the records based on a particular Account and retrieve the Open Opportunities related to this record.

Let’s see How we can achieve this below:

  1. Get the “Open Opportunities” view Id using retrieveQueryId() method which is shown above.
  2. After that call this function:
//Method to return records from View by Filtering it out based on the Parent Record
function executeFilterQuery(filterentityName, filterentityId, relationshipName,queryType, viewId) {
    var functionName = "executeQuery";
    var recordsFromView = null;
    try {

        //Get Client Url
        var clientUrl = Xrm.Page.context.getClientUrl();
        //Declare new XML HttpRequest Object
        var req = new XMLHttpRequest()

        if (viewId == "") {
            return;
        }
        //Sync Operation
        req.open("GET", encodeURI(clientUrl + "/api/data/v8.0/" + filterentityName + "(" + filterentityId + ")/" + relationshipName + "/?" + queryType + "=" + viewId), false);
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.send();
        //If it is executed successfully
        if (req.status == 200) {

            var data = JSON.parse(req.response);
            recordsFromView = data.value;

        }
        else {
            var error = JSON.parse(req.response).error;
        }

        return recordsFromView;

    } catch (e) {
        alert(e.message);
    }
}

Where:

  • filterentityName: Parent record by which we need to filter the records. For e.g. Accounts in our case.
  • filterentityId: Parent Record Id
  • relationshipName: It is the collection-valued navigation property name. In our case “opportunity_parent_account”
  • queryType = If it is a System View then queryType = “savedQuery”, For Custom View (user created) it is “userQuery”
  • viewid: ViewId which we retrieved above using retrieveQueryId() method.

For Testing purpose you may call the below method on any event of the form:

//Method called on Load event
function startOperation() {

    //For System Views
    //Retrieve the View Id for the system view "Active Contacts"
    var systemQueryId = retrieveQueryId("Active Contacts", "savedqueries", "$select=name,savedqueryid")
    var queryRecords = executeQuery("contacts", "savedQuery", systemQueryId);

    //For User Created Views
    //Retrieve the View Id for the user created view "User Created Custom View"
    var customQueryId = retrieveQueryId("User Created Custom View", "userqueries", "$select=name,userqueryid")
    var customQueryRecords = executeQuery("contacts", "userQuery", customQueryId);


    //To Execute Views By filtering it based on parent record

    //Retrieve the View Id for the system view "Active Contacts"
    var filterviewId = retrieveQueryId("Open Opportunities", "savedqueries", "$select=name,savedqueryid");

    //Retrieve the Opportunities record that belong to particular Account
    var oppRecords = executeFilterQuery("accounts", "D8747EC1-A6F5-E511-80E2-C4346BAC339C", "opportunity_parent_account","savedQuery", filterviewId);

}

 Conclusion:

In this way we can execute Predefined Queries using Web API through Scripts.

Lets have a quick glimpse of new exciting features coming up in Maplytics May Release.

The post Executing Predefined Queries in Dynamics CRM using Web API through Scripts first appeared on Microsoft Dynamics 365 CRM Tips and Tricks.

Execute Web API request using Angular JS in Dynamics CRM

$
0
0

Introduction

In our earlier blogs of  Web API introduced in Dynamics CRM 2016, we have explained different requests and functions of Web API to querying and performing operations in Dynamics CRM.

This blog will show you how to execute Web API request using Angular JS.

This article would be helpful for those who have knowledge of Angular JS and now want to know how to use Angular JS to perform operations in Dynamic CRM.

Angular JS provides in-built service “$http” that facilitates communication with the remote HTTP servers via XMLHttpRequest object or via JSONP. In JQuery, $.ajax is used for same purpose.

So, we can use “$http” service to execute Web API request.

Below is the code snippet that executes Web API function:

     $http({
                url: encodeURI(Xrm.Page.context.getClientUrl() + "/api/data/v8.0/RetrieveVersion()"),
                dataType: 'json',
                method: 'GET',
                headers: {
                    "Content-Type": "application/json"
                }
            }).success(function (response) {
                successCallback(response.Version);
            })
        .error(function (error) {
            errorCallback(error);
        });

You can see that, we pass Web API request to retrieve version of Dynamics CRM to URL. Execute “RetrieveVersion()” function, similarly you can execute other Web API functions like “WhoAmI()”, ”GetDefaultPriceLevelRequest()”, etc.

Below is the code snippet that query Dynamics CRM data,

  $http({
                url: encodeURI(Xrm.Page.context.getClientUrl() + "/api/data/v8.0/accounts?$select=name&$top=3"),
                dataType: 'json',
                method: 'GET',
                headers: {
                    "Accept": "application/json",
                    "OData-MaxVersion": "4.0",
                    "OData-Version": "4.0",
                    "Prefer": "odata.maxpagesize=3"
                }
            }).success(function (response) {
                successCallback(response);
            })
       .error(function (error) {
           errorCallback(error);
       });

In this code, we have passed Web API query to select top 3 accounts. Here, the only difference between above code and the code that executes Web API function is URL and headers.

Conclusion:

If you are developing an application for Dynamics CRM using Angular JS, we can use $http service to get Dynamics CRM data or perform operations in Dynamics CRM.

Completed  with Dynamics CRM implementation? Whats next? Monitor User Adoption!

The post Execute Web API request using Angular JS in Dynamics CRM first appeared on Microsoft Dynamics 365 CRM Tips and Tricks.

Retrieve Metadata using Name in Web API

$
0
0

Dynamics 365 introduced a lot of new features and improvements over the previous versions to offer more control and functionalities to the user. The ability to retrieve metadata using name is one such improvement in Web API.

Previously, to retrieve entity metadata, users needed to use ‘metadataid’. With the addition of this improvement, users can now retrieve the Entity/Attributes/Global Option Set meta by using the logical name.

When do we need to retrieve metadata?

There are many scenarios where the user needs object type code, primary attributes, localized label, list of entity attributes, etc. or when the user wants option set metadata. In such situations the user needs to read the entity metadata which can now be easily retrieved.

Let us see an example to understand how to retrieve Entity metadata:

  • To retrieve Contact entity metadata using Name, use the script mentioned below;
//this function is used to retrieve entityMetadata
function retrieveEntityMetaData() {

    var entityName = "";
    try {       
        //set variable value
        entityName = "contact";

        //create AJAX request
        $.ajax({
            type: "GET",
            contentType: "application/json; charset=utf-8",
            datatype: "json",
            url: encodeURI(this.getWebAPIPath() + "EntityDefinitions(LogicalName='" + entityName + "')"),

            beforeSend: function (xhr) {
                //Specifying this header ensures that the results will be returned as JSON.             
                xhr.setRequestHeader("Accept", "application/json");
                xhr.setRequestHeader("Accept", "application/json");
                xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
                xhr.setRequestHeader("OData-MaxVersion", "4.0");
                xhr.setRequestHeader("OData-Version", "4.0");
            },
            success: function (data, textStatus, xhr) {
                //Call successCallback
                retrieveEntityMetaDataSuccess(data);
            },
            error: function (xhr, textStatus, errorThrown) {
                errorCallback(xhr);
            }
        });

    } catch (e) {
        showMessage(e.message);
    }
}
  •  The ‘success callback’ function mentioned below will get the metadata;
//success call back
function retrieveEntityMetaDataSuccess(data) {
    try {

        if(data != null) {

            //get objectTypeCode
            var objectTypeCode = data.ObjectTypeCode;

            //get primary name
            var primaryAttribute = data.PrimaryNameAttribute;
        }
    }
    catch(e) {
        showMessage(e.message);
    }
}
  •  If you want to retrieve metadata of any particular attribute then pass the following in url parameter in Ajax request;
  url:encodeURI(this.getWebAPIPath() + "EntityDefinitions(LogicalName='" + entityName + "')/Attributes(LogicalName='parentcustomerid')") ,
success: function (data, textStatus, xhr) {
                        //Call successCallback
                        successCallback(data);
                    },

 In successCallback function, use data.value to get the attribute metadata.

  • If you want to retrieve all the entity attributes then pass the following in url parameter in Ajax request;
url:encodeURI(this.getWebAPIPath() + "EntityDefinitions(LogicalName='" + entityName + "')/Attributes")

 In successCallback function, use data.value to get the list of entity attributes.

  • If you want to retrieve relationship metadata then you can use the following in url parameter in Ajax request;
url: encodeURI(this.getWebAPIPath() + "RelationshipDefinitions(SchemaName='account_primary_contact')")

 In successCallback function, use data.value to get the relationship metadata.

  • If you want to retrieve Global option set metadata then use the following in url parameter in Ajax request;
url: encodeURI(this.getWebAPIPath() + "GlobalOptionSetDefinitions(Name='budgetstatus')")

In successCallback function, use data.Options to get all options.

 

Conclusion:

Now with the addition of the ability to retrieve metadata using name in Dynamics 365, users can easily retrieve metadata.

One Pic = 1000 words! Analyze data 90% faster with visualization apps!

Get optimum visualization of Dynamics 365 CRM data with –
Kanban Board – Visualize Dynamics 365 CRM data in Kanban view by categorizing entity records in lanes and rows as per their status, priority, etc.
Map My Relationships – Map My Relationships – Visualize connections and relationships between Dynamics 365 CRM entities or related records in a Mind Map view.

The post Retrieve Metadata using Name in Web API first appeared on Microsoft Dynamics 365 CRM Tips and Tricks.


Use WEB API Batch Request in Dynamics 365 to execute long FetchXML

$
0
0

Introduction:

Recently we had a project where we use WEB API for retrieve the records from Dynamics CRM. In our project, we dynamically create FetchXML to retrieve records but sometimes Fetchxml have a lot of columns and conditions etc so its length get increase and we this the fetchxml in URL which violates the browser URL length rule. So When we try to execute this long length FetchXML and retrieve the records using the GET method, We were getting the error message of “HTTP Error 404 – Not Found” because of WEB API request fails to execute too long FetchXML. When we work on this error message, we find that we need to use WEB API Batch Request to execute the long FetchXML.

In the below example, we execute the long FetchXML of account entity and use POST request to execute long FetchXML.

First, we created the simple request body as below:

//create request body
var bodyFetch='';
bodyFetch = '--batch_recordfetch\n'
bodyFetch += 'Content-Type: application/http\n'
bodyFetch += 'Content-Transfer-Encoding: binary\n'
bodyFetch += '\n'
bodyFetch += 'GET [CRM URL]/api/data/v8.2/accounts?fetchXml=' + fetch + ' HTTP/1.1\n'
bodyFetch += 'Content-Type: application/json\n'
bodyFetch += 'OData-Version: 4.0\n'
bodyFetch += 'OData-MaxVersion: 4.0\n'
bodyFetch += 'Prefer: odata.include-annotations=*\n'
bodyFetch += '\n'
bodyFetch += '--batch_recordfetch--'

Note: ‘fetch’ is the parameter of the long FetchXML.

And we pass the created the simple request body as data to Ajax request and we will receive the response of request as success or failure as below:

//create AJAX request
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
datatype: "json",
async: true,
url: '[CRM URL]/api/data/v8.2/' + '$batch',
data: bodyFetch,
beforeSend: function (xhr) {
//Specifying this header ensures that the results will be returned as JSON.
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("OData-MaxVersion", "4.0");
xhr.setRequestHeader("OData-Version", "4.0");
xhr.setRequestHeader("Prefer", "odata.include-annotations=*");
xhr.setRequestHeader("Content-Type", "multipart/mixed;boundary=batch_recordfetch");
},
//success callback
success: function (data, textStatus, xhr) {
data = JSON.parse(data.substring(data.indexOf('{'), data.lastIndexOf('}') + 1));
if (data != null) {
if (data.value == null) {
alert("success");
}
}
},
//error callback
error: function (xhr, textStatus, errorThrown) {
alert("failed");                          
}
});

Conclusion:

User can easily execute the long length FetchXML using the WEB API Batch Request.

To read more about FetchXML visit here.

Export Dynamics CRM Reports

The post Use WEB API Batch Request in Dynamics 365 to execute long FetchXML first appeared on Microsoft Dynamics 365 CRM Tips and Tricks.

Execute a workflow using Xrm.WebApi.online.execute method via JavaScript in Dynamics 365 CRM v9

$
0
0

Introduction

In this blog, we are going to create a request using ExecuteWorkflow action and would execute the request that would execute a custom workflow. This approach would eliminate the need to create an Ajax request and is supported across web client, UCI and Mobile.

For demonstration purpose, we have created a custom workflow. This would create a task in our CRM related to the current account when it’s triggered by a JavaScript function.

Note: Make sure to keep your existing custom workflow available to run as an on-demand process.

JavaScript in Dynamics 365 CRM v9

Now with the help of execute request we are going to trigger that workflow.

Solution: Following is the piece of code to achieve the above objective.

javascript

In the above piece of code, we have created a dynamics request object named “ExecuteCustomWorkflowRequest” and we have passed current account id to it along with workflow id. We would recommend to retrieve workflow id dynamically. As of now, we have passed hard coded workflow id for demonstration purpose, which can be found in the URL of workflow as highlighted in blue colour in the following screenshot:

JavaScript in Dynamics 365 CRM v9

Once the “triggerCustomWorkflowRequest” request is built, we would pass it to execute method which would then invoke “ExecuteWorkflow” action. This action will execute our workflow to create task related to the account record whose id was passed in the “triggerCustomWorkflowRequest” request.

Upon execution of our custom workflow via execute method, following task is created.

JavaScript in Dynamics 365 CRM v9

Also, following is a link to execute workflow via HTTP Request: https://www.inogic.com/blog/2016/11/execute-workflow-using-web-api-in-dynamics-365-2/

For more information on execute method visit the following link: https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/clientapi/reference/xrm-webapi/online/execute

You can find complete list of WebApi actions here:  https://docs.microsoft.com/en-us/dynamics365/customer-engagement/web-api/actions?view=dynamics-ce-odata-9

Hope it helps.

Cut short 90% of your manual work and repetitive data entry!

Get 1 Click apps and say goodbye to all repetitive data entry in CRM –
Click2Clone – Clone/Copy Dynamics 365 CRM records in 1 Click
Click2Export – Export Dynamics 365 CRM Report/CRM Views/Word/Excel template in 1 Click
Click2Undo – Undo & Restore Dynamics 365 CRM data in 1 Click

The post Execute a workflow using Xrm.WebApi.online.execute method via JavaScript in Dynamics 365 CRM v9 first appeared on Microsoft Dynamics 365 CRM Tips and Tricks.

Execute Action with ColumnSet(ComplexType) type parameter Using Xrm.WebApi.online.execute in Dynamics 365 CRM V9.0

$
0
0

Introduction

Microsoft has introduced Xrm.WebApi.online.execute to execute an action in Dynamics CRM version 9.0. In our last blog we have seen how to Execute action using Xrm.WebApi.online.execute in Dynamics CRM. In this blog we will see how to execute action with “ColumnSet(ComplexType)” type property.

Here we are executing “GenerateQuoteFromOpportunity” action for sample purpose as this action contains the “ColumnSet(ComplexType)” type parameter.

Properties of ColumnSet(ComplexType) parameter:

xrm

For these properties we need to add another getMetadata method as shown in the below example.

Syntax:

Xrm.WebApi.online.execute(request).then(successCallback, errorCallback);

successCallback: This function call is for when is action executed successfully.

errorCallback: This function call is for when there is any error while executing action. It returns an error as result in string format.

Given below is the example of how to write the function to execute “GenerateQuoteFromOpportunity” action:

Generate Parameters:

/**

* This function generates quote from opportunity using GenerateQuoteFromOpportunity action

* @param formContext

* @param opportunityID

*/

function executeAction(executionContext) {

let functionName = “executeAction”;

var opportunityID = null;

var formContext = null;

try {

debugger;

//Get form context

formContext = executionContext.getFormContext();

//Get opportunity id

opportunityID = !isValid(executionContext.getFormContext().data)

|| !isValid(executionContext.getFormContext().data.entity)

|| !isValid(executionContext.getFormContext().data.entity.getId)

? null : executionContext.getFormContext().data.entity.getId();

//Set parameters

var GenerateQuoteFromOpportunityReq = function (OpportunityId, ColumnSetVal) {

this.OpportunityId = { “guid”: OpportunityId };

this.ColumnSet = {

“AllColumns”: ColumnSetVal,

“getMetadata”: function () {

return {

boundParameter: null,

operationType: 0,

operationName: “GenerateQuoteFromOpportunity”,

parameterTypes: {

“AllColumns”: {

“typeName”: “Edm.Boolean”, //Primitive Type

“structuralProperty”: 1

}

}

}

}

};

this.getMetadata = function () {

return {

boundParameter: null,

parameterTypes: {

“OpportunityId”: {

“typeName”: “Edm.Guid”, //Primitive Type

“structuralProperty”: 1

},

“ColumnSet”: {

“typeName”: “mscrm.ColumnSet”, //Complex Type

“structuralProperty”: 2

}

},

operationType: 0,

operationName: “GenerateQuoteFromOpportunity”

};

};

};

var generateQuoteFromOpportunityReq = new GenerateQuoteFromOpportunityReq(opportunityID, true);

}

Execute Action:

Xrm.WebApi.online.execute(generateQuoteFromOpportunityReq).then(function (result) {

//Validate result

if (!isValid(result) || !isValid(result[“responseText”])) {

return;

}

else {

//get result in JSON object

var resultJson = JSON.parse(result[“responseText”]);

//Validate JSON

if (isValid(resultJson)) {

//Validating the attributes

if (!isValid(Xrm) || !isValid(Xrm.Navigation)) { return; }

//openAlertDialog

Xrm.Navigation.openAlertDialog({ confirmButtonLabel: “Ok”, text: “Quote with ID: ” + resultJson.quoteid + ” is generated successfully. ” });

}

}

}, function (error) {

throwError(functionName, error);

});

} catch (error) {

throwError(functionName, error);

}

}

On success it returns a promise object with specific attributes.

In above example we have used ‘AllColums’ property of “ColumnSet(ComplexType)” parameter. In the same way we can use ‘Columns’ parameter. We just need to set “Edm.String” as typename in getMetadata method.

Conclusion

In this blog, we have seen how we can execute action with “ColumnSet(ComplexType)” type parameter using Xrm.WebApi.online.execute in Dynamics 365 CRM V9.0.

Click2Clone-One-Click-Productivity-App-to-Copy_clone-Dynamics-365_CRM-Records

The post Execute Action with ColumnSet(ComplexType) type parameter Using Xrm.WebApi.online.execute in Dynamics 365 CRM V9.0 first appeared on Microsoft Dynamics 365 CRM Tips and Tricks.

Execute Different Web API Operations using PowerApps Portals (Preview)

$
0
0

Introduction

In the recent release, Microsoft has provided the ability using which we can perform different CRUD operations using Portals WEB API. The operations will run at server-side and are similar to Dynamics Web API Operations but the difference is in the way it is written and called in PowerApps Portals.

If you have a custom web page with a page template or web template and you want data displayed in the custom web page to be stored in Dynamics by performing some business logic then you need to use PowerApps Portals API, which will communicate with the Dynamics 365 in the backend and perform the required operation in Dynamics 365.

Let us consider a requirement where we need to record our punch in details, punch out details and if there is any incorrect entry then we need to delete that punch details. For this scenario, we will use PowerApps Portals Web API and see how we can implement the requirement.

So we will execute below four operations,

– Retrieve record
– Create record
– Update record
– Delete record

Before going directly to Web API, we need to first look at what are the configurations we need to do to allow Web API operations in PowerApps Portals.

Please check the below screenshots of the Portal Site Settings to allow Web API Operations in PowerApps Portal.

1. Create Site Setting in PowerApps Portal as below:

a. Enable the entity in PowerApps Portals

Note: new_logindetail is the logical name of the custom entity.

Execute Different WebAPI Operations using PowerApps Portals
b. Enable fields for API Operations

Execute Different WebAPI Operations using PowerApps Portals
c. Show Web API Errors in Portal

Execute Different WebAPI Operations using PowerApps Portals

Note: You need to create a Site Setting for each entity that needs to be enabled for Web API and if you want to enable all fields for Web API operations then you can use “*” or else you can specify the logical name of each field separated by a comma.

2. Create Entity Permission and Create new web role for Web API
You can navigate to Entity Permission entity directly from the navigation pane.

Execute Different WebAPI Operations using PowerApps Portals
Note: The highlighted is the custom entity used for performing Web API Operations. You can select any other entity which you want and give the privileges as shown above for the new Web Role which we will use for performing Web API Operations.

Execute Different WebAPI Operations using PowerApps Portals
Note: You can give any name to the Web Role but make sure to set Authenticated Users Role to Yes. By doing this only portal users i.e. authenticated users will able to perform Portal Web API CRUD Operations.

After our configurations are done, now we will see how we can perform different Web API operations in PowerApps Portal.

For executing Web API, Microsoft has provided a Wrapper AJAX function which we can use for executing any Web API method for any entity. Please check the below link to get and use the Wrapper AJAX function in your code.

https://docs.microsoft.com/en-us/powerapps/maker/portals/web-api-perform-operations#wrapper-ajax-function

As this is a common function which we can use for any Web API operations in the portal, so I will create a new Web Template and simply copy-paste the function code in the created Web Template as below:

AJAX Function Code Snippet:

<script>
(function(webapi, $){
function safeAjax(ajaxOptions) {
var deferredAjax = $.Deferred();

shell.getTokenDeferred().done(function (token) {
// add headers for AJAX
if (!ajaxOptions.headers) {
$.extend(ajaxOptions, {
headers: {
“__RequestVerificationToken”: token
}
});
} else {
ajaxOptions.headers[“__RequestVerificationToken”] = token;
}
$.ajax(ajaxOptions)
.done(function(data, textStatus, jqXHR) {
validateLoginSession(data, textStatus, jqXHR, deferredAjax.resolve);
}).fail(deferredAjax.reject); //AJAX
}).fail(function () {
deferredAjax.rejectWith(this, arguments); // on token failure pass the token AJAX and args
});

return deferredAjax.promise();
}
webapi.safeAjax = safeAjax;
})(window.webapi = window.webapi || {}, jQuery)
</script>

So our Wrapper AJAX template will look as seen from the below screenshot

Execute Different WebAPI Operations using PowerApps Portals

Now, whenever we want to refer to this in any other Web Template, you just need to use the below line of code:
{% include ‘Wrapper AJAX Template’ %}

Note that here I have used my newly created Web Template name i.e. ‘Wrapper Ajax Template’.

Now let us create a new page, which will be visible when the user login the portal and allows the user to punch in from the portal. Remember in the web page we will just add an HTML page using a Page template using which the user can do Punch In. Following are the details of the web page created.

Execute Different WebAPI Operations using PowerApps Portals

In order to render HTML in Web Page, I have use Web Template but you can also use Content Page of Web Page to add your custom HTML in the Web Page. I will perform all CRUD operations in the Web Template. Now let’s understand that in step by step.

1. There is a custom entity created in Dynamics to store the Login/Logout Details in CRM. First, we will retrieve Punch In details created today and if Punch In the record found then we will display that in the table in HTML.

2. We will have 3 buttons “Punch In”, “Punch Out” and “Delete” to perform the respective operations using Portals Web API.

Our final HTML will look like below,

Execute Different WebAPI Operations using PowerApps Portals

To retrieve the data from CRM, we can use normal FetchXml and display data in HTML table by looping through each punch in record if record exist already. Below is the code to retrieve and the data and display it in the HTML Table.

{% fetchxml punchdetails %}
<fetch version=”1.0″ output-format=”xml-platform” mapping=”logical” distinct=”false”>
<entity name=”new_logindetail”>
<attribute name=”new_logindetailid” />
<attribute name=”new_logouttime” />
<attribute name=”new_logintime” />
<attribute name=”createdon” />
<order attribute=”createdon” descending=”false” />
<filter type=”and”>
<condition attribute=”createdon” operator=”today” />
</filter>
</entity>
</fetch>
{% endfetchxml %}

<table>
<tr><th>Login Time</th><th>Logout Time</th><th>Date Created</th><th>Actions</th>
{% for item in punchdetails.results.entities %}
<tr>
<td>{{item.new_logintime}}</td>
<td>{{item.new_logouttime}}</td>
<td>{{item.createdon}}</td>
<td>
<button type=”button” id=”delete” onclick=”deletePunchDetails(‘{{item.new_logindetailid}}’)”>Delete</button>
<button type=”button” id=”punch_out” onclick=”updatePunchDetails(‘{{item.new_logindetailid}}’)”>Punch Out</button>
</td>
</tr>
{% endfor -%}
<tr>
<td><button type=”button” id=”punch_in” onclick=”addPunchDetails()”>Punch In</button></td>
</tr>
</table>

Below is the screenshot of the how web template will look like after adding the code. In the same way, you need to add the code in the Web Template.

Please note “punchdetails” is the name of the fetchXml variable which we need to use to retrieve the results from fetchXml. Also, to update and delete specific entry we need to add Update and Delete buttons in each row dynamically and call the respective function by passing GUID of the record.

We don’t need to add Punch In in each row as Punch In button is used to create a new record of Login/Logout Details in CRM.

Now we will see the code for each of the Web API request.

1. Create Punch In record:

function addPunchDetails()
{
webapi.safeAjax({
type: “POST”,
url: “/_api/new_logindetails”,
contentType: “application/json”,
data: JSON.stringify({
“new_logintime”: new Date(), //Date Time
“new_name”: “Login_”+new Date().toLocaleDateString(), //String
“new_loginattempts”:1, //Whole Number
“new_usertype”:2 //Option Set
“new_user@odata.bind”:”/contacts({{user.Id}})”, //Setting Logged In User(Lookup)
“new_workingday”: “2,3,4” //Multi-Select Option Set
}),
success: function (res, status, xhr) {
}
});
}

When webapi.safeAjax is executed, it calls the AJAX Wrapper class which we already added in another web template and references it in this web template.

Also, fields which I used for create request are based on my requirement but you can use different fields with different data type as well.

2. Update or Punch Out:

function updatePunchDetails(id)
{
webapi.safeAjax({
type: “PATCH”,
url: “/_api/new_logindetails(“+id+”)”,
contentType: “application/json”,
data: JSON.stringify({
“new_logouttime”: new Date()
}),
success: function (res) {
console.log(res);
}
});
}

The id parameter which we pass to this method is the GUID of the record that we pass from the loop above. Similarly, we will have to pass the parameter to DELETE method as well as below:

3. Delete Punch entry from CRM

function deletePunchDetails(id)
{
webapi.safeAjax({
type: “DELETE”,
url: “/_api/new_logindetails(“+id+”)”,
contentType: “application/json”,
success: function (res) {
console.log(res);
}
});
}

Note: Also, when you create record from portal “System” will be set as the Owner of the record.

Records created in CRM:

Execute Different Web API Operations using PowerApps Portals

Also as mentioned above, if the user don’t have permission to access page or anonymous users will not be able to see the page and hence won’t be able to perform Web API Operations as seen from the below screenshot.

For Anonymous Users:

Execute Different Web API Operations using PowerApps Portals

Note: All PowerApps Portal Web API Operations follow OData query syntax and work in the same manner as our Dynamics OData query works.

Conclusion

In this way, you can execute different Web API operations as per your requirement from PowerApps Portals.

One Pic = 1000 words! Analyze data 90% faster with visualization apps!

Get optimum visualization of Dynamics 365 CRM data with –
Kanban Board – Visualize Dynamics 365 CRM data in Kanban view by categorizing entity records in lanes and rows as per their status, priority, etc.
Map My Relationships – Map My Relationships – Visualize connections and relationships between Dynamics 365 CRM entities or related records in a Mind Map view.

The post Execute Different Web API Operations using PowerApps Portals (Preview) first appeared on Microsoft Dynamics 365 CRM Tips and Tricks.

How to Perform Basic CRUD Operations using Offline Web API in Mobile Clients

$
0
0

Dynamics 356

Introduction

Microsoft has provided offline ability to use “Dynamics 365 for phones app” or “Field Service (Dynamics 365) App”. Mobile Offline allows users to work with the data in offline mode as well i.e. when they are not connected to the internet. So, in the offline mode, if we want to create or manage the data programmatically, we need to use Microsoft Dynamics Offline Web API methods within the script.

Microsoft Dynamics Offline Web API methods can be used for basic commands while working in offline mode. The basic methods that are available for using the Xrm.WebApi.offline include the following: createRecord,  retrieveRecords, retrieveMultipleRecords, updateRecord and deleteRecord.

Note: These OfflineWebApi methods will work only for tables that are enabled for mobile offline and only basic validation will be performed on the data that is being input.

By using the below method, we can identify whether the entity is available to use in offline mode: Xrm.WebApi.offline.isAvailableOffline(entityLogicalName);

In this blog, I will show the sample codes to create, retrieve, update and delete records using Xrm.WebApi.offline methods in JavaScript.

  1. Create:

It is used to create table record. The required parameters of this function are;

    1. entityLogicalName – Logical name of the table.
    2. data – JSON object of the data to create a new record.

//This function is used to create a contact record
function createContact() {
    var objContact = null;
    try {
          //Create the Json object of contact record
          objContact = new Object();
          objContact["firstname"] = "Jenny";
          objContact["lastname"] = "Smith";
          //Call Create method
          Xrm.WebApi.offline.createRecord("contact", objContact).then(function (result) {
              Xrm.Navigation.openAlertDialog("Contact record has been created successfully.");
          },
        function (error) {
            Xrm.Navigation.openAlertDialog(error.message);
        });
    } catch (e) {
        Xrm.Navigation.openAlertDialog(e.message);
    }

  1. Update:

It is used to update table record. The required parameters of this function are;

    1. entityLogicalName – Logical name of the table.
    2. entityId – GUID of record.
    3. data – JSON object of the data to update record.

//This function is used to update a contact record
function updateContact() {
    var objContact = null;
    try {
        //Create the Json object of contact record
        objContact = new Object();
        objContact["telephone1"] = "18018015012";
        objContact["fax"] = "123456";
        objContact["parentcustomerid_account@odata.bind"] = "/accounts(08f4aca2-9793-eb11-b1ac-0022481cb79b)"
        //Call Update method
        Xrm.WebApi.offline.updateRecord("contact", "fb4231a9-dba4-eb11-b1ac-000d3a4e57c1", objContact).then(function (result) {
            Xrm.Navigation.openAlertDialog("Contact record has been updated successfully.");
        },
      function (error) {
          Xrm.Navigation.openAlertDialog(error.message);
      });
    } catch (e) {
        Xrm.Navigation.openAlertDialog(e.message);
    }
}

  1. Delete:

It is used to delete table record. The required parameters of this function are;

    1. entityLogicalName – Logical name of the table.
    2. entityId – GUID of record.

//This function is used to delete a contact record
function deleteContact() {
    try {
        //Call Delete method
        Xrm.WebApi.offline.deleteRecord("contact", "5d0111d1-bf05-4079-b695-247e4c9acac2").then(function (result) {
            Xrm.Navigation.openAlertDialog("Contact record has been deleted successfully.");
        },
      function (error) {
          Xrm.Navigation.openAlertDialog(error.message);
      });
    } catch (e) {
        Xrm.Navigation.openAlertDialog(e.message);
    }
}

  1. Retrieve:

It is used to retrieve a single record from a table. The required parameters of this function are;

  1. entityLogicalName – Logical name of the table.
  2. entityId – GUID of record.
  3. options – OData Query.

//This function is used to retrieve single contact record
function retrieveContact() {
    try {
        //Call Retrieve method
        Xrm.WebApi.offline.retrieveRecord("contact", "fb4231a9-dba4-eb11-b1ac-000d3a4e57c1", "?$select=firstname,lastname,telephone1").then(function (result) {
            Xrm.Navigation.openAlertDialog("Contact retrieved successfully - FirstName: " + result.firstname + ", LastName: " + result.lastname + " and Telephone: " + result.telephone1);
        },
      function (error) {
          Xrm.Navigation.openAlertDialog(error.message);
      });
    } catch (e) {
        Xrm.Navigation.openAlertDialog(e.message);
    }

  1. RetrieveMultiple:

It is used to retrieve multiple records from the table. The required parameters of this function are;

  1. entityLogicalName – Logical name of the table.
  2. options – we can use OData Query and FetchXML as well.

RetrieveMultiple method with OData Query

//This function is used to retrieve contact records using OData Query
function retrieveContactsWithOdata() {
    try {
        //Call Retrieve method
        Xrm.WebApi.offline.retrieveMultipleRecords("contact", "?$select=firstname,lastname,telephone1&$filter=_parentcustomerid_value ne null").then(function (result) {
            Xrm.Navigation.openAlertDialog("Length: " + result.entities.length);
        },
      function (error) {
          Xrm.Navigation.openAlertDialog(error.message);
      });
    } catch (e) {
        Xrm.Navigation.openAlertDialog(e.message);
    }
}

RetrieveMultiple method with FetchXML – To use a FetchXML, use the fetchXml attribute to specify the query.

//This function is used to retrieve contact records using Fetch XML
function retrieveContactsWithFetch() {
    var fetchXML = null;
    try {
        //Fetch XML to retrieve Contact records
        fetchXML = "<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>" +
        "<entity name='contact'>" +
          "<attribute name='fullname' />" +
          "<attribute name='telephone1' />" +
          "<attribute name='contactid' />" +
          "<order attribute='fullname' descending='false' />" +
          "<filter type='and'>" +
            "<condition attribute='parentcustomerid' operator='not-null' />" +
          "</filter>" +
        "</entity>" +
      "</fetch>";
        //Call Retrieve method
        Xrm.WebApi.offline.retrieveMultipleRecords("contact", "?fetchXml=" + fetchXML).then(function (result) {
            Xrm.Navigation.openAlertDialog("Length: " + result.entities.length);
        },
      function (error) {
          Xrm.Navigation.openAlertDialog(error.message);
      });
    } catch (e) {
        Xrm.Navigation.openAlertDialog(e.message);
    }
}

Conclusion

By using the Offline Web API methods, we can easily create and manage the table record which is available in the offline database for offline use within mobile clients i.e., “Dynamics 365 for phones app” or “Field Service (Dynamics 365) App”.

Maplytics

 

The post How to Perform Basic CRUD Operations using Offline Web API in Mobile Clients first appeared on Microsoft Dynamics 365 CRM Tips and Tricks.

Viewing all 33 articles
Browse latest View live