Announcements
Hello,
I have two JS codes that trigger the onSave event of the Work Order form. Each script includes some logic to validate the data before saving the work order, including Web API calls from different tables, and I have no problems with either script.
However, when I press the Save button on the form, I got the following error message, and the form does not save from the first attempt:
The form will be saved successfully on the second attempt. This error causes confusion for the end-user, who thinks the form has been saved.
Code 1:
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(); var formContext = executionContext.getFormContext(); var formType = formContext.ui.getFormType(); console.log(formType); // let flagtosave = false; if(formType !== 1){ //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 ruleThree = false; rule3(executionContext).then(function(data) { ruleThree = data; if (!ruleThree) { if (saveMode === SaveMode.Save || saveMode === 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 it's linked to canceled agreement!" }); return; } } else { isValidationNeeded = false; // flagtosave= true; Xrm.Page.data.entity.save().then(function() { }, 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; // flagtosave = true; Xrm.Page.data.entity.save().then(function() { }, function(error) { var errorMessage = error.message; console.log(errorMessage); }); } }, function(errorMessage) { Xrm.Navigation.openAlertDialog({ text: errorMessage }); }); } } else { isValidationNeeded = false; console.log(preventEventSave); // setTimeout(()=> { if (preventEventSave) { Xrm.Page.data.entity.save().then(function() { }, function(error) { var errorMessage = error.message; console.log(errorMessage); }); } // }, 1000); } } }, function(errorMessage) { Xrm.Navigation.openAlertDialog({ text: errorMessage }); }); } // if(flagtosave){ // setTimeout(()=> { // }, 600); // } // else{ // try{ // // }catch(e){ // console.log(e); // } // } // executionContext.getEventArgs().preventDefault(); } // if rule1 is passed then check rule3 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(); 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. 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(); var woType = formContext.getAttribute("msdyn_workordertype").getValue(); //close the WO or not //console.log(valInc); if (woType != null && woType.length > 0) { var woTypeName = woType[0].name; } if (woStatus != null && woStatus === 690970003 && woTypeName === "Installation" ) { // If the System status is equal to Completed //get active related service task Xrm.WebApi.retrieveMultipleRecords("msdyn_workorderservicetask", "?$select=msdyn_name,msdyn_percentcomplete,statecode,haceb_responsevalueyesno&$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); console.log(result.entities[i].haceb_responsevalueyesno); if (result.entities[i].haceb_responsevalueyesno == false) { serviceTaskValidation = false; break; } } if (!serviceTaskValidation) { boolRule2 = false; } resolve(boolRule2); }, function(error) { reject(error.message); } ) }else{ resolve(boolRule2); } }); 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") { 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 { } 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; }
Code 2:
var WorkOrderForm = (function () { var SaveMode = { Save: 1, SaveAndClose: 2, SaveAndNew: 59, Autosave: 70, }; //this is variable that shows if validation was successfully passed or not var isValidationNeeded = true; function OnSave(executionContext) { // let flagtosave= false; //so if there are several save handlers and one of previous already called preventDefault //there is no need to do any validations anymore if (executionContext.getEventArgs().isDefaultPrevented()) { return; } //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; } //so if validation was successfully passed - flag is reset //and code just leaves the form alone and allows changes to be saved if (!isValidationNeeded) { isValidationNeeded = true; return; } //getting of the form context from execution context object //@ts-ignore var formContext = executionContext.getFormContext(); //getting of "Account Number" value from field var worktype = formContext.getAttribute("msdyn_workordertype").getValue(); let status = formContext.getAttribute("msdyn_systemstatus").getValue(); console.log("status", status); let id = formContext.data.entity.getId(); console.log("id", id); if (status === "690970004" || 690970004) { Xrm.WebApi.retrieveMultipleRecords( "haceb_assetdetail", `?$filter=(_haceb_workorder_value eq ${id.slice(1, id.length-1).toUpperCase()})` ).then( function success(result) { if (result.entities.length > 1) { Xrm.Navigation.openAlertDialog({ confirmButtonLabel: "Close", text: "You can't save because you are only allowed to have 1 panel reading, delete the other one in order to save.", title: "Error Message", }); } // perform additional operations on retrieved records }, function (error) { console.log(error.message); // handle error conditions } ); } //if field is blank there is no need to do any checks - code just leaves form if (worktype !== null) { console.log("workordertype ", worktype); if (worktype[0].name !== "Site inspection") { let serviceAccount = formContext .getAttribute("msdyn_serviceaccount") .getValue(); if (serviceAccount !== null) { let asset = formContext.getAttribute("msdyn_customerasset"); if (asset.getValue() === null) { //@ts-ignore Xrm.Navigation.openAlertDialog({ title: "Validation Message", confirmButtonLabel: "Close", text: `Please make sure the ${serviceAccount[0].name} has a customer asset. Otherwise, please create your WO from the customer asset table or the sub-grid from the account.`, }); } else { // flagtosave= true; isValidationNeeded = false; if (saveMode === SaveMode.Save || saveMode === SaveMode.Autosave) { formContext.data.entity.save(); } else if (saveMode === SaveMode.SaveAndClose) { formContext.data.entity.save("saveandclose"); } else { formContext.data.entity.save("saveandnew"); } // }, 1000); } //@ts-ignore } else { // raise error ... //@ts-ignore Xrm.Navigation.openAlertDialog({ title: "Validation Message", confirmButtonLabel: "Close", text: "The OW not have service account.", }); } } else { isValidationNeeded = false; if (saveMode === SaveMode.Save || saveMode === SaveMode.Autosave) { formContext.data.entity.save(); } else if (saveMode === SaveMode.SaveAndClose) { formContext.data.entity.save("saveandclose"); } else { formContext.data.entity.save("saveandnew"); } } // if(flagtosave){ // // setTimeout(()=> { // // // setTimeout(()=> { // // //and save event is called again // // } // // }, 600); // } // else{ // try{ executionContext.getEventArgs().preventDefault(); // }catch(e){ // console.log(e); // } // } } //preventing of the save operation before async operation is started } return { OnSave: OnSave, }; })();
I believe I am getting the above error because of the multiple async events for the API calls inside both of the scripts.
What will be the updated code for both of them to handle and solve this issue?
I would highly appreciate your input and any help is highly appreciated.
Thank you,
EBMRay
Hi EBMRay,
This error is caused by that you save the form's data again when it is saving. In your case, both Code1 and Code2 execute the form.data.save() function which leads to this error.
The best practise is that merge two code and execute Code2 after Code1 is succeed.
Hi ,
Thank you for your reply.
I disabled Code 2 that I provided on the main post and tried to save a work order and as a result, the "Save in progress" disappeared.
It seems that the issue is from code 2 because when I execute the save and Code 1 is enabled I don't get this message.
What are the changes that should be applied to handle the async operation and make it work as Code 1 without doing the merge? Or the merge is recommended to make it work?
Awaiting your response.
Best regards,
EBMRay
Hi EBMRay,
Please check if both of them can execute independently(Disable one event to run another one).
If so, you need to merge the two events to one. And then click your button to try again.
André Arnaud de Cal... 291,359 Super User 2024 Season 2
Martin Dráb 230,370 Most Valuable Professional
nmaenpaa 101,156