{Solved} Save Customer signature from a canvas app in Dynamics 365 Multiline Text field

This is indeed my first blog in powerapps and guess what – one of the topics which I think is required for so many real time requirements as well as an interesting one.

First of all, we all know that a multi-line of text field can be rendered as a pen input control and it can be easily rendered as a signature control. Unfortunately its not so easy if you plan to save some customer signature as a base64 string in multiline text field. In this entire blog I am assuming you know how to build a canvas app using power apps and also is familiar with the pen control.

So lets start with the problem first. If you try to save the pen input image directly in the description field of the power apps, it won’t save as base64 of the image. It would render as //blobmanager/526…..

I  am not rendering the whole content but its kind of no use.

What is the other option. The other option I tried out is to map this image to the default image field of the entity to see if it directly matches. Surprisingly not even that works.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.

image

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”

expression.

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.

image

And here is the expression to set it.

concat(‘data:image/png;base64,’,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)

Advertisements

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": "SignatureDemo",
    "termsOfService": "
https://prod-82.westus.logic.azure.com/terms-of-service",
    "contact": {
      "name": "Debajit Dutta",
      "url": "
http://www.xrmforyou.com",
      "email": "debajit.dutta@xrmforyou.com"
    }
  },
  "host": "prod-82.westus.logic.azure.com:443",
  "basePath": "/workflows",
  "schemes": [
    "https"
  ],
  "consumes": [],
  "produces": [],
  "paths": {
    "/bff4ca2dbe0049f7bf5474b54710b96b/triggers/manual/paths/invoke": {
      "post": {
        "summary": "Save signature to Dynamics 365",
         "operationId": "SendSignatureToFlow",
        "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": "bVg0NQ9QteaQFQehWqkDmjiz8vQNSZUHMFUwWaEQ2QE",
            "description": "",
            "required": true,
            "x-ms-visibility": "internal"
          },
          {
            "name": "recordid",
            "in": "query",
            "type": "string",
            "description": "",
            "required": true
          },
          {
            "name": "file",
             "in": "formData",

            "type": "file",
             "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)

Add Metadata to your Notes and Attachments in Dynamics–Notes Metadata Manager from XrmForYou.com

It gives me great pleasure to announce the new CRM add-on from XrmForYou stable – Notes Metadata Manager utility from XrmForYou stable.

Well Notes (Annotations) have existed in CRM since pre-historic times. And perhaps one of the most widely used feature in Dynamics till date since its inception. After all it gives a nice way to store your documents along with some notes and description which can be read by CRM users.

However with my many years in consulting, I realized the pain points of customers using Notes as well.

  • Can I add new fields in my notes entity (Annotation) to capture some extra information along with Note Title and Note Description?
  • Can I put notes are separate from my timeline control? May be in a separate tab?
  • Can I drag and drop documents in Notes section so that it will automatically upload?
  • Can I create more than one Note record at a time with attachments?

We have progressed leaps and bounds but even with the latest version the answer to most of the questions above is “NO”. Also traditionally since inception, Notes entity was not customizable to add new fields and users were just limited to using only two field “Note Title” and “Note Description”.

For trial and pricing, write to us at info@xrmforyou.com

Well, we have understood the pain and hence we have released this Add-On for you.

Step 1: Configuration

It comes as a Managed solution. Once you install the managed solution and open up the solution configuration page, you get a screen like one below.

image

The top section is the license information which will be provided by our team.

The section below that shows all the entities which have been enabled for Notes. This is the area where you can configure additional metadata for your Notes records corresponding to each entity.

I click on Account entity and the existing metadata account shows up as shown below.

image

You can create up to a maximum of 10 additional metadata records as per the current release of the tool. The metadata currently supported are of type text and optionset.

image

Above is the way to create a text metadata. Also you can make the additional metadata mandatory to be entered during record creation by setting the Required? field to checked.

Below is the way to create an optionset metadata for your note record.

image

As you can see from above you can configure any global option set and map your Optionset Metadata with that global optionset for the list of possible values.

You save your metadata and that’s all from the Configuration Page.

Step 2: Setting it up on your form

The next step is setting up the custom notes control on the form.To do that you just need to include the custom web resource that comes with our solution on the form where you want to show the control. Detail on the web resource control follows in our actual documentation on our website. www.xrmforyou.com

Once the webresouce is inserted on the form, this is how it looks as shown below. Below are the screenshots in the Unified Interface environment.

image

Inline editing of Note title, Description and metadata.

image

Inline new record creation:

image

Inline search

image

Attachment Upload

image

Bulk Upload

image

Drag & Drop

image

For trial and pricing, write to us at info@xrmforyou.com

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)

{Quick tip} Why is my Interactive Dashboard not showing up in Unified Apps.

Well this is very basic to say the least. But still sometimes in our regular day-day work we tend to miss out on one of the small steps and that eats into our precious time. If you already know this, there is no point in continuing with this blog. However if you are stuck in the same problem, may be this helps you out of peril.

A consultant walks up to me and informs that he has created a Single steam Interactive Dashboard but it is not showing in the Customer Service Hub or for that matter any other Unified Apps.

So before I actually walked to his desk, confirmed with few check lists.

  • Published the Dashboard –> Yes
  • Make sure it’s visible to everyone –> Yes
  • Re-opened your customer service hub application in browser? Sometimes cache is an issue –> Yes.

Yes to all basic verifications. No option but to walk up and verify and indeed the Dashboard is not showing up.

And finally the ingenious question which I could only think of – Did you include this Dashboard in your APP? The answer came – NO

So here it is guys, unlike class Web interface, to make a dashboard appear in Unified interface, you need to add it to the Dashboard’s list of your APP. A unified APP is basically shown with the components you pick and choose.

  • Open your solution
  • In Model driven apps, add the APPS where your want to show the Dashboard.

image

  • Open the APP and in the Dashboards area, select your Dashboard from the Interactive Dashbaords section. Please note the procedure for classic dashboards is same.

image   image

And voila! you are done.

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)

Dynamics 365 Portal Authentication with Azure AD B2B Guest User.

Azure AD B2B has been a boon for organizations working with partners for its various applications without losing control on corporate data. The capability of adding guest users and assigning them application is something which opens up a horizon on single sign on of enterprise applications. For details on Azure AD B2B, please visit this link – https://docs.microsoft.com/en-us/azure/active-directory/b2b/what-is-b2b

Now suppose you have users from your partner organization whom you want to access your Portals. You do not want them to set-up as a Member user in your active directory. Rather you want to set them up as a guest user and assign them to the portal. But how to do it. So let’s follow the steps

Step 1: Set-up your guest user

Login to your portal : https://portal.azure.com

Go to your Azure Active Directory and then Users and click on “New Guest User”

image     image

I enter the user email address. Here I entered it as my personal email – debajit.dutta@xrmforyou.com which is different from my Azure domain xrmforyou73.onmicrosoft.com. In real life scenarios this will be the email address of your partner organization.

image

Once you send the invite, the partner will receive an invitation email. Sample below. Once the partner clicks on “Get Started”, he is asked for credentials and consent and is authenticated where he can see his access panel where the applications he has been assigned to are shown. Currently the user does not have any applications assigned to him.

imageimage

Step 2: Assigning the guest user to the Dynamics 365 Portals application in AD

While this step is not must for authenticating with the portal, this makes a better experience of the partner to seamlessly authenticate with the portal from their Access Panel.

Again in the Azure portal navigate to Azure active directory –> App Registrations.

Your portal instance is created as an APP in Azure Active Directory.

image

Click on the Application and then in the next Page again click on the Microsoft CRM Portals app as highlighted in the below screenshot.

image

In the overview page, click where total users are being shown and then add the Guest user.

image

image

And you are done. Now when the partner accesses his Access Panel, he could see his Microsoft CRM Portal on his screen. (partner may need to sign in again to see the new APP’s assigned).

image

However if I now click on Open then, it would throw an error. This is because the Sign In Page of the Portal App was not set.

Step 3: Set the sign-on URL of Portal App.

Open the Microsoft CRM Portals App in your Azure Active Directory and click on Settings and then click on Properties

image

In the Home Page URL put the URL of the portals:

Here – https://xrmforyou73.microsoftcrmportals.com

image

Save it and you are done.

Now when the partner logs in and tries to open the Portals, he first needs to sign in using Azure AD button in the portal. From the next time onwards, it just seamless authentication from his access panel.

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)

CRUD operations using executeMultiple in Dynamics 365 WebApi

Just another day at office and yet another challenge. Looked a simple one at the beginning. Basically here is the requirement

“Multiple create and update operations needs to be performed using Dynamics 365 Web API through client side.”

Off-course we can use the Xrm.WebApi.createRecord or Xrm.WebApi.updateRecord but in that case for as many records, those many server side calls need to be made from the client side.

But Microsoft has covered our back right! We have the executeMultiple method. So what’s the fuss about?

Well although we have the method but how to make it work. So basically the executeMultiple will accept an array of request object. And to create the request object, we can easily fall back to the documentation of execute method.

Unfortunately the document lacks in showing how to perform a CRUD operation request object. And that’s the fuss is all about. Things like this believe me, would take you days to resolve.

Well not to worry. If you think that this is going to take away your night’s sleep, I have done that for you. So let’s jump straight to the action here. Check for the parts highlighted in yellow. There in lies all the tricks!

And here is how to create request object for CREATE. Below is the code to create a request object for Account create.

var cAccount = {};
            cAccount["name"] = "CRUD Test";

// put your remaining fields to create the account object.

            var request = {};
            request.getMetadata = function () {
                return {
                     boundParameter: undefined,
                    operationType: 2,
                    operationName: "Create",
                     parameterTypes: {

                    }
                 };
            };

           request.etn = "account";
            request.payload = cAccount;

Below is the code to UPDATE an existing account.

var uAccount = {};
            uAccount["name"] = "CRUD Test – Update";

            var request2 = {};
            request2.getMetadata = function () {
                return {
                     boundParameter: undefined,
                    operationType: 2,
                    operationName: "Update",
                    parameterTypes: {

                    }
                };
            };

            request2.etn = "account";
            request2.payload = uAccount;

request2.id = “<put your account id here>”;

And finally the execute multiple code.

Xrm.WebApi.executeMultiple([request, request2]).then(
           function (results) {
               debugger;

               // parse your results here
            },
           function (error) {
           });

Hope this will help many and save your time!

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)