Business Process Flows (BPF) in Dynamics 365 offer a structured way to guide users through a defined process. However, there are scenarios where progression to the next stage must be validated against specific business rules. In this blog, we see how to implement custom validations on stage progression using JavaScript.
Let us take a simple scenario where a Lead can only progress to the next stage of a BPF if
Lead Quality = Hot and Lead Source = Web
If these conditions are not met, users will receive a notification, and the stage change will be prevented.
Below is the sample code
function OnLoad(executionContext)
{
var formContext = executionContext.getFormContext();
formContext.data.process.addOnPreStageChange(validateStageProgression);
}
function validateStageProgression(executionContext)
{
var bpfSampleStage = "6e2b5d9e-da30-4a47-8ca9-d75c24fd51f4";
var formContext = executionContext.getFormContext();
var rating = formContext.getControl('header_process_leadqualitycode').getAttribute().getValue();
var leadSource = formContext.getControl('header_process_leadsourcecode').getAttribute().getValue();
var stageObj = formContext.data.process.getActiveStage();
var stageId = stageObj.getId();
var requiredFieldErrorId = "contractValidationNotificationId";
formContext.ui.clearFormNotification(requiredFieldErrorId);
if(stageId)
{
if (stageId.toLowerCase() === bpfSampleStage)
{
if (executionContext.getEventArgs().getDirection() === "Next")
{
executionContext.getEventArgs().preventDefault();
if(rating == 1 && leadSource == 8) // rating = Hot and Source = Web
{
formContext.data.process.removeOnPreStageChange(validateStageProgression);
formContext.data.process.moveNext();
}
else
{
notificationMessage = "Cannot move to the next stage until conditions are met !";
formContext.ui.setFormNotification(notificationMessage, "ERROR", requiredFieldErrorId)
}
}
}
}
}
The addOnPreStageChange method registers the validation function on the form’s load event to monitor stage changes.
The preventDefault() method stops the stage transition if the conditions are not met, ensuring data integrity.
If the validation fails, an error notification is displayed using the setFormNotification() method, guiding users to correct the data.
Upon satisfying the conditions, moveNext() is invoked programmatically to move the process to the next stage.
As shown below, clicking on Next as rating and lead source values do not satisfy the condition, we can see the notification on the form and the user is not able to move to the next stage.
The new Smart Grid Preview feature allows us to find, filter, and sort data with natural language.
To enable it navigate to Environment >> Settings >> Features inside Power Platform Admin Center and turn on Natural Language Grid and View Search.
After enabling it we will see a search box on the grid page where we can type in questions about our data in plain English.
Let’s say we need to find “Contacts from the company Contoso”. Normally, this would mean defining the filters/query. But with the Smart Grid’s natural language search, we just type the request, and the system filters the view accordingly.
The result –
We can also use it to sort data.
Another example
The result –
Using natural language search has loads of benefits:
Ease of Use: Do complex searches without needing to be tech-savvy.
Speed: Find what you need quickly without navigating through multiple filters.
Accessibility: Makes data interaction easy for everyone, even if you’re not a tech pro.
As it’s still in preview, there are a few things the Smart Grid Preview doesn’t support yet:
Query Aggregation
Query Grouping
Adding Columns
Remember, it’s still a work in progress and not ready for full production use.
Recently we observed that our plugin registered on the Delete message of appointment on the PreValidation stage was not getting triggered when we were deleting or updating the occurrence of the Recurring Appointment.
For both of the below operations, our plugin was not getting triggered. The plugin had the logic to delete a few associated records to the appointment record.
Delete operation – This deletes all the existing appointment.
Recurrence Update –This deletes the existing appointment and creates new appointment records based on the new recurrence.
On trying out different things, we saw that the plugin was getting triggered if registered on the PreOperation.
For testing, we registered a sample plugin that throws the InvalidPluginExecutionException and saw it getting triggered in case of PreOpertaion as shown below.
We might get the below error while using LINQ to query Dataverse –
System.NotSupportedException: ‘The method ‘GroupJoin’ cannot follow the method ‘SelectMany’ or is not supported. Try writing the query in terms of supported methods or call the ‘AsEnumerable’ or ‘ToList’ method before calling unsupported methods.’
This error occurs because the GroupJoin method, which is essentially what happens during the into … syntax in LINQ, is not supported in the Dataverse/LINQ provider for Dynamics CRM. The issue is related to how the LINQ provider translates queries into FetchXML or SQL that the Dataverse understands. Specifically, nested joins or SelectMany (used by DefaultIfEmpty() in left joins) are not fully supported by the LINQ provider for Dataverse.
The GroupJoin and DefaultIfEmpty methods (used for left joins) result in queries that cannot be translated directly into FetchXML. The LINQ provider for Dataverse does not support all LINQ-to-Entities features, such as nested joins or advanced grouping logic. When you perform nested joins with DefaultIfEmpty() for left joins, the LINQ provider struggles to translate it into the underlying Dataverse query format, which is why the exception is thrown.
To fix it we can break the query into multiple steps as shown below.
However, here as we are fetching partial data into memory and combining it, it increases transfer and processing overhead and can take a long time to process based on the number of records.
The better alternative from a performance perspective would be to use FetchXML or QueryExpression here.
We might get the below error while using LINQ to query Dataverse – “System.NotSupportedException: ‘Invalid ‘where’ condition. An entity member is invoking an invalid property or method.’” Here we got the below error because we used the HasValue property.
Here the issue with HasValue arises because FetchXML doesn’t have a direct equivalent for nullable checks like HasValue in LINQ. In FetchXML, null checks are handled explicitly through conditions like neq (not equal) or eq (equal) with the null value. Therefore, instead of using HasValue, we need to manually check for null using != null or GetValueOrDefault().
We will also get the same error on below query.
Here we get this error because OriginatingLeadId is a LookUp referencing Lead table, and we are trying to access the Name property of it in the where clause, which cannot be directly translated into FetchXML. To fix it we can perform a join between the Contact and Lead table.
Let us see one more example.
The query, c.Attributes[“firstname”].ToString() is trying to access the firstname attribute and convert it to a string. However, the LINQ provider doesn’t know how to translate.ToString() into a valid FetchXML query.
To fix it we can use GetAttributeValue method.
Or doing the casting
However, we will get the same not supported error if we try to use Attributes Collection.
The error occurs because of the syntax c.Attributes[“firstname”] directly accesses the internal Attributes dictionary of the Entity object. The LINQ provider in Dataverse (Dynamics 365) cannot translate this access pattern into a FetchXML