Showing posts with label Dynamics 365. Show all posts
Showing posts with label Dynamics 365. Show all posts

Friday, December 30, 2022

Dynamics 365 Process Workflow Trigger Conditions

Hello Friends,

Welcome back with another post on Dynamics 365. Today, we will learn about the conditions upon which a Processes >> Workflow can be triggered in Dynamics 365.

Automatic Trigger:

Basically, there are 5 options upon which a Processes >> Workflow can be set to trigger automatically. These are-

  1. Record is created-
    1. If selected, then the workflow will trigger automatically when a new record is created. It always triggers AFTER the creation of record.
  2. Record status changes-
    1. If selected, then the workflow will trigger automatically when the Status field of an existing record change its value. It can be set to execute either BEFORE the changes or AFTER the changes of Status field. For example, Opportunity status changes to Won, Lost, Close.
  3. Record is assigned-
    1. If selected, then the workflow will trigger automatically when you Change the Ownership of a record. It can be set to execute either BEFORE the changes applied or AFTER the changes applied.
    2. Remember, if you are creating a record for someone else means you are already setting someone else as owner while creating the record, it means you are assigning the record to someone else automatically. This is different case and workflow will not trigger in this case.
  4. Record fields change-
    1. If selected, it further asks to choose the field(s) you wish to get the workflow triggered upon their value change. You can pick more than one fields. The workflow will trigger automatically when you Change value of a field (selected during setup) of a record. It can be set to execute either BEFORE the changes applied or AFTER the changes applied.
  5. Record is deleted-
    1. If selected, then the workflow will trigger automatically when a record is deleted. It always triggers BEFORE the creation of record.

On-Demand Trigger:

Apart from automatic trigger, Dynamics 365 Processes >> Workflows can be triggered On-Demand. These are of 2 types.
  1. As an on-demand process-
    1. If selected, it starts reflecting on record page under Flow >> Run Workflow. You may select and run the workflow.
    2. On-Demand workflow can offer bulk function to help eliminate tedious tasks from your workday.
  2. As a child process-
    1. If selected, it can be further associated with another workflow to get executed. When we click on "Add Step" during creation of workflow steps, we found a step "Start Child Workflow", workflow marked "As a child process" can be associated here.

Dynamics 365 Processes > >Workflows can be triggered in two mode-
  1. Synchronous
  2. Asynchronous

Dynamics 365 Processes > >Workflows can be triggered under two type of ownerships-
  1. The owner of the workflow
  2. The user who made the changes to the record

Dynamics 365 Processes > >Workflows supports 4 type of scopes-
  1. User
  2. Business Unit
  3. Parent: Child Business Unit
  4. Organization

Related Articles:
Disclaimer: This post is for personal use only.

    Thursday, December 29, 2022

    Power Automate Flow vs Dynamics 365 Flow

    Hello Friends,

    Welcome back with another post. Today, we will discuss a very important comparison which is usually asked during interviews. It's a comparison between-

    1. Microsoft Power Automate Flow
    2. Microsoft Dynamics 365 Workflow
    Let's see the advantages & disadvantages-

    Advantages of Power Automate Flow-
    1. Power Automate Flows can work with various web-based applications / services. For example - SharePoint, Dataverse, Twitter, Gmail, SQL.
    2. Power Automate provide 600+ built-in connectors and custom connectors to connect with various apps / services. For example-
      1. You can create a record in CRM based upon a tweet posted in Twitter.
      2. You can create a case in CRM based upon an email received on Gmail.
      3. You can send notification in Microsoft Teams to notify users when an opportunity is created, or a case is created.
    3. Power Automate Flows facilitates to perform CRUD operations upon data.
    4. Power Automate provides pre-built templates to create the flow.

    Advantages of Dynamics 365 Workflow-
    1. Dynamics 365 Workflows can be synchronous as well as asynchronous.
    2. Dynamics 365 Workflows are faster than Power Automate Flows.

    Additional Comparision:

    Feature (Capability) Power Automate Flow Dynamics 365 Flow
    Conditional Branching (Modeling) Yes Yes
    Dynamics Content (Composition) Yes Yes
    Trigger on Field Changes (Execution) Yes Yes
    Trigger Conditionally on Field Values (Execution)
    (e.g., On a Certain Date in a Date Field)
    No No
    Run On-Demand (Execution) Yes Yes
    Run-as Scopes (Execution)
    (e.g., Organization, Business Unit, User)
    Yes Yes
    Auditing (History) Yes Yes
    Solution Support (Authoring & Portability) Yes Yes


    Feature (Capability) Power Automate Flow Dynamics 365 Flow
    Looping (Modeling) Yes No
    Wait Conditions on Fields (Modeling) No Yes
    Parallel Branch (Modeling) Yes No
    OOB Connectors to External Systems (Modeling) Yes No
    Access To Pre-Image of Event Data (Composition) No Yes
    Run Child Workflows (Composition) No Yes
    Run CDS Actions Including Custom (Composition) No Yes
    Run Custom Workflow Activities (Composition) No Yes
    Group Steps to Run in a Transaction (Composition) Yes No
    Approval Workflows (Composition) Yes No
    Trigger on Multiple CDS Entity Events (Execution) No Yes
    Run on a Schedule (Execution) Yes No
    Run Synchronously (Execution) No Yes
    Run Analytics (History) Yes No
    Modern Designer (Authoring & Portability) Yes No
    AI Assisted Authoring (Authoring & Portability) Yes No

    Related Articles:
    Disclaimer: This post is for personal use only.

    Thursday, February 10, 2022

    Migration Steps

    Hello Friends,

    Welcome back with another post. Today, we will discuss about the steps that needs to be followed during any migration. Let's see-

    1. Evaluate
      1. This is the primary step or a Pre Migration Step.Here, we evaluate the intent of migration and define a scope for the data that needs to be migrated. It includes-
        1. Data Source
        2. Data Types
        3. Quantify Packages
    2. Plan
      1. This the stage where we define the strategy for data migration. It includes-
        1. Plan migration strategy
        2. Plan downtime
        3. Master data source identification
        4. Plan the data cleaning
        5. Destination data source identification
        6. Plan the data verification
    3. Extract
      1. This is the stage where we define and perform the data extraction from data source(s). Normally, we use Intermediate database (Staging Database) here. It includes-
        1. Creating packages to extract
        2. Simplify data at source or at intermediate database
    4. Clean
      1. This is the stage where we cleanup the data before loading to the actual data base. Cleaning is a continuous process. We can perform this process in parallel to other steps as well and at stage. It includes-
        1. Identify & Remove duplicate data
        2. Remove Garbage data
    5. Load
      1. This is the stage where actual process of loading the data into production database is performed. This stage is very crucial and needs extensive planning. We need to ensure that the stage should have a minimal impact upon users as well as upon business continuity. It includes-
        1. Loading small set of data
        2. Ensure everything is OK
        3. Push rest of the data
        4. Process can be done in using iterative approach
    6. Verify
      1. This is the final stage of migration or a Post Migration Step. Verification of migrated data is also crucial and a continuous process. It is better to include a Business Application Data Expert to validate the data at different stages. Validation is required-
        1. When data is extracted to ensure all the requisite data is accounted for
        2. When cleanup is done to ensure relevant data is not removed
        3. When data is loaded to ensure all data is loaded in correct and accurate manner



    With this, I am concluding this post.
    Happy Coding !!!
    Will see you again with some new topics.

    Stay Safe !
    Stay Healthy !

    Monday, January 31, 2022

    Dynamics 365: CRUD Operations-6 (Delete Item)

    Hello Friends,

    Welcome back with another post on Dynamics 365. This post is the 6th part of CRUD operations.

    In last post, we have created an item in Account Entity.

    Dynamics 365: CRUD Operations-1 (Basic Preparations)

    Dynamics 365: CRUD Operations-2 (Retrieve All Items)

    Dynamics 365: CRUD Operations-3 (Create Item)

    Dynamics 365: CRUD Operations-4 (Read Item)

    Dynamics 365: CRUD Operations-5 (Update Item)

    Now, we will learn about how to delete an individual item from D365 >> Account entity. 

    1. Below is the complete HTML. This HTML includes code of previous post as well. You may copy/paste this entire HTML.
    2. <html>
          <head></head>
          <body onfocusout="parent.setEmailRange();" style="overflow-wrap: break-word;">
              <meta charset="UTF-8">
              <link rel="stylesheet" href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-js/1.4.0/css/fabric.min.css">
              <link rel="stylesheet" href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-js/1.4.0/css/fabric.components.min.css">
              <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
              <link href="https://unpkg.com/bootstrap-table@1.18.1/dist/bootstrap-table.min.css" rel="stylesheet">
              
              <script src="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-js/1.4.0/js/fabric.min.js"></script>
              <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
              <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
              <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>  
              <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
              <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
              <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
              <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
              <script src="https://unpkg.com/bootstrap-table@1.16.0/dist/bootstrap-table.min.js"></script>
              <script src="https://unpkg.com/tableexport.jquery.plugin/tableExport.min.js"></script>
              <style type="text/css">
                  .footer {
                      position: fixed;
                      bottom: 0;
                      right: 0;
                      padding-bottom: 10px;
                      padding-right: 10px;
                  }
          
                  .footerButton {
                      width: 150px;
                  }
              </style>
              <div>
                  <table id="tblCreateRecord" style="width: 100%;">
                      <tr>
                          <td style="width: 50%;">Account Name</td>
                          <td style="width: 5%;">:</td>
                          <td style="width: 45%;"><input type="text" id="txtAccountName"></td>
                      </tr>
                      <tr>
                          <td style="width: 50%;">Primary Contact Person (ID)</td>
                          <td style="width: 5%;">:</td>
                          <td style="width: 45%;"><input type="text" id="txtPrimaryContactPersonID"></td>
                      </tr>
                      <tr>
                          <td style="width: 50%;">Account Category Code (Preferred Customer-1 / Standard-2)</td>
                          <td style="width: 5%;">:</td>
                          <td style="width: 45%;"><input type="text" id="txtAccountCategoryCode"></td>
                      </tr>
                      <tr>
                          <td style="width: 50%;">Annual Revenue</td>
                          <td style="width: 5%;">:</td>
                          <td style="width: 45%;"><input type="text" id="txtAnnualRevenue"></td>
                      </tr>
                      <tr>
                          <td style="width: 50%;">Primary Phone</td>
                          <td style="width: 5%;">:</td>
                          <td style="width: 45%;"><input type="text" id="txtPrimaryPhone"></td>
                      </tr>
                      <tr>
                          <td colspan="3">
                              <input type="button" onclick="fnCreateRecord();return false;" value="Create Record"/>
                              <input type="button" onclick="fnUpdateRecord();return false;" value="Update Record"/>
                              <input type="button" onclick="fnDeleteRecord();return false;" value="Delete Record"/>
                          </td>
                      </tr>
                      
                  </table>
              </div>
              <div>
                  <table id="table" data-search="true" data-header-style="headerStyle" data-page-size="25">
                      <thead>
                          <tr>
                              <th data-field="id" data-visible="false" data-checkbox="true">Id</th>
                              <th data-field="name" data-sortable="true">Full Name</th>
                              <th data-field="mainphone" data-sortable="true">Main Phone</th>
                              <th data-field="primaryemail" data-sortable="true">EMail (Primary)</th>
                              <th data-field="primarycontact" data-sortable="true">Primary Contact</th>
                              <th data-field="primarycontactname" data-sortable="true">Primary Contact Name</th>
                              <th data-field="readitem" data-sortable="false">Read</th>
                          </tr>
                      </thead>
                  </table>
              </div>
          </body>
          <script type="text/javascript">
              var vrAccountID = 0;
              $(document).ready(function(){
                  fnGetAllAccounts();
              });
              function fnGetAllAccounts() 
              {
                  //var query = '?$select=accountcategorycode,address1_addressid,address1_longitude,donotphone,name,_primarycontactid_value,revenue';
                  var query = '?$select=accountid,name,telephone1,emailaddress1,_primarycontactid_value';
                  window.parent.Xrm.WebApi.online.retrieveMultipleRecords("account", query).then(
                  function success(accounts) 
                  {
                      var results = accounts.entities;
                      var accountRecords = [];  
                      results.forEach(function (result, index, array) 
                      {
                          var accountid = result["accountid"];
                          var name = result["name"];
                          var telephone = result["telephone1"];
                          var emailaddress = result["emailaddress1"];
                          var primarycontactid = result["_primarycontactid_value"];
                          var primarycontactname = result["_primarycontactid_value@OData.Community.Display.V1.FormattedValue"];
                          
                          var accountRecord = {};  
                          accountRecord =  
                          {  
                              'id': accountid,
                              'name': name,
                              'account': accountid,
                              'mainphone': telephone,
                              'primaryemail':emailaddress,
                              'primarycontact':primarycontactid,
                              'primarycontactname':primarycontactname,
                              'readitem':'<a href="javascript:void(0);" onclick="fnReadRecord(\'' + accountid + '\');return false;">Read</a>'
                          }  
                          accountRecords.push(accountRecord);  
                      });
                      $('#table').bootstrapTable({ data: accountRecords });  
                  },
                  function (error) {
                      console.log(error.message);
                      reject(Error(error.message));
                  });
              }
      
              function fnCreateRecord()
              {
                  var entityData =
                  {
                      "name": $('#txtAccountName').val(),
                      "primarycontactid@odata.bind": "/contacts(" + $('#txtPrimaryContactPersonID').val() + ")", //--- Lookup --- Display Text = Primary Contact
                      "accountcategorycode": $('#txtAccountCategoryCode').val(),     // Option Set --- Display Text = Category
                      "revenue": parseFloat($('#txtAnnualRevenue').val()),        // Currency (money type) ---Display Text = Annual Revenue
                      "telephone1":$('#txtPrimaryPhone').val()
                  }
                  window.parent.Xrm.WebApi.createRecord("account", entityData).then(
                      function success(result) {
                          //Success - No Return Data
                          alert("Account created successfully.");
                      },
                      function (error) {
                          alert(error.message);
                      }
                  );
              }
      
              function fnReadRecord(accountID)
              {
                  vrAccountID = accountID;
                  //var query = '?$select=accountcategorycode,address1_addressid,address1_longitude,donotphone,name,_primarycontactid_value,revenue';
                  var query = '?$select=accountid,name,accountcategorycode,revenue,telephone1,_primarycontactid_value';
                  window.parent.Xrm.WebApi.online.retrieveRecord("account",accountID, query).then(
                  function success(result) 
                  {debugger;
                      if(result != null)
                      {
                          $('#txtAccountName').val(result["name"]);
                          $('#txtPrimaryContactPersonID').val(result["_primarycontactid_value"]);
                          $('#txtAccountCategoryCode').val(result["accountcategorycode"]);
                          $('#txtAnnualRevenue').val(result["revenue"]);
                          $('#txtPrimaryPhone').val(result["telephone1"]);
                      }
                  },
                  function (error) {
                      console.log(error.message);
                      reject(Error(error.message));
                  });
              }
      
              function fnUpdateRecord()
              {
                  var entityData =
                  {
                      "name": $('#txtAccountName').val(),
                      "primarycontactid@odata.bind": "/contacts(" + $('#txtPrimaryContactPersonID').val() + ")", //--- Lookup --- Display Text = Primary Contact
                      "accountcategorycode": $('#txtAccountCategoryCode').val(),     // Option Set --- Display Text = Category
                      "revenue": parseFloat($('#txtAnnualRevenue').val()),        // Currency (money type) ---Display Text = Annual Revenue
                      "telephone1":$('#txtPrimaryPhone').val()
                  }
      
                  window.parent.Xrm.WebApi.updateRecord("account", vrAccountID, entityData).then(
                      function success(result) {
                          alert("Account updated successfully.");
                      },
                      function (error) {
                          // handle error conditions
                          console.log(error.message);
                          reject(error.message);
                      }
                  );
              }
      
              function fnDeleteRecord()
              {
                  window.parent.Xrm.WebApi.deleteRecord("account", vrAccountID).then(
                      function success(result) {
                          alert("Account deleted successfully.");
                      },
                      function (error) {
                          console.log(error.message);
                          // handle error conditions
                      }
                  ); 
              }
          </script>
      </html>
      
    3. You need to copy/paste this HTML in Web Resource file we discussed in previous post.
    4. Save the Web Resource file and then publish it. Now refresh the D365 page (Ctrl + F5).
    5. Now, check it.
    6. First load the page and click on Read button for any record, you wish to delete.
    7. Now, click on Delete Record button. It will delete the record and prompts the message.
    8. Now, refresh the page or open the Account entity list form.
    9. The entity record has been deleted.
    10. This way, you can delete the individual record itself.
    11. The API used is:-
      1. window.parent.Xrm.WebApi.deleteRecord
    12. With this post, this series comes to an end. This is how, you can perform CRUD operations in D365.
    With this, I am concluding this post.
    Happy Coding !!!
    Will see you again with some new topics.

    Stay Safe !
    Stay Healthy !