Validating Document Upload in Business Process Flow by Setting Field Requirement Level Conditionally (Part 2 of 2)

This is the second post in a two-part series of File field as input and SharePoint as storage. You can check out the first post via this link.

Using the File field in Business Process Flow for uploading of documents

Sometimes, the new functionalities introduced to the Common Data Service (CDS) platform is not immediately supported in the no-code functionality of the model-driven apps and only through supported API in the beginning. For example, column comparison can be used in queries using FetchXML, Web API, or the SDK API but it is not available in UI components like advanced filtering panel (or Advanced Find), view designer, etc. Another example is the Multi Select Option Set which is still not supported in Workflow, Business Rule or Business Process Flow. But somehow, File datatype which was introduced at the end of last year was already available in the Business Process Flow (BPF) as soon as it was made available in the model-driven app with 2020 Release Wave 1 in April 2020. I believe that might be because of the importance of use case scenarios for the file type field.

One of the most common use cases is to enforce the user to upload specific files before proceeding further in the process (you can read more details at the beginning of Part 1 blog post). In such a scenario, you can add the 'file' field in the BPF stage and set as Required. In that way, the user will not be able to proceed to the next step of BPF until the file is uploaded.

The solution above will suffice if you are ok with storing the file(s) in the CDS. But if the requirement is to store the documents in the SharePoint document library, some additional components are required which I have listed down in the next section

Validate and move the files uploaded to SharePoint

Below are the additional components and actions you need to perform to move the files uploaded through a File field to a SharePoint document library:
  1. Business Process Flow with the following 3 fields
    1. Two Options field as a flag to indicate whether the file is uploaded or not (Identity Document Uploaded)
    2. File field to upload the file (Identity Document File)
    3. Text field with URL format type to store the SharePoint document URL (Identity Document File URL)
  2. JavaScript web resource to set the field value and requirement level (we use JavaScript as the ‘file’ field is not supported in Business Rules as of now). 
  3. Automated flow to move attachment from File field to the SharePoint document library
The details for the automated flow listed in item 3 can be found in the Part 1 blog post so I am not going to detail those in this post. In summary, the flow is automatically triggered on change of the 'file' field and when the field is uploaded, it is moved to the SharePoint document library and removed from CDS.

First of all, all three fields are added to the stage of the BPF and the Identity Document Uploaded flag is set as Required in BPF.

var LZW = LZW || {};
LZW.Xrm = LZW.Xrm || {};
LZW.Xrm.Contact = {
executionContext: null,
onLoad: function (executionContext)
{
    LZW.Xrm.Contact.executionContext = executionContext;
    var formContext = executionContext.getFormContext();
    formContext.data.entity.attributes.forEach(function (attribute, index)
    {
        var name = attribute.getName();
        attribute.addOnChange(function (executionContext)
        {
            LZW.Xrm.Contact.onChange(executionContext.getEventSource().getName());
        });
    });
    LZW.Xrm.Contact.setDocumentRequirementLevel();
},
onChange: function (fieldName)
{
    switch (fieldName)
    {
        case "lzw_identitydocumentuploaded":
        case "lzw_identitydocumentfileurl":
            LZW.Xrm.Contact.setDocumentRequirementLevel();
            break;
        case "lzw_identitydocumentfile":
            LZW.Xrm.Contact.setDocumentUploadedFlag();
            break;
    }
},
setDocumentRequirementLevel: function (executionContext)
{
    var formContext = LZW.Xrm.Contact.executionContext.getFormContext();
    if (formContext.getAttribute("lzw_identitydocumentuploaded").getValue())
    {
        if (formContext.getAttribute("lzw_identitydocumentfileurl").getValue() === null)
        {
            formContext.getControl("header_process_lzw_identitydocumentfile").setVisible(true);
            formContext.getAttribute("lzw_identitydocumentfile").setRequiredLevel("required");
formContext.getControl("header_process_lzw_identitydocumentfileurl").setVisible(false); formContext.getAttribute("lzw_identitydocumentfileurl").setRequiredLevel("none");
} else { formContext.getControl("header_process_lzw_identitydocumentfileurl").setVisible(true); formContext.getAttribute("lzw_identitydocumentfileurl").setRequiredLevel("required");
formContext.getControl("header_process_lzw_identitydocumentfile").setVisible(false); formContext.getAttribute("lzw_identitydocumentfile").setRequiredLevel("none");
} } else { formContext.getControl("header_process_lzw_identitydocumentfile").setVisible(true); formContext.getAttribute("lzw_identitydocumentfile").setRequiredLevel("none");
formContext.getControl("header_process_lzw_identitydocumentfile").setVisible(false); formContext.getAttribute("lzw_identitydocumentfileurl").setRequiredLevel("none");
} }, setDocumentUploadedFlag: function (executionContext) { var formContext = LZW.Xrm.Contact.executionContext.getFormContext(); var hasDocumentUploaded = formContext.getAttribute("lzw_identitydocumentfile").getValue() !== null; formContext.getAttribute("lzw_identitydocumentuploaded").setValue(hasDocumentUploaded); formContext.getAttribute("lzw_identitydocumentuploaded").fireOnChange(); } };
Then, add the JavaScript above to show/hide fields and set the requirement level of the fields. JavaScript web resource is used for this solution because the 'file' field is not supported in the Business Rule yet. In order to get the controls in the BPF by name getControl() to show/hide, "header_process_" need to be prefixed before the name of the field.
formContext.getControl("header_process_<<FieldNamedentity>>")

The difference between the solution at the beginning of this post where the 'file' field is added in the BPF stage as Required and this one is that the Identity Document Uploaded flag set the requirement level of the Identity Document File field and Identity Document File URL fields dynamically so that the user can proceed to the next stage as soon as the document is uploaded or after the document is moved to the SharePoint and only Identity Document File URL contains data.

When the Identity Document Uploaded flag is changed to Yes, the JavaScript set the Identity Document File field as mandatory so that the user cannot proceed unless the file is uploaded.


If the file is uploaded to the Identity Document File field while Identity Document Uploaded flag is No, the flag will be automatically changed to Yes by the JavaScript. In this stage, the user can proceed to the next stage.


Let's say the user did not proceed to the next stage yet and navigated to another record in the system to process something else. By the time the user comes back to the record, the automated flow has already moved the attachment from 'file' field to the SharePoint document library, cleared the 'file' field and populated the Identity Document File URL with the SharePoint document URL.

In this stage, the Identity Document File URL field is mandatory instead of the Identity Document File field because of the way the JavaScript set the requirement level dynamically. The user can still proceed to the next stage even though the Identity Document File field is empty because there is a value of migrated file SharePoint URL in the Identity Document File URL field.

Summary

File data type field is available in the Business Process Flow. By using the Two Options field as a flag and JavaScript, we can dynamically show/hide and set the requirement level of the fields before the Business Process Flow can proceed to the next stage.

Comments

Popular Posts

[Power Automate] How to Set Lookup Field Value in Common Data Service (current environment) Flow Connector

[Power Apps] Using Common Data Service's Lookup Data Type Field in Canvas App

Get the Lookup Display Name and Option Set Value Label in a Single Query Using a CDS (Current Environment) Connector FormattedValue Property

Move Attachment from File Field of CDS to SharePoint in Power Automate (Part 1 of 2)

Find out how to include a link to the record (Record URL) when sending an email from Dynamics 365/CDS using flow

[Power Automate] List Records - Use Expand Query to Retrieve Related Data in flow

Send Email from Dynamics 365/CDS with Attachment from Notes Using Flow

Getting the Lookup Attribute of the Parent Record in Power Apps Canvas App Development with Common Data Service (CDS)

How to Set Lookup Fields with Null Value from Dynamic Content in CDS (current environment) Connector