This widget could not be displayed.
This widget could not be displayed.

Unexpected 'Approved' UI action button behavior

Maxwell3
Kilo Guru

Hello all,

 

I am wondering is this has ever happened to anyone and how to fix it if it has?

I have a custom 'Approve' button, and the top one behaves differently than the bottom one sometimes, this is only happening in Prod and not the other lower environments. I have not been able to re-create the issue in DEV or Test. Sometimes the top Approve button will not do anything when clicked on, so the users will click on the bottom one then it creates a blank record. This UI action is only supposed to set the record to "Approved" pending certain conditions, or else it displays an error message and then nothing else is supposed to happen.

 

Here is the UI configuration:

 

Maxwell3_0-1748634403061.png

Here is the script:

 

function approve_request() {

   
    if ((g_form.getValue("u_type_of_request") == 'local')
||(g_form.getValue("u_type_of_request") == 'longdistance')) {
   
        var trec = new GlideAjax('LookUp');
            trec.addParam('sysparm_name', 'checkAttachment');
            trec.addParam('sysparm_remsysid', g_form.getUniqueValue());
            //trec.addParam('sysparm_created_by', g_user.userName);
            trec.getXMLAnswer(_handleResponse);    
        function _handleResponse(response) {
                var answer1 = response;
                if (answer1 == 'false'){
                    g_form.addErrorMessage("This cannot be submitted for approval without an attached Document.");
                    return false;
                   
                } else  {
                    if ((g_form.getValue("u_form_attached") == 'Yes') && (g_form.getValue("u_certificate_attached") == "Yes")){        
                        gsftSubmit(null, g_form.getFormElement(), 'approve_');
                       
                    }
                    else {
                        alert("All attachment questions have to be answered 'Yes' to approve");
                        return false;
                    }
                }
   
            }      
    }  
       
   

   
    var treq = new GlideAjax('LookUp');
        treq.addParam('sysparm_name', 'CheckCert');
        treq.addParam('sysparm_certuserid', g_form.getValue('u_employee'));
        treq.getXMLAnswer(doExtendedParsetele1);
        function doExtendedParsetele1(response){
        var answer = response;
        if (answer == 'false'){
alert("Please submit a Certification request. A Certification request must be submitted before your supervisor can approve request. ");
   
        return false;  
                }
            else
            gsftSubmit(null, g_form.getFormElement(), 'approve_');  
                   
            }
   
   
}

   

if (typeof window == 'undefined')
   approve();


function approve() {
   
    current.u_state = '31';
    var effect_date = current.u_effective_date;
    var app_date = new GlideDate();
    current.approval_date = app_date;
    var sched = current.u_type_of_request;
    //Check if effective date is not null, if its not set expiry date based on that.

    if (effect_date == '' || effect_date <= app_date) {
            var edate = new GlideDate();
        //create Expiration date object
            if (effect_date == ''){
                current.u_effective_date = edate;
                if (sched == 'Co' || sched == 'Ep'){
                    edate.addYearsUTC(1);
                    current.u_expiry_date = edate;

                }
            }
            else {
                var eff_date1 = new GlideDate();
                eff_date1.setValue(current.u_effective_date);
                if (sched == 'Co' || sched == 'Ep'){
                    eff_date1.addYearsUTC(1);
                    current.u_expiry_date = eff_date1;
                }

            }
            if (current.u_renewal == true){
        //look for record that is approved
            var tr = new GlideRecord('table_name');
                tr.addQuery('u_active', 'true');
                tr.addQuery('u_state', '31');
                tr.addQuery('u_employee',current.u_employee);
                tr.addQuery('u_renewal', 'false');
                tr.query();
               
                if (tr.next()){
                    //tr.setValue('u_state', '35');
                    //tr.setValue('u_active', 'false');
                    //tr.update();
                current.u_active = 'true';
                current.u_renewal = 'false';
                current.u_state = '50';

                }
                //current.u_active = 'true';
                //current.u_renewal = 'false';
            }
    } else {
        var eff_date = new GlideDate();
        eff_date.setValue(current.u_effective_date);
        if (sched == 'Co' || sched == 'Ep'){
            eff_date.addYearsUTC(1);
            current.u_expiry_date = eff_date;

            }

    }
    if (current.u_renewal == true){
   
        current.u_active = 'true';
        current.u_renewal = 'false';
        current.u_state = '50';

    }
        if (sched == 'loc' || sched == 'longdist' || sched == 'Temploc' || sched == 'Templong' || sched == 'Templocmili' || sched == 'Templongdist' || sched == 'Ep' || sched == 'Co' || sched == 'distrecord'){
        //look for record that is approved

        var rw = new GlideRecord('table_name');
                rw.addQuery('u_active', 'true');
                rw.addQuery('u_state', '31');
                rw.addQuery('u_employee',current.u_employee);
                rw.addQuery('u_renewal', 'false');
                rw.query();
               
                if (rw.next()){
                current.u_active = 'true';
                current.u_renewal = 'false';
                current.u_state = '50';

                }
            }
   
    current.update();
}
1 REPLY 1

SasiChanthati
Giga Guru

Looking at your code and configuration, I can identify a few potential issues:

  1. Duplicate UI Actions: You have two "Approve" buttons with the same name but potentially different configurations. This could cause confusion in the system.

  2. Conditional Logic Issues: Your approverequest() function has two separate conditional blocks that both can call gsftSubmit() with 'approve' action, but they're not mutually exclusive. This could lead to unpredictable behavior.

  3. Environment-Specific Issue: Since this only happens in Production and not in lower environments, it could be related to:

    • Different user permissions in Production
    • Caching issues in the Production environment
    • Different data in Production triggering edge cases in your code

Here are some suggestions to fix the issue:

  1. Consolidate the UI Actions: Instead of having two separate "Approve" buttons, consider having just one.

  2. Fix the JavaScript Logic: Your approve_request() function has two separate code paths that both can call gsftSubmit(). You should restructure this to have a single, clear flow.

  3. Add Debug Logging: Add console.log() statements in your client script to see which path is being executed when users click the buttons.

  4. Check Browser Console: Have users check the browser console for JavaScript errors when the button doesn't work.

  5. Review the Server-Side Script: The approve() function seems to have complex logic for handling different scenarios. Make sure it's handling all cases correctly.

  6. Check for Form Validation: Ensure that any required fields are properly filled before the approve action is triggered.

  7. Review ACLs and Roles: Verify that users have the appropriate permissions in Production.

The main problems appear to be in the structure of your client-side script and how the two approval paths interact.

Here's a corrected version of your UI action script:

function approve_request() {
    // First check if we need to validate attachments based on request type
    if (g_form.getValue("u_type_of_request") == 'local' || 
        g_form.getValue("u_type_of_request") == 'longdistance') {
        
        // Check for attachments
        var trec = new GlideAjax('LookUp');
        trec.addParam('sysparm_name', 'checkAttachment');
        trec.addParam('sysparm_remsysid', g_form.getUniqueValue());
        trec.getXMLAnswer(function(response) {
            if (response == 'false') {
                g_form.addErrorMessage("This cannot be submitted for approval without an attached Document.");
                return;
            } else if (g_form.getValue("u_form_attached") != 'Yes' || 
                      g_form.getValue("u_certificate_attached") != "Yes") {
                alert("All attachment questions have to be answered 'Yes' to approve");
                return;
            } else {
                // If we passed attachment checks, now check certification
                checkCertification();
            }
        });
    } else {
        // If request type doesn't require attachment validation, go straight to certification check
        checkCertification();
    }
    
    // Function to check certification
    function checkCertification() {
        var treq = new GlideAjax('LookUp');
        treq.addParam('sysparm_name', 'CheckCert');
        treq.addParam('sysparm_certuserid', g_form.getValue('u_employee'));
        treq.getXMLAnswer(function(response) {
            if (response == 'false') {
                alert("Please submit a Certification request. A Certification request must be submitted before your supervisor can approve request.");
                return;
            } else {
                // All checks passed, submit the form for approval
                console.log("All validation passed, submitting approval");
                gsftSubmit(null, g_form.getFormElement(), 'approve_');
            }
        });
    }
}

// Server-side script
if (typeof window == 'undefined')
   approve();

function approve() {
    current.u_state = '31';
    var effect_date = current.u_effective_date;
    var app_date = new GlideDate();
    current.approval_date = app_date;
    var sched = current.u_type_of_request;
    
    // Handle effective and expiry dates
    if (effect_date == '' || effect_date <= app_date) {
        var edate = new GlideDate();
        
        if (effect_date == '') {
            current.u_effective_date = edate;
            if (sched == 'Co' || sched == 'Ep') {
                edate.addYearsUTC(1);
                current.u_expiry_date = edate;
            }
        } else {
            var eff_date1 = new GlideDate();
            eff_date1.setValue(current.u_effective_date);
            if (sched == 'Co' || sched == 'Ep') {
                eff_date1.addYearsUTC(1);
                current.u_expiry_date = eff_date1;
            }
        }
    } else {
        var eff_date = new GlideDate();
        eff_date.setValue(current.u_effective_date);
        if (sched == 'Co' || sched == 'Ep') {
            eff_date.addYearsUTC(1);
            current.u_expiry_date = eff_date;
        }
    }
    
    // Handle renewal cases
    if (current.u_renewal == true) {
        current.u_active = 'true';
        current.u_renewal = 'false';
        current.u_state = '50';
    }
    
    // Check for existing approved records
    if (sched == 'loc' || sched == 'longdist' || sched == 'Temploc' || 
        sched == 'Templong' || sched == 'Templocmili' || sched == 'Templongdist' || 
        sched == 'Ep' || sched == 'Co' || sched == 'distrecord') {
        
        var rw = new GlideRecord('table_name');
        rw.addQuery('u_active', 'true');
        rw.addQuery('u_state', '31');
        rw.addQuery('u_employee', current.u_employee);
        rw.addQuery('u_renewal', 'false');
        rw.query();
        
        if (rw.next()) {
            current.u_active = 'true';
            current.u_renewal = 'false';
            current.u_state = '50';
        }
    }
    
    current.update();
}

Key improvements:

  1. Sequential Validation: The client-side script now performs validations in a sequential manner, with the certification check only happening after attachment validation passes.

  2. Clearer Control Flow: Eliminated the confusing dual-path structure that could lead to multiple gsftSubmit() calls.

  3. Better Function Organization: Used nested functions to make the code more readable and maintainable.

  4. Added Console Logging: Added a console.log statement before submission to help with debugging.

For the UI configuration:

  1. Keep only one "Approve" button in your UI Action configuration to avoid confusion.
  2. Make sure the UI Action is properly configured with:
    • The correct client and/or server scripts
    • Appropriate conditions for when it should be visible/enabled
    • Proper form processing settings

This revised code should help eliminate the issues you're experiencing with the approve buttons behaving inconsistently.