Replicate Dynamics 365 Workflow Timeout wait condition in Microsoft flows

Lately working on Microsoft flows these days where I am helping my customer to migrate Dynamics 365 workflows to Microsoft flow. One of the workflow was using a timeout condition with  Duration Timeout as shown in the screenshot below.

image

I needed to replicate the same in Microsoft Flows. It’s quite simple and one of the most common requirements. Hence thought of blogging this one.

Basically there are two ways. One is using the Approval Trigger where you can set the timeout.

image

However Approval conditions of Flows are meant for specific needs and hence we won’t be using this one. So what is the other way? Let’s explore then.

I put a simple requirement here to test the timeout condition.

Create an account. On create of the account the flow fires. It waits for 2 minutes and then creates a Task record and associates it with the account.”

Very simple, isn’t it. So lets see.

The first thing is I initialize the variable. The variable type is of string and value I set to 2 minutes from current time.

image

The next step is to add the Delay Until condition and make the flow wait till the current execution time is equal to the variable we set earlier.

image

I end the flow with a create record step of Dynamics 365 which creates a Task record and associates it with the account record. Simple one and I am not showing it.

And below is the result when I run the flow.

image

As you can see, the Delay step waited for 2 minutes before it moved on the next step.

Hope this helps.

Debajit Dutta

(Dynamics MVP)

For consultation/ corporate training visit www.xrmforyou.com or reach out to us at info@xrmforyou.com

Our product offerings:

Role based views for Dynamics 365 (http://www.xrmforyou.com/role-based-views.html)

CRM-Sharepoint Attachment uploader and metadata manager (http://www.xrmforyou.com/sharepoint-integrator.html)

Record Cloner for Dynamics 365 (http://www.xrmforyou.com/record-cloner.html)

Multiselect picklist for Dynamics 365 (http://www.xrmforyou.com/multi-select-picklist.html)

Advertisements

Execute Flows programmatically on-demand from anywhere in Dynamics 365

Flows are the new path on which every Dynamics 365 consultant is treading now and while you move along, you discover many new stuffs on your journey.

And  one of them is when customer walked up to me  and asked – “Flows are not realtime and they need a trigger. Can I call them through some means on demand and get the results of the flow back?”.

Well, I never did this since this requirement never popped up but I was aware that it can be done and hence said “Yes” and went back to my holy grail – “Visual studio”. Can’t put the exact requirement here but for this blog I create a simple flow and the same concepts can be applied no matter how much complex your flow is.

So here is the requirement for this blog – When an account is created, I call a flow with the created account GUID and also pass in the number of child contacts to be created. The flow takes those parameters in and creates as many contacts as defined by the input parameter to the flow and returns the created contact guid’s to the invoker.

Please understand that the purpose of this blog is not to show what u can do with flow and when you should use them or when not, but to call them programmatically on demand.

So I started creating the flow. Before I proceed let’s understand the requirement.

My flow will be invoked programmatically with some input parameters and then the flow will execute all its defined paths and send the response back to the invoker.

So basically the flow will receive a HttpRequest call with body provided by the invoker and that will be my first flow trigger. So I started.

image

Once you select the Request trigger, you should be seeing the below screenshot.

image

As you can  see, if you wish to pass some data to the Request, you need to define the Request Body JSON schema so that flow understands your input parameters and their data types.

This is very easy now. Just paste your JSON body and use the option – “Use sample payload to generate JSON schema” as highlighted above.

For this example, I would be passing two parameters in the body – the account id and  the number of child records to create. Below is the JSON I intend to pass.

{"parentRecordId": "A16B3F4B-1BE7-E611-8101-E0071B6AF231","numberOfRecords": 5}

Once I put this and use the option to generate the schema, I get the schema.

image

below is my entire flow

image

image

image

Just to summarize, I take the accountid and number of records to create  input parameters. I initialize two variables one for record counter and one for storing the created contact’s id.

The important step is the last one – “Response” step.

There in the response body I set the array variable named Responses. This will be the response which will be received by the invoker.

To invoke this I create a plugin on POST create of the account and then from there I invoke the workflow

var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

                  var outputRecordId = (Guid)context.OutputParameters["id"];

                  HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("https://prod-47.westus.logic.azure.com:443/workflows/25a5b8c4aapi-version=v=1.0&sig=ysWzgmjyNCSrUxy0KPWZlq-OvsVmVUqGalWaEnBuryY");
                   webRequest.Method = "POST";

                  webRequest.ContentType = "application/json";
           

                  var data = "{\"parentRecordId\" : \"" + outputRecordId.ToString().Trim(‘{‘, ‘}’) + "\", \"numberOfRecords\": 5}";
                  var dataContent = Encoding.UTF8.GetBytes(data);

                  using(var stream = webRequest.GetRequestStream())
                  {
                         stream.Write(dataContent, 0, dataContent.Length);
                   }

                  Stream response = ((HttpWebResponse)webRequest.GetResponse()).GetResponseStream();

                  using(var sr = new StreamReader(response))
                   {
                        // this will be a JSON array containing the list of newly created contact GUID’s
                         var result = sr.ReadToEnd();
                  }

The other part of the code are pretty simple. However the important part is authenticating with the flow. And this is achieved by taking the URL of the HTTP Request trigger from the flow.

Below is the screenshot from where you need to take this. And then create the HTTP Web Request object with this URL.

image

In the same way you can call any flow from anywhere be it client side script or server side. Your flow can be sending notifications and stuff which you can trigger programmatically using this procedure.

Hope this helps!

Debajit Dutta

(Dynamics MVP)

For consultation/ corporate training visit www.xrmforyou.com or reach out to us at info@xrmforyou.com

Our product offerings:

Role based views for Dynamics 365 (http://www.xrmforyou.com/role-based-views.html)

CRM-Sharepoint Attachment uploader and metadata manager (http://www.xrmforyou.com/sharepoint-integrator.html)

Record Cloner for Dynamics 365 (http://www.xrmforyou.com/record-cloner.html)

Multiselect picklist for Dynamics 365 (http://www.xrmforyou.com/multi-select-picklist.html)

Convert you existing text fields into Autonumber field with the new entity designer in powerapps in Dynamics 365

Well this has long been awaited for. And how many  times I had my customer walking up to me and ask – “I have an existing field. Do CRM provide Autonumber feature? Can I convert an existing text field to AutoNumber field?”.

Till this point my answer was Yes but with a suffix“but” in it.

However going forward you can with the new entity designer in power apps.

So you can select Primary Attribute Number field of your entity and covert it to AutoNumber type now.

Below I open the OOB Account Number field and set the Data Type from Text to AutoNumber.

image

Short and sweet. Isn’t it?

P.S – Only existing text fields could be converted into Auto Number Type. You can off-course create a new Auto Number Type field.

Hope this helps!

Debajit Dutta

(Dynamics MVP)

For consultation/ corporate training visit www.xrmforyou.com or reach out to us at info@xrmforyou.com

Our product offerings:

Role based views for Dynamics 365 (http://www.xrmforyou.com/role-based-views.html)

CRM-Sharepoint Attachment uploader and metadata manager (http://www.xrmforyou.com/sharepoint-integrator.html)

Record Cloner for Dynamics 365 (http://www.xrmforyou.com/record-cloner.html)

Multiselect picklist for Dynamics 365 (http://www.xrmforyou.com/multi-select-picklist.html)

Making an entity enabled to send emails in Dynamics 365 and it’s existing email fields – Gotchas!

After my last blog on canvas app and OPEN API, I would say this one is pretty basic. However time and again I keep hearing kind of similar questions based on this topic and hence I thought of penning this blog.

Well there are two questions usually that I face.

  • How do I make my custom entity email able?. In other words, how can I select my custom entity in the To, CC, BCC section of email?

  • If I have more than one email field already available before I enable this setting, which one would it take while sending email?

Well the first one is quite easy and I think majority of us know this. In case you are unware, you need to go to the Entity Settings and then enable the checkbox “Send email to Entity”

image

Well above is a view from the new powerapps admin center. In case you are still working on the old version, this is what it would look like.

image

Well you may be thinking what’s new. After all this is know. When we select this option, a new field of format  “Email” would be created and that will be used to receive emails from CRM.

Wait..but what about the second question?

Well in that case, the email field which was created first would be used for sending the email.

Small one but next time if someone pops this question, you can just steal the show by letting out this small secret.

Hope this helps!

Debajit Dutta

(Dynamics MVP)

For consultation/ corporate training visit www.xrmforyou.com or reach out to us at info@xrmforyou.com

Our product offerings:

Role based views for Dynamics 365 (http://www.xrmforyou.com/role-based-views.html)

CRM-Sharepoint Attachment uploader and metadata manager (http://www.xrmforyou.com/sharepoint-integrator.html)

Record Cloner for Dynamics 365 (http://www.xrmforyou.com/record-cloner.html)

Multiselect picklist for Dynamics 365 (http://www.xrmforyou.com/multi-select-picklist.html)

{Solved} Save Customer Signature from Pen Control in Canvas App to Dynamics 365 text field

One more customer requirement and one more blog on powerapps. And this time a really common requirement. What if you want to store customer signature in Dynamics 365 record.

For example – Imagine a product ordered online making its journey from an inventory to the hands of a customer. You can perceive how many approval signature it may require before the end consumer finally signs this off as received. What if you are needed to store all the signatures in a single record? An obvious solution comes is we will store the base64 encoding of the image in multi-line text field. And we can have multiple multi-line textbox to store signatures from various approvers.

While the solution is easy, like in many cases the implementation is not. And the primary reason is because of the format of the image of which Pen Input control provides, which is used to capture signature in Canvas app.

Lets start with the problem first. If you check for the PenInput.Image property, you would find that it gives the result in this format – “appres://blobmanager/bfd46aab08b948de948102838e58e3c8/20”

The numbers will be randomized but this is the format and as you understand it’s of no use to us.

What is the other option. Say you have just one signature to store and you plan to map it directly to the image field of the record, it won’t work as well. If you do that, you would not get any error. But it would always render a black content, something like below. Also it’s not an option since there is only one image field you can create for an entity and hence can’t store multiple signatures.

image

So I started digging and digging and more digging. Finally came up with a solution which would be perfect fit for our beloved D365.

Step : 1 Build the Power App screen to capture signature.

Well I am leaving it to the fact that you already know to build a canvas app. And considering you know this, this is what the edit screen would look like mostly. You may have many controls. I have kept it to one. Also I will take the update scenario because doing this I can show you how to pass the record id as well. We will get to it later.

image

Step 2: Build a Microsoft flow

What i realized is to do this, I need to connect my canvas app with a flow and  then post the content of the app to the flow. Here I basically need to pass two parameters to the flow

  • The Image content of the Pen control or the customer signature
  • Guid of the record to be updated.
  • Any other fields that you want to update.

For me, since I have no other fields on the form, it is just the first two parameters.

I go to my canvas app and then select flows.

image

In the flows, since I would be posting the contents from my canvas app to the flow, I start with Request connector.

image

image

I am assuming canvas app is sending the content of the image in body and then may be the record id as query parameter.

So I need to take them in two separate variables in the Flow. So the next I use the Initialize Variable condition.

Below shows setting the variable “Content” to the image content sent from Power Apps.

Capture

Basically I am taking the body content from the HttpRequest and assigning it to the local parameter “Content”. Since I am parsing the body, hence in the expression I have used

“triggerBody().$content”

Also note that I have used decodeBase64 function. The  reason for that and is then the content body comes over from the HTTPTrigger, it seems to be double encoded base64 string. However when we need to put in CRM, we need just single encoding of the binary to base64. Found it the hard way though :). Making sure it’s not hard for you.

My final expression for content

“decodeBase64(triggerBody().$content)”

The next stuff that I need to do is pass the get the record id from the request and assign it to a variable

image

Above I assign the variable “RecordId” to the expression –

triggerOutputs().queries.recordid

All this may sound too over the top but believe me it will all make more sense once we bring all the pieces together. As of now just understand that the canvas app passed the signature and recorid and you just took back in the flow for further processing.

And the final step is use the Dynamics 365 update action to update the record. Here I have taken the account entity and I am going to save the signature from the canvas app to the description field of the account which is multi-line.

I set the Record Id to be updated.

image

And then our holy grail field, the description.

Capture1

And here is the expression to set it. Notice the use of replace function to replace double quotes. This is because sometimes the content may come up with leading and trailing double quotes

concat('data:image/png;base64,', replace(variables('Content'),'"',''))

All set and done. The next step is to connect the connector to connect the canvas app to the flow.

Step 3: Build a Connector

Well this I found really hard to do. And my whole intention is that you don’t face obstacles like I faced. The connector will basically be used to connect the canvas app to the Microsoft flow.

I go ahead and create a custom connector. Follow the screenshots below.

image

image

There are multiple options you get to create a connector but what we will do here is use the option = “Import an OpenAPI file”.

image

But wait, where do I have the file. I need to create an OpenAPI file right.

If you remember correctly, the first flow step was a HTTP step and it expects a certain protocol when it is being invoked. So why not get the URL that the HTTP is expecting. If we re-open our Microsoft flow then copy the request URL, then it would be something like this.

image

https://prod-82.westus.logic.azure.com:443/workflows/bff4ca2dbe0049f7bf5474b54710b96b/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=bVg0NQ9QteaQFQehWqkDmjiz8vQNSZUHMFUwWaEQ2QE

If you see the URL properly, then there are four parameters in the query

  • api-version
  • sv
  • sig
  • sp

So our open API schema should take mention of these four parameters. But how does we create the OPEN API file.

If you search the internet you will get a website link to do the same –

“http://specgen.apistudio.io”.

It’s indeed a wonderful website where if you put the URL it would get everything working for you (not everything but well almost).

Well I was not that lucky though. For entire 2 days or so, the site seemed to be down.

image

It was nightmare to learn and search and put everything up. But somehow I managed. To keep this post short, here is the JSON file content which I uploaded as a separate link.

https://debajmecrm.com/2019/03/16/open-api-sample-json/

Some important parameters which I have highlighted and explained below.

  • title : This is the name with which the connector appears in the canvas app.
  • operationId: the name of the function which will be invoked from canvas app.
  • api-version, sp, sig and sv which are basically the query string parameters and the values you need to take from your URL which I have explained earlier. If you observe carefully, there is one attribute “x-ms-visibility”: “internal which basically specifies that the canvas app does not need to pass this value when invoking the flow. It would be set internally.
  • Couple of more parameters – recordid and file which needs to be passed from canvas app. The file is of type formData which is basically a internal data type to support file content.

I hope I was able to explain most of the stuffs. After replacing the URLs and the parameters with the values from your environment, save it and upload the JSON file.

And finally create the connector

image

All set and done. Now the next step is to set-up this connector in  canvas apps.

Step 4: Set the connector up in canvas app.

Select your canvas app screen where you have put the pen control and then select new Data source.

image

Search for your custom connector. It would appear. Select and Add.

image

And finally wiring up the event

image

As you can see I am passing the record id through BrowseGallery1.Selected.Account. You may need to pass the recordid in some other way depending on how you arrived at the screen. I am passing “application/json” as the content-type parameter.

And now once you run your canvas app and then check your CRM, you see this in your description field.

image

Nirvana! And guess what, feels wonderful to put a smile on the face of the customer. And before I wind up, you might be wondering how did I come to the correct expressions while setting the variables Content and RecordId.

Once I execute the flow from PowerApps, below the output body I got.

image

Hope this helps!

Debajit Dutta

(Dynamics MVP)

For consultation/ corporate training visit www.xrmforyou.com or reach out to us at info@xrmforyou.com

Our product offerings:

Role based views for Dynamics 365 (http://www.xrmforyou.com/role-based-views.html)

CRM-Sharepoint Attachment uploader and metadata manager (http://www.xrmforyou.com/sharepoint-integrator.html)

Record Cloner for Dynamics 365 (http://www.xrmforyou.com/record-cloner.html)

Multiselect picklist for Dynamics 365 (http://www.xrmforyou.com/multi-select-picklist.html)

OPEN API sample JSON

This post is being referred from: https://debajmecrm.com/2019/03/16/solved-save-customer-signature-from-a-canvas-app-in-dynamics-365-multiline-text-field/

The explanation of the highlighted parts of is explained in the parent link.

{
    "swagger": "2.0",
    "info": {
        "description": "API to save signature as base64",
        "version": "1.0.0",
        "title": "UpdateSignaturetoAccount",
        "termsOfService": "https://<your domain for http trigger>.westus.logic.azure.com/terms-of-service",
        "contact": {
            "name": "Debajit Dutta",
            "url": "http://www.xrmforyou.com",
            "email": "debajit.dutta@xrmforyou.com"
        }
    },
    "host": "<your domain for http trigger>.westus.logic.azure.com:443",
    "basePath": "/workflows",
    "schemes": [
        "https"
    ],
    "consumes": [],
    "produces": [],
    "paths": {
        "/06781ec9396c44b0810abf56c7511c73/triggers/manual/paths/invoke": {
            "post": {
                "summary": "Save signature to Dynamics 365",
                "operationId": "SignatureToFlow",
                "produces": [
                    "application/json"
                ],
                "responses": {
                    "202": {
                        "description": "Accepted"
                    }
                },
                "parameters": [
                    {
                        "name": "content-type",
                        "in": "header",
                        "description": "",
                        "type": "string",
                        "required": true
                    },
                    {
                        "name": "api-version",
                        "in": "query",
                        "type": "string",
                        "default": "2016-06-01",
                        "description": "",
                        "required": true,
                        "x-ms-visibility": "internal"
                    },
                    {
                        "name": "sp",
                        "in": "query",
                        "type": "string",
                        "default": "/triggers/manual/run",
                        "description": "",
                        "required": true,
                        "x-ms-visibility": "internal"
                    },
                    {
                        "name": "sv",
                        "in": "query",
                        "type": "string",
                        "default": "1.0",
                        "description": "",
                        "required": true,
                        "x-ms-visibility": "internal"
                    },
                    {
                        "name": "sig",
                        "in": "query",
                        "type": "string",
                        "default": "jmdbo2bnxDHQtc7AfPESsEBWA_QXBD_Cm4_-qK6zg_U",
                        "description": "",
                        "required": true,
                        "x-ms-visibility": "internal"
                    },
                    {
                        "name": "recordid",
                        "in": "query",
                        "type": "string",
                        "description": "",
                        "required": true
                    },
                    {
                        "name": "content",
                        "in": "body",
                        "schema": {
                            "type": "string",
                            "format":  "byte"
                        },
                        "description": "Signature to upload.",
                        "required": true
                    }
                ]
            }
        }
    },
    "definitions": {},
    "parameters": {},
    "responses": {},
    "securityDefinitions": {},
    "security": [],
    "tags": []
}

Hacking your way to Execute a CRM workflow programmatically from anywhere in Dynamics 365 portals

Before I even proceed further, couple of things. You might be thinking calling On-Demand workflows can be so sweetly done from entity list and entity forms just using configuration. Then why the hell  we need to hack?

Well I am aware of that wonderful feature but this post is not about that. You can call an on-demand workflow from entity form and entity list but again, we need an entity form or list right?

What if your customer has spun up some custom buttons on the fly using script and click of the buttons they want to perform some server side operations? What if the area may be an entity form or entity list and just some other area of the portal like a registration page or something like that?

Well my customer had a similar sort of requirement. And sometimes no matter how much you try, you may need to give in to the customer demands.

Please understand that I have hacked around the platform code a bit to get this working. It may continue working in the future or may stop if some changes in the platform and I have put a caveat for my customer already. However if you are in dire straits like me, may be you can do this but make sure you put a caveat to your customer.

I guess half of the readers have left after those big red comments. However if you are still reading, may be you would like to continue till the end.

So I created a workflow for account entity which does something mundane – “Create a Task record”.

image

Now I want to call this workflow from anywhere and not just an entity list record or entity form. Well if that the case below the code to execute this workflow. I have put it inside the function executeCustomWorkflow which you can call from anywhere in portals and it just works.

function executeCustomWorkflow() {
    debugger;
    var u = "/_services/execute-workflow/7b138792-1090-45b6-9241-8f8d96d8c372"; // execute workflow request url

    var params = {};
    var workflow = {};

    workflow.LogicalName = "workflow";
    workflow.Id = "43459d81-1cfe-4465-b9ed-e756d00adb69"; // guid of the workflow you wish to execute. This will be consistent across your environments

    var data = {};
    data.LogicalName = "account";
    data.Id = "b5233ccc-8540-e911-a837-000d3a11e59b"; // guid of the account record.

    params.workflow = workflow;
    params.entity = data;

    var jData = JSON.stringify(params);

    // calling the platform method. bascially you can do your own promise and invoke the execute workflow url.
    shell.ajaxSafePost({  
        type: "POST",
         contentType: "application/json",
        url: u,
        data: jData
    }).done(function (r) {
        debugger;
         }).fail(function (n) {
            debugger;
    });
}

I have put appropriate comments wherever required so that you can understand it. Now this function can be bound to button click or any other event and it will work.

But as I always try, I would not leave you in the dark. You may be wondering, how did I get the Workflow execute request URL? If you configure a workflow button for entity form and see it’s HTML, you will find the URL right up there in the mark-up.

image

What power does it give you then? Well it opens up loads of things and also addresses the perennial problem of performing CRUD operations from custom buttons from anywhere in the portal on-demand.

All you end is an entity on which the workflow would be called. And you can spin up just a dummy entity for invocation purpose and do the rest in workflow.

Hope this helps!

Debajit Dutta

(Dynamics MVP)

For consultation/ corporate training visit www.xrmforyou.com or reach out to us at info@xrmforyou.com

Our product offerings:

Role based views for Dynamics 365 (http://www.xrmforyou.com/role-based-views.html)

CRM-Sharepoint Attachment uploader and metadata manager (http://www.xrmforyou.com/sharepoint-integrator.html)

Record Cloner for Dynamics 365 (http://www.xrmforyou.com/record-cloner.html)

Multiselect picklist for Dynamics 365 (http://www.xrmforyou.com/multi-select-picklist.html)