web
You’re offline. This is a read only version of the page.
close
Skip to main content

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :
Microsoft Dynamics 365 | Integration, Dataverse...
Answered

Plugin - Work Order OnUpdate Validation

(1) ShareShare
ReportReport
Posted on by 905

Hello everyone,

I want to add some business validation before the users save a work order based on the below scenarios:

  1. Prevent users to save the Work order if the system status selected is "closed-posted" and the agreement lookup value linked to the WO has status "Cancelled agreement".
  2. Prevent the users from closing the work order if the incident type is "visit" and the Products grid contains one product.

I started this week to learn plugins and the above I think requires that. However, if a real-time workflow can achieve the above to throw an exception error for the user in the form based on the above conditions what is the best way to do it?

I want someone to point me to some resources or provide an example based on the below:

  1. How can I extract from a lookup value a specific field attribute which is in my case the status option set type of the agreement table using a plugin?
  2. How can I make a condition to check if the products grid is empty or the rows are equal to 0 using a plugin?
  3. Does the above scenarios can be achieved using one plugin onUpdate event?

I want a piece of advice on what is the easiest and the fastest solution to solve the above scenarios.

If someone can provide an example It would be highly appreciated.

Thank you!!

I have the same question (0)
  • Suggested answer
    Community Member Profile Picture
    on at

    Hi EBMRay,

    For your first scenarios:

    You could create an on save event on the Work Order form with the following code:

    var isValidationNeeded = true;
    function preventSave(executionContext){
    	if (!isValidationNeeded) {
                isValidationNeeded = true;
                return;
        }
    	var formContext = executionContext.getFormContext();
    	var status = formContext.getAttribute("msdyn_systemstatus").getValue();
    	if(status === 690970004){
    		var agreement = formContext.getAttribute("msdyn_agreement").getValue();
    		if(agreement != null && agreement.length >0){
    			var id = agreement[0].id;
                executionContext.getEventArgs().preventDefault();
    			Xrm.WebApi.retrieveRecord("msdyn_agreement",id,"?$select=msdyn_systemstatus").then(
    				function success(result){
                        isValidationNeeded = false; 
    					if(result["msdyn_systemstatus"] === 690970003){
    						Xrm.Navigation.openAlertDialog({text:"current work order can't be saved"});
    					}else{
                            formContext.data.entity.save();
                        }
    				},
    				function (error){
    					Xrm.Navigation.openAlertDialog({ text: error.message });
    				}
    			);
    		}
    	}
    }

    This is my test code, you can refer to this blog(Cancelling save event based on the result of async operation – Andrew Butenko's Blog)

    And it can work on my side:

     pastedimage1634278456782v1.png

    And for your second scenarios, Do you mind  using Ribbon Workbench?

  • EBMRay Profile Picture
    905 on at

    Hi  ,

    I appreciate the example provided to prevent the user save the WO if the agreement is canceled.

    Regarding the second scenario, I don't mind using Ribbon Workbench if it can solve using this tool and it's much easier than writing a plugin.

    It would be highly appreciated if you could also provide an example regarding the above and I will test the first scenario and get back to you.

    Finally, does the second scenario logic will be also the OnSave button?

    Looking forward to your response.

    Thanks again!!

  • Suggested answer
    Community Member Profile Picture
    on at
    [deleted]
  • EBMRay Profile Picture
    905 on at

    Hi Steve,

    I have tried the script mentioned and it worked perfectly.

    I still have the second point on how can I check for sub-grid rows length and iterate through Service Tasks Statuses.

    For example, if you have multiple incidents and their tasks are not completed the users should be able to close the WO.

    Actually, I tried to continue on top of your code to start to apply the logic for the above: (Still testing to learn how to)

    WO Validation JS

    Finally, How can I handle those multiple validations onSave event of the form because currently, I have 3 different conditions:

    1. Prevent the user from closing the work order if the incident type is visit and contains products.
    2. Prevent the user to close the work order if the linked agreement is canceled.
    3. Prevent the user from completing the work order if not all the service tasks are done.

    Could you please check the code what I've tried and what should be changed?

    Your help is highly appreciated.
    Looking forward to your response.

    Best regards,

  • Community Member Profile Picture
    on at

    Hi EBMRay,

    Just one thing to confirm: The incident type is visit means the  display name of "Primary Incident Type" filed in the Work Order is "Service", right?

  • EBMRay Profile Picture
    905 on at

    Hi Steve,

    Yes, it is the "Primary Incident type" field I am doing a condition based on that field value.

    Thank you!

  • Suggested answer
    Community Member Profile Picture
    on at

    Hi EBMRay,

    There is no need to get product/service task grid, you can use retrieveMultipleRecords()(API doc: retrieveMultipleRecords (Client API reference) in model-driven apps - Power Apps | Microsoft Docs) method to check them.

    The below code is my new sample which is used to check incident type and service task. The product validation is similar as service task, you can try yourself.

    var isValidationNeeded = true;
    var serviceTaskValidation = true;
    
    function preventSave(executionContext){
    	if (!isValidationNeeded) {
                isValidationNeeded = true;
                return;
        	}
    	var formContext = executionContext.getFormContext();
    	
    	//get current WO id
    	var workOrderId = formContext.data.entity.getId().replace("{","").replace("}","");
    	var valInc = formContext.getAttribute("msdyn_primaryincidenttype").getValue();
    	var status = formContext.getAttribute("msdyn_systemstatus").getValue();
    	
    	//close the WO or not
    	if(status != null && status === 690970004){
    		executionContext.getEventArgs().preventDefault();
    		
    		//if visit type equals visit
    		console.log(valInc);
    		if(valInc == null || valInc[0].name !== "Service"){
    			//get active related service task 
    			Xrm.WebApi.retrieveMultipleRecords("msdyn_workorderservicetask","?$select=msdyn_name,msdyn_percentcomplete,statecode&$filter=statecode eq 0 and msdyn_workorder/msdyn_workorderid eq "   workOrderId).then(
    				function success(result){
                    			for(var x in result){
    						if(result[x].msdyn_percentcomplete != 100){
    							serviceTaskValidation = false;
    							break;
    						}
    					}
    					if(serviceTaskValidation){
    						isValidationNeeded = false;
    						formContext.data.save();
    					}else{
    						Xrm.Navigation.openAlertDialog({ text: "current work order can't be closed because not all the service tasks are done" });
    					}
    				},
    				function (error){
    					Xrm.Navigation.openAlertDialog({ text: error.message });
    				}
    			);
    		}else{
    			Xrm.Navigation.openAlertDialog({ text: "current work order can't be closed because incident type is visit" });
    		}
    		
    	}
    }
    
    

  • EBMRay Profile Picture
    905 on at

    Hi Steve,

    Thank you so much for providing another example regarding the above scenarios.

    I will try the code mentioned. I just wanted to ask you that the code provided should be added as a new web resource and on save event of the form as we did for the first script? There will not be any conflict between the two scripts? or the same script mentioned should be on the same web resource that we did the first time?

    Awaiting your response.

    Thanks again!!

  • Community Member Profile Picture
    on at

    Hi EBMRay,

    It is better to merge the two scripts into one and use it as the library of onSave event.

  • EBMRay Profile Picture
    905 on at

    Hi   ,

    Thank you for your reply.

    I started to apply the logic to merge those two scripts into one and until now I did the below:

    function preventSave(executionContext){
    
        var ruleOne = rule1(executionContext);
        var ruleTwo = rule2(executionContext);
    
        if(ruleOne && ruleTwo){
    
            formContext.data.save();
    
    }
    
    }
        function rule1(executionContext){
    
    	var formContext = executionContext.getFormContext();
    	var status = formContext.getAttribute("msdyn_systemstatus").getValue();
    	if(status === 690970004){
    		var agreement = formContext.getAttribute("msdyn_agreement").getValue();
    		if(agreement != null && agreement.length >0){
    			var id = agreement[0].id;
                executionContext.getEventArgs().preventDefault();
    			Xrm.WebApi.retrieveRecord("msdyn_agreement",id,"?$select=msdyn_systemstatus").then(
    				function success(result){
                        
    					if(result["msdyn_systemstatus"] === 690970003){
    						Xrm.Navigation.openAlertDialog({text:"Current work order can't be saved"});
                            return false;
    					}else{
                            
                            return true;
                        }
    				},
    				function (error){
    					Xrm.Navigation.openAlertDialog({ text: error.message });
                        return false;
    				}
    			);
    		}
    	}
    
    }
    
    function rule2(executionContext){
    
            var formContext = executionContext.getFormContext();
            
            //get current WO id
            var workOrderId = formContext.data.entity.getId().replace("{","").replace("}","");
            var valInc = formContext.getAttribute("msdyn_primaryincidenttype").getValue();
            var status = formContext.getAttribute("msdyn_systemstatus").getValue();
            
            //close the WO or not
            if(status != null && status === 690970004){
        
                var agreement = formContext.getAttribute("msdyn_agreement").getValue();
                if(agreement != null && agreement.length >0){
                    var id = agreement[0].id;
                    
                executionContext.getEventArgs().preventDefault();
                
                //if visit type equals visit
                console.log(valInc);
                if(valInc == null || valInc[0].name !== "Service"){
                    //get active related service task 
                    Xrm.WebApi.retrieveMultipleRecords("msdyn_workorderservicetask","?$select=msdyn_name,msdyn_percentcomplete,statecode&$filter=statecode eq 0 and msdyn_workorder/msdyn_workorderid eq "   workOrderId).then(
                        function success(result){
                                    for(var x in result){
                                if(result[x].msdyn_percentcomplete != 100){
                                    serviceTaskValidation = false;
                                    break;
                                }
                            }
                            if(serviceTaskValidation){
                                
                              return true;
                            }else{
                                Xrm.Navigation.openAlertDialog({ text: "current work order can't be closed because not all the service tasks are done" });
                                return false;
                            }
                        },
                        function (error){
                            Xrm.Navigation.openAlertDialog({ text: error.message });
                            return false;
                        }
                    );
                }else{
                   Xrm.Navigation.openAlertDialog({ text: "current work order can't be closed because incident type is visit" });
                   return false;
                }
                
            }
        }
    }

    I just wanted your advice if this is the correct way I am doing it.

    Your help is highly appreciated.

    Thank you!

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Neeraj Kumar – Community Spotlight

We are honored to recognize Neeraj Kumar as our Community Spotlight honoree for…

Leaderboard > Microsoft Dynamics 365 | Integration, Dataverse, and general topics

#1
Siv Sagar Profile Picture

Siv Sagar 93 Super User 2025 Season 2

#2
#ManoVerse Profile Picture

#ManoVerse 80

#3
Martin Dráb Profile Picture

Martin Dráb 64 Most Valuable Professional

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans