Skip to main content

Notifications

Announcements

No record found.

Microsoft Dynamics 365 | Integration, Dataverse...
Answered

Plugin - Work Order OnUpdate Validation

Posted on by 873

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!!

  • EBMRay Profile Picture
    EBMRay 873 on at
    RE: Plugin - Work Order OnUpdate Validation

    Hi ,

    I am grateful for your support and I value the guidance you provided.

    You helped me to get started and I learned about injecting JS code to Model-Driven forms.

    Regarding the way to prevent the behavior of the above, please feel free to update your answer if you found the way.

    Meanwhile, I can confirm that this case has been resolved.

    Thank you!!

  • Verified answer
    Community Member Profile Picture
    Community Member Microsoft Employee on at
    RE: Plugin - Work Order OnUpdate Validation

    Hi EMBRay,

    Please try the below code, it fixed issue 1 and changed the filter condition in rule3.

    The issue 2 seems that when you create a new product, it will check your WO form's data is dirty or not(saved or unsaved). If it is not dirty(saved), it won't trigger onSave event. Otherwise, it would  rigger onSave event. I haven't found any way to prevent this behavior. If I found any way to do this later, I would update my answer.

    var isValidationNeeded = true;
    var preventEventSave = true;
    var SaveMode = {
    Save: 1,
    SaveAndClose: 2,
    SaveAndNew: 59,
    Autosave: 70
    };

    function preventSave(executionContext) {

    debugger;

    //getting save mode from event
    var saveMode = executionContext.getEventArgs().getSaveMode();

    //if savemode is not one of listed - just quit the execution and let the record to be saved
    if (saveMode !== SaveMode.Save &&
    saveMode !== SaveMode.SaveAndClose &&
    saveMode !== SaveMode.SaveAndNew &&
    saveMode !== SaveMode.Autosave) {
    return;
    }
    if (!isValidationNeeded) {
    isValidationNeeded = true;
    return;
    }

    // if rule1 is passed then check rule3
    var ruleThree= false;

    rule3(executionContext).then(function(data) {
    ruleThree = data;
    if (!ruleThree) {
    if (saveMode === SaveMode.Save || saveMode === SaveAndClose){
    Xrm.Navigation.openAlertDialog({
    text: "current work order can't be closed because the incident type is visit and contains products!"
    });
    return;

    }
    } else {
    var boolRule1 = false;
    var formContext = executionContext.getFormContext();
    var status = formContext.getAttribute("msdyn_systemstatus").getValue(); // getting the status the value

    console.log(status);
    // Completed Status
    // status is not close posted
    if (status === 690970004 || status === 690970003) {

    var ruleOne = false;
    var ruleTwo = false;

    if (status === 690970004) {
    rule1(executionContext).then(function(data) {

    ruleOne = data;

    if (!ruleOne) {

    if (saveMode === SaveMode.Save || saveMode === SaveAndClose){
    Xrm.Navigation.openAlertDialog({
    text: "Current work order can't be saved because of canceled agreement"
    });
    return;

    }

    } else {
    isValidationNeeded = false;
    formContext.data.save().then(function () {
    alert("Form saved successfully");
    }, function (error) {
    var errorMessage = error.message;
    console.log(errorMessage);
    });

    }
    }, function(errorMessage) {
    Xrm.Navigation.openAlertDialog({
    text: errorMessage
    });
    });
    }


    if (status === 690970003) {

    rule2(executionContext).then(function(data) {

    ruleTwo = data;
    if (!ruleTwo) {
    Xrm.Navigation.openAlertDialog({
    text: "current work order can't be closed because not all the service tasks are done"
    });
    return;
    } else {
    isValidationNeeded = false;
    formContext.data.save().then(function() {
    alert("Form saved successfully");
    }, function(error) {
    var errorMessage = error.message;
    console.log(errorMessage);
    });
    }
    }, function(errorMessage) {
    Xrm.Navigation.openAlertDialog({
    text: errorMessage
    });
    });
    }

    }else{
    isValidationNeeded = false;
    console.log(preventEventSave);
    if(preventEventSave){
    formContext.data.save().then(function() {
    alert("Form saved successfully");
    }, function(error) {
    var errorMessage = error.message;
    console.log(errorMessage);
    })
    }

    }
    }
    }, function(errorMessage) {
    Xrm.Navigation.openAlertDialog({
    text: errorMessage
    });
    });
    }

    function rule1(executionContext) { // 1. Prevent the user to close posted the work order if the linked agreement is canceled.
    var formContext = executionContext.getFormContext();
    var agreement = formContext.getAttribute("msdyn_agreement").getValue();
    executionContext.getEventArgs().preventDefault();
    var promiseRule1 = new Promise(function(resolve, reject) {
    var boolRule1 = true;
    if (agreement != null && agreement.length > 0) {
    var id = agreement[0].id;
    var result = 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 because of Cancelled agreement"});
    boolRule1 = false;
    }
    resolve(boolRule1);
    },
    function(error) {
    //Xrm.Navigation.openAlertDialog({ text: error.message });
    reject(error.message);
    }
    );
    } else {
    resolve(boolRule1);
    }
    })
    return promiseRule1;
    }

    function rule2(executionContext) { //2.Prevent the user from completing the work order if not all the service tasks are done.
    executionContext.getEventArgs().preventDefault();
    var promiseRule2 = new Promise(function(resolve, reject) {

    var boolRule2 = true;
    var serviceTaskValidation = true;
    var formContext = executionContext.getFormContext();
    //get current WO id
    var workOrderId = formContext.data.entity.getId().replace("{", "").replace("}", "");
    //var valInc = formContext.getAttribute("msdyn_primaryincidenttype").getValue();
    var woStatus = formContext.getAttribute("msdyn_systemstatus").getValue();
    //close the WO or not
    //console.log(valInc);
    if (woStatus != null && woStatus === 690970003) { // If the System status is equal to Completed
    //get active related service task
    var result = 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 i = 0; i < result.entities.length; i++) {

    console.log(result.entities[i].msdyn_name);
    console.log(result.entities[i].msdyn_percentcomplete);

    if (result.entities[i].msdyn_percentcomplete != 100) {

    serviceTaskValidation = false;
    break;
    }
    }
    if (!serviceTaskValidation) {
    boolRule2 = false;
    }
    resolve(boolRule2);
    },
    function(error) {
    reject(error.message);
    }
    )
    }

    });
    return promiseRule2;
    }

    function rule3(executionContext){ // Prevent Closing WO if primary incident is visit and WO contains products
    var promiseRule3 = new Promise(function (resolve, reject) {
    var boolRule3 = true;
    var woProdValidation = true;
    var formContext = executionContext.getFormContext();
    var woID = formContext.data.entity.getId().replace("{", "").replace("}", "");
    var valInc = formContext.getAttribute("msdyn_primaryincidenttype").getValue();

    if(valInc != null && valInc.length >0){
    var name = valInc[0].name;
    if(name == "Visit"){
    executionContext.getEventArgs().preventDefault();
    Xrm.WebApi.retrieveMultipleRecords("msdyn_workorderproduct","?$select=msdyn_name&$filter=msdyn_workorder/msdyn_workorderid eq " + woID +" and statecode eq 0").then(
    function success(result) {
    console.log(result);
    // perform operations on on retrieved records
    if(result.entities != null && result.entities.length > 0){
    woProdValidation = false;
    }else{
    alert("no data");
    }
    if (!woProdValidation) {
    boolRule3 = false;
    }
    resolve(boolRule3);
    },
    function (error) {
    reject(error.message);
    // handle error conditions
    }
    )
    }else{
    preventEventSave = false;
    resolve(boolRule3);
    }
    }else{
    preventEventSave = false;
    resolve(boolRule3);
    }
    });
    return promiseRule3;
    }

  • EBMRay Profile Picture
    EBMRay 873 on at
    RE: Plugin - Work Order OnUpdate Validation

    Hi Steve,

    Thank you for providing the above code.


    I have tried the updated code and while testing I encountered the below issues:

    1. If the WO status is "unscheduled" and I press the save button the form is not being saved because it's going to the else logic and I believe this is because we're not calling the function to save the form if the status was not either completed or closed posted?

    Rule3Err.PNGRule3Tu.gif

    2. Please have a look at the below behavior while adding a product manually from the grid:
    WOProductIssue.gif

    While adding a product to the WO from the grid without pushing the save button on the WO it automatically shows that error because I believe a background process is triggering to save the product to the WO.

    Can we prevent that behavior and show only that error if he pushed the save button only?

    The filter view of the products grid is the "WO Product Associated View" but I am not checking a specific view I just want to check if the grid has rows or not.
    So based on our script the code is working to check for the total rows count the grid view right?

    Finally, could you please provide the updated code version to fix those issues?

    Looking forward to your response.

    Best regards,

  • Suggested answer
    Community Member Profile Picture
    Community Member Microsoft Employee on at
    RE: Plugin - Work Order OnUpdate Validation

    Hi EBMRay,

    Please try the following JS script, it should work:

    var isValidationNeeded = true;

    var SaveMode = {
    Save: 1,
    SaveAndClose: 2,
    SaveAndNew: 59,
    Autosave: 70
    };

    function preventSave(executionContext) {

    debugger;

    //getting save mode from event
    var saveMode = executionContext.getEventArgs().getSaveMode();

    //if savemode is not one of listed - just quit the execution and let the record to be saved
    if (saveMode !== SaveMode.Save &&
    saveMode !== SaveMode.SaveAndClose &&
    saveMode !== SaveMode.SaveAndNew &&
    saveMode !== SaveMode.Autosave) {
    return;
    }
    if (!isValidationNeeded) {
    isValidationNeeded = true;
    return;
    }

    // if rule1 is passed then check rule3
    var ruleThree= false;
    rule3(executionContext).then(function(data) {
    ruleThree = data;
    if (!ruleThree) {
    if (saveMode === SaveMode.Save || saveMode === SaveAndClose){
    Xrm.Navigation.openAlertDialog({
    text: "current work order can't be closed because the incident type is visit and contains products!"
    });
    return;

    }
    } else {
    var boolRule1 = false;
    var formContext = executionContext.getFormContext();
    var status = formContext.getAttribute("msdyn_systemstatus").getValue(); // getting the status the value

    console.log(status);
    // Completed Status
    // status is not close posted
    if (status === 690970004 || status === 690970003) {

    var ruleOne = false;
    var ruleTwo = false;

    if (status === 690970004) {
    rule1(executionContext).then(function(data) {

    ruleOne = data;

    if (!ruleOne) {

    if (saveMode === SaveMode.Save || saveMode === SaveAndClose){
    Xrm.Navigation.openAlertDialog({
    text: "Current work order can't be saved because of canceled agreement"
    });
    return;

    }

    } else {
    isValidationNeeded = false;
    formContext.data.save().then(function () {
    alert("Form saved successfully");
    }, function (error) {
    var errorMessage = error.message;
    console.log(errorMessage);
    });

    }
    }, function(errorMessage) {
    Xrm.Navigation.openAlertDialog({
    text: errorMessage
    });
    });
    }


    if (status === 690970003) {

    rule2(executionContext).then(function(data) {

    ruleTwo = data;
    if (!ruleTwo) {
    Xrm.Navigation.openAlertDialog({
    text: "current work order can't be closed because not all the service tasks are done"
    });
    return;
    } else {
    isValidationNeeded = false;
    formContext.data.save().then(function() {
    alert("Form saved successfully");
    }, function(error) {
    var errorMessage = error.message;
    console.log(errorMessage);
    });
    }
    }, function(errorMessage) {
    Xrm.Navigation.openAlertDialog({
    text: errorMessage
    });
    });
    }

    }
    }
    }, function(errorMessage) {
    Xrm.Navigation.openAlertDialog({
    text: errorMessage
    });
    });
    }

    function rule1(executionContext) { // 1. Prevent the user to close posted the work order if the linked agreement is canceled.
    var formContext = executionContext.getFormContext();
    var agreement = formContext.getAttribute("msdyn_agreement").getValue();
    executionContext.getEventArgs().preventDefault();
    var promiseRule1 = new Promise(function(resolve, reject) {
    var boolRule1 = true;
    if (agreement != null && agreement.length > 0) {
    var id = agreement[0].id;
    var result = 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 because of Cancelled agreement"});
    boolRule1 = false;
    }
    resolve(boolRule1);
    },
    function(error) {
    //Xrm.Navigation.openAlertDialog({ text: error.message });
    reject(error.message);
    }
    );
    } else {
    resolve(boolRule1);
    }
    })
    return promiseRule1;
    }

    function rule2(executionContext) { //2.Prevent the user from completing the work order if not all the service tasks are done.
    executionContext.getEventArgs().preventDefault();
    var promiseRule2 = new Promise(function(resolve, reject) {

    var boolRule2 = true;
    var serviceTaskValidation = true;
    var formContext = executionContext.getFormContext();
    //get current WO id
    var workOrderId = formContext.data.entity.getId().replace("{", "").replace("}", "");
    //var valInc = formContext.getAttribute("msdyn_primaryincidenttype").getValue();
    var woStatus = formContext.getAttribute("msdyn_systemstatus").getValue();
    //close the WO or not
    //console.log(valInc);
    if (woStatus != null && woStatus === 690970003) { // If the System status is equal to Completed
    //get active related service task
    var result = 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 i = 0; i < result.entities.length; i++) {

    console.log(result.entities[i].msdyn_name);
    console.log(result.entities[i].msdyn_percentcomplete);

    if (result.entities[i].msdyn_percentcomplete != 100) {

    serviceTaskValidation = false;
    break;
    }
    }
    if (!serviceTaskValidation) {
    boolRule2 = false;
    }
    resolve(boolRule2);
    },
    function(error) {
    reject(error.message);
    }
    )
    }

    });
    return promiseRule2;
    }

    function rule3(executionContext){ // Prevent Closing WO if primary incident is visit and WO contains products

    executionContext.getEventArgs().preventDefault();

    var promiseRule3 = new Promise(function (resolve, reject) {
    var boolRule3 = true;
    var woProdValidation = true;
    var formContext = executionContext.getFormContext();
    var woID = formContext.data.entity.getId().replace("{", "").replace("}", "");
    var valInc = formContext.getAttribute("msdyn_primaryincidenttype").getValue();

    if(valInc != null && valInc.length >0){
    var name = valInc[0].name;
    if(name == "Visit"){
    Xrm.WebApi.retrieveMultipleRecords("msdyn_workorderproduct","?$select=msdyn_name&$filter=msdyn_workorder/msdyn_workorderid eq " + woID).then(
    function success(result) {
    console.log(result);
    // perform operations on on retrieved records
    if(result.entities != null && result.entities.length > 0){
    woProdValidation = false;
    }else{
    alert("no data");
    }
    if (!woProdValidation) {
    boolRule3 = false;
    }
    resolve(boolRule3);
    },
    function (error) {
    reject(error.message);
    // handle error conditions
    }
    )
    }else{
    resolve(boolRule3);
    }
    }else{
    resolve(boolRule3);
    }
    });
    return promiseRule3;
    }

    Note:

    The filter in this line Xrm.WebApi.retrieveMultipleRecords("msdyn_workorderproduct","?$select=msdyn_name&$filter=msdyn_workorder/msdyn_workorderid eq " + woID) is based on your WO Product's view used in subgrid. If your view has other filter conditions, please add it to filter in this line, such as Xrm.WebApi.retrieveMultipleRecords("msdyn_workorderproduct","?$select=msdyn_name&$filter=msdyn_workorder/msdyn_workorderid eq " + woID + "and xx eq xx")

  • EBMRay Profile Picture
    EBMRay 873 on at
    RE: Plugin - Work Order OnUpdate Validation

    Hi ,

    Thank you for your prompt response.

    The answer is Yes, whatever is the status of WO we should check for rule3 and not based on any WO specific status.

    What should we change in the code to validate the rule3 regardless what is the WO status?

    Awaiting your response.

    Thanks again!

  • Community Member Profile Picture
    Community Member Microsoft Employee on at
    RE: Plugin - Work Order OnUpdate Validation

    Hi EBMRay,

    Q:"Clicking the save button twice issue has been resolved but I just wanted to ask you what you've changed in the code to avoid that?"

    A: I changed the position of this line isValidationNeeded = false; of both rule1 and rule2. So when you click save the second time, it would still validate.

    And I have a question: Does the rule3 should be validated whatever the status of  WO or it should be checked in some specific status?

    If it should be validated in some specific status, please tell me  what are those status.

  • EBMRay Profile Picture
    EBMRay 873 on at
    RE: Plugin - Work Order OnUpdate Validation

    Dear Steve,

    Thank you for providing the updated version.

    Clicking the save button twice issue has been resolved but I just wanted to ask you what you've changed in the code to avoid that?

    In addition, for Rule3 condition, it will not be satisfied because if the system status of the WO was unscheduled it will never check for Rule3 logic and if it was closed posted or completed the logic of the parent condition is if (status === 690970004 || status === 690970003) that is either completed or closed posted.

    Please have a look below at the error:

    Rule3Error.PNGRule3Error.PNG
    Where should we place the rule3 logic to avoid the above issue?

    I didn't change anything in the code so please check the one you provided.

    Awaiting your response.

  • Suggested answer
    Community Member Profile Picture
    Community Member Microsoft Employee on at
    RE: Plugin - Work Order OnUpdate Validation

    Hi EBMRay,

    I fixed this bug( click save button twice would save the data) with the updated version:

    var isValidationNeeded = true;

    var SaveMode = {
    Save: 1,
    SaveAndClose: 2,
    SaveAndNew: 59,
    Autosave: 70
    };

    function preventSave(executionContext) {

    debugger;

    //getting save mode from event
    var saveMode = executionContext.getEventArgs().getSaveMode();

    //if savemode is not one of listed - just quit the execution and let the record to be saved
    if (saveMode !== SaveMode.Save &&
    saveMode !== SaveMode.SaveAndClose &&
    saveMode !== SaveMode.SaveAndNew &&
    saveMode !== SaveMode.Autosave) {
    return;
    }
    if (!isValidationNeeded) {
    isValidationNeeded = true;
    return;
    }

    var boolRule1 = false;
    var formContext = executionContext.getFormContext();
    var status = formContext.getAttribute("msdyn_systemstatus").getValue(); // getting the status the value

    console.log(status);
    // Completed Status
    // status is not close posted
    if (status === 690970004 || status === 690970003) {

    var ruleOne = false;
    var ruleTwo = false;

    if (status === 690970004) {
    rule1(executionContext).then(function(data) {

    ruleOne = data;

    if (!ruleOne) {

    if (saveMode === SaveMode.Save || saveMode === SaveAndClose){

    executionContext.getEventArgs().preventDefaultOnError();
    Xrm.Navigation.openAlertDialog({
    text: "Current work order can't be saved because of canceled agreement"
    });
    return;

    }

    } else {
    // if rule1 is passed then check rule3
    var ruleThree= false;
    rule3(executionContext).then(function(data) {
    ruleThree = data;
    if (!ruleThree) {
    Xrm.Navigation.openAlertDialog({
    text: "current work order can't be closed because the incident type is visit and contains products!"
    });
    return;
    } else {
    isValidationNeeded = false;
    formContext.data.save().then(function() {
    alert("Form saved successfully");
    }, function(error) {
    var errorMessage = error.message;
    console.log(errorMessage);
    });
    }
    }, function(errorMessage) {
    Xrm.Navigation.openAlertDialog({
    text: errorMessage
    });
    });
    }
    }, function(errorMessage) {
    Xrm.Navigation.openAlertDialog({
    text: errorMessage
    });
    });
    }


    if (status === 690970003) {

    rule2(executionContext).then(function(data) {

    ruleTwo = data;
    if (!ruleTwo) {
    Xrm.Navigation.openAlertDialog({
    text: "current work order can't be closed because not all the service tasks are done"
    });
    return;
    } else {
    isValidationNeeded = false;
    formContext.data.save().then(function() {
    alert("Form saved successfully");
    }, function(error) {
    var errorMessage = error.message;
    console.log(errorMessage);
    });
    }
    }, function(errorMessage) {
    Xrm.Navigation.openAlertDialog({
    text: errorMessage
    });
    });
    }

    }
    }
    function rule1(executionContext) { // 1. Prevent the user to close posted the work order if the linked agreement is canceled.
    var formContext = executionContext.getFormContext();
    var agreement = formContext.getAttribute("msdyn_agreement").getValue();
    executionContext.getEventArgs().preventDefault();
    var promiseRule1 = new Promise(function(resolve, reject) {
    var boolRule1 = true;
    if (agreement != null && agreement.length > 0) {
    var id = agreement[0].id;
    var result = 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 because of Cancelled agreement"});
    boolRule1 = false;
    }
    resolve(boolRule1);
    },
    function(error) {
    //Xrm.Navigation.openAlertDialog({ text: error.message });
    reject(error.message);
    }
    );
    } else {
    resolve(boolRule1);
    }
    })
    return promiseRule1;
    }

    function rule2(executionContext) { //2.Prevent the user from completing the work order if not all the service tasks are done.
    executionContext.getEventArgs().preventDefault();
    var promiseRule2 = new Promise(function(resolve, reject) {

    var boolRule2 = true;
    var serviceTaskValidation = true;
    var formContext = executionContext.getFormContext();
    //get current WO id
    var workOrderId = formContext.data.entity.getId().replace("{", "").replace("}", "");
    //var valInc = formContext.getAttribute("msdyn_primaryincidenttype").getValue();
    var woStatus = formContext.getAttribute("msdyn_systemstatus").getValue();
    //close the WO or not
    //console.log(valInc);
    if (woStatus != null && woStatus === 690970003) { // If the System status is equal to Completed
    //get active related service task
    var result = 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 i = 0; i < result.entities.length; i++) {

    console.log(result.entities[i].msdyn_name);
    console.log(result.entities[i].msdyn_percentcomplete);

    if (result.entities[i].msdyn_percentcomplete != 100) {

    serviceTaskValidation = false;
    break;
    }
    }
    if (!serviceTaskValidation) {
    boolRule2 = false;
    }
    resolve(boolRule2);
    },
    function(error) {
    reject(error.message);
    }
    )
    }

    });
    return promiseRule2;
    }

    function rule3(executionContext){ // Prevent Closing WO if primary incident is visit and WO contains products

    executionContext.getEventArgs().preventDefault();

    var promiseRule3 = new Promise(function (resolve, reject) {
    var boolRule3 = true;
    var woProdValidation = true;
    var formContext = executionContext.getFormContext();
    var woID = formContext.data.entity.getId().replace("{", "").replace("}", "");
    var valInc = formContext.getAttribute("msdyn_primaryincidenttype").getValue();

    if(valInc != null && valInc.length >0){
    var name = valInc[0].name;
    if(name == "Visit"){
    var incType = result.msdyn_name;
    Xrm.WebApi.retrieveMultipleRecords("msdyn_workorderproduct","?$select=msdyn_name&$filter=msdyn_workorder/_msdyn_workorder_value eq " + woID).then(
    function success(result) {
    // perform operations on on retrieved records
    if(result.entities || result.entities.length === 0){
    alert("no data");
    }else{
    woProdValidation = false;
    }

    if (!woProdValidation) {
    boolRule3 = false;
    }
    resolve(boolRule3);
    },
    function (error) {
    reject(error.message);
    // handle error conditions
    }
    )
    }else{
    resolve(boolRule3);
    }
    }else{
    resolve(boolRule3);
    }
    });
    return promiseRule3;
    }

  • EBMRay Profile Picture
    EBMRay 873 on at
    RE: Plugin - Work Order OnUpdate Validation

    Dear   ,

    Thank you for providing the resources to check for save mode.

    I updated the code to check for the save mode and I started adding a new rule to our script that:

    Rule3:
    - Prevent the user from closing the work order if the incident type is visit and contains work order products. (workorderproduct grid rows >0)

    However, while testing rule1 & rule2 only I noticed an issue when you click the save button:

    The first time the button is clicked it throws the error which is expected. However, if you click the same button again after you close the popup of the dialog the form gets saved and skip the validation process.
    In addition, the error dialog does not appear at all when the button was pushed the second time.

    Below is proof of both rules:

    Rule1:

    AgreementRuleError.gif

    Rule 2:
    CompletedRuleError.gif

    Please find below the updated code:

    var isValidationNeeded = true;

    var SaveMode = {
        Save: 1,
        SaveAndClose: 2,
        SaveAndNew: 59,
        Autosave: 70
    };

    function preventSave(executionContext) {

    debugger;

     //getting save mode from event
     var saveMode = executionContext.getEventArgs().getSaveMode();

     //if savemode is not one of listed - just quit the execution and let the record to be saved
     if (saveMode !== SaveMode.Save &&
       saveMode !== SaveMode.SaveAndClose &&
       saveMode !== SaveMode.SaveAndNew &&
       saveMode !== SaveMode.Autosave) {
       return;
    }
        if (!isValidationNeeded) {
            isValidationNeeded = true;
            return;
        }

        var boolRule1 = false;
        var formContext = executionContext.getFormContext();
        var status = formContext.getAttribute("msdyn_systemstatus").getValue(); // getting the status the value

        console.log(status);
        // Completed Status
        // status is not close posted
        if (status === 690970004 || status === 690970003) {

            var ruleOne = false;
            var ruleTwo = false;

            if (status === 690970004) {
                rule1(executionContext).then(function(data) {
                    isValidationNeeded = false;
                    ruleOne = data;

                    if (!ruleOne) {

                        if (saveMode === SaveMode.Save || saveMode === SaveAndClose){
                           
                            executionContext.getEventArgs().preventDefaultOnError();
                            Xrm.Navigation.openAlertDialog({
                                text: "Current work order can't be saved because of canceled agreement"
                            });
                            return;
                       
                        }
                       
                    } else {

                        if (saveMode === SaveMode.Save || saveMode === SaveAndClose){

                            formContext.data.save().then(function() {
                                alert("Form saved successfully");
                            }, function(error) {
                                var errorMessage = error.message;
                                console.log(errorMessage);
                            });
                        }
                     
                    }
                }, function(errorMessage) {
                    Xrm.Navigation.openAlertDialog({
                        text: errorMessage
                    });
                });
            }


            if (status === 690970003) {

                rule2(executionContext).then(function(data) {
                    isValidationNeeded = false;
                    ruleTwo = data;
                    if (!ruleTwo) {
                        Xrm.Navigation.openAlertDialog({
                            text: "current work order can't be closed because not all the service tasks are done"
                        });
                        return;
                    } else {
                        alert(2);
                        formContext.data.save().then(function() {
                            alert("Form saved successfully");
                        }, function(error) {
                            var errorMessage = error.message;
                            console.log(errorMessage);
                        });
                    }
                }, function(errorMessage) {
                    Xrm.Navigation.openAlertDialog({
                        text: errorMessage
                    });
                });
            }

        }

        if(incType == "Visit"){

            var ruleThree= false;

            rule3(executionContext).then(function(data) {
                isValidationNeeded = false;
                ruleThree = data;
                if (!ruleThree) {
                    Xrm.Navigation.openAlertDialog({
                        text: "current work order can't be closed because the incident type is visit and contains products!"
                    });
                    return;
                } else {
                    alert(3);
                    formContext.data.save().then(function() {
                        alert("Form saved successfully");
                    }, function(error) {
                        var errorMessage = error.message;
                        console.log(errorMessage);
                    });
                }
            }, function(errorMessage) {
                Xrm.Navigation.openAlertDialog({
                    text: errorMessage
                });
            });

        }
    }
    function rule1(executionContext) { // 1. Prevent the user to close posted the work order if the linked agreement is canceled.
        var formContext = executionContext.getFormContext();
        var agreement = formContext.getAttribute("msdyn_agreement").getValue();
        executionContext.getEventArgs().preventDefault();
        var promiseRule1 = new Promise(function(resolve, reject) {
            var boolRule1 = true;
            if (agreement != null && agreement.length > 0) {
                var id = agreement[0].id;
                var result = 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 because of Cancelled agreement"});
                            boolRule1 = false;
                        }
                        resolve(boolRule1);
                    },
                    function(error) {
                        //Xrm.Navigation.openAlertDialog({ text: error.message });
                        reject(error.message);
                    }
                );
            } else {
                resolve(boolRule1);
            }
        })
        return promiseRule1;
    }

    function rule2(executionContext) { //2.Prevent the user from completing the work order if not all the service tasks are done.
        executionContext.getEventArgs().preventDefault();
        var promiseRule2 = new Promise(function(resolve, reject) {

            var boolRule2 = true;
            var serviceTaskValidation = true;
            var formContext = executionContext.getFormContext();
            //get current WO id
            var workOrderId = formContext.data.entity.getId().replace("{", "").replace("}", "");
            //var valInc = formContext.getAttribute("msdyn_primaryincidenttype").getValue();
            var woStatus = formContext.getAttribute("msdyn_systemstatus").getValue();
            //close the WO or not
            //console.log(valInc);
            if (woStatus != null && woStatus === 690970003) { // If the System status is equal to Completed
                //get active related service task
                var result = 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 i = 0; i < result.entities.length; i++) {

                            console.log(result.entities[i].msdyn_name);
                            console.log(result.entities[i].msdyn_percentcomplete);

                            if (result.entities[i].msdyn_percentcomplete != 100) {

                                serviceTaskValidation = false;
                                break;
                            }
                        }
                        if (!serviceTaskValidation) {
                            boolRule2 = false;
                        }
                        resolve(boolRule2);
                    },
                    function(error) {
                        reject(error.message);
                    }
                )
            }

        });
        return promiseRule2;
    }

    function rule3(executionContext){ // Prevent Closing WO if primary incident is visit and WO contains products

        executionContext.getEventArgs().preventDefault();

        var promiseRule3 = new Promise(function (resolve, reject) {
        var boolRule3 = true;
        var woProdValidation = true;
        var formContext = executionContext.getFormContext();
        var woID = formContext.data.entity.getId().replace("{", "").replace("}", "");
        var valInc = formContext.getAttribute("msdyn_primaryincidenttype").getValue();

        if(valInc != null && valInc.length >0){

            var id = valInc[0].id;
               
                Xrm.WebApi.retrieveRecord("msdyn_incidenttype",id,"?$select=msdyn_name").then(
                    function success(result){
                        alert(valInc);
                        if(result.msdyn_name == "Visit"){

                            var incType = result.msdyn_name;

                      Xrm.WebApi.retrieveMultipleRecords("msdyn_workorderproduct","?$select=msdyn_name&$filter=msdyn_workorder/_msdyn_workorder_value eq " + woID).then(
                      function success(result) {
                    // perform operations on on retrieved records
                    if(result.entities.length == 0){
                        alert("no data");
                        }else{
                        for (var i = 0; i < result.entities.length; i++) {

                                woProdValidation = false;
                                console.log(result.entities[i].msdyn_name);
                                break;
                }

                    if (!woProdValidation) {
                    boolRule3 = false;
                   
                }
                resolve(boolRule3);

        }

        },
        function (error) {
            reject(error.message);
            // handle error conditions
        }
            );
        }

        },function (error){
            Xrm.Navigation.openAlertDialog({ text: error.message });
        // handle error conditions
        }
        );
            }
        });
        return promiseRule3;
    }


    Therefore, could you please check the rule3 logic? Rule3 is checking a different field (Primary Incident Type == visit) in the form and not the system status so the question of what might happen if the user saves the form and rule1 was not valid as well as rule3 was not valid? It will throw two error dialogs?

    What are the changes that should be done in the code to avoid those issues? Could you please provide the updated version?

    Looking forward to your response.

    Thank you!

  • Suggested answer
    Community Member Profile Picture
    Community Member Microsoft Employee on at
    RE: Plugin - Work Order OnUpdate Validation

    Hi EBMRay,

    This should be cased by different save mode, please refer to the API docs:

    https://docs.microsoft.com/en-us/powerapps/developer/model-driven-apps/clientapi/reference/save-event-arguments/getsavemode

    You can refer to this blog to try it yourself first:

    https://butenko.pro/2018/11/15/cancelling-save-based-on-the-result-of-async-operation/

    If you still have this problem, please phase your code here and I will test it and update.

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

December Spotlight Star - Muhammad Affan

Congratulations to a top community star!

Top 10 leaders for November!

Congratulations to our November super stars!

Tips for Writing Effective Suggested Answers

Best practices for providing successful forum answers ✍️

Leaderboard

#1
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 291,280 Super User 2024 Season 2

#2
Martin Dráb Profile Picture

Martin Dráb 230,235 Most Valuable Professional

#3
nmaenpaa Profile Picture

nmaenpaa 101,156

Leaderboard

Product updates

Dynamics 365 release plans