The Zurich release has arrived! Interested in new features and functionalities? Click here for more

Export PDF button Not working sometimes.

practicalin
Mega Contributor

Hello Everyone,

 

I have been facing an issue with a button "Export PDF".

I have a ui action calling out the script include to perform this action.

The same script include is being used by different ui actions as well.

The buttons is working sometimes, sometimes not clickable.

Sometimes its clickable and sometimes its not generating data.

 

Not sure whats wrong,

Will be pasting my script here.

Script Include:

var CustomExportPDF = Class.create();
CustomExportPDF.prototype = Object.extendsObject(AbstractAjaxProcessor, {

    getFieldsFromFormView2: function(_table, _view, _format) {

        var table = this.getParameter("sysparm_table_form") || _table;
        var view = this.getParameter("sysparm_view_form") || _view;
        var format = this.getParameter("sysparm_format_form") || _format;

        var r = (format == 'json') ? {} : [];
        var form_view = new GlideRecord("sys_ui_view");
        if (form_view.get("name", view)) {
            var section = new GlideRecord("sys_ui_section");
            section.addQuery("view", form_view.getUniqueValue());
            section.addQuery("name", table);
            section.query();
            while (section.next()) {
                var field = new GlideRecord("sys_ui_element");
                field.addQuery("sys_ui_section", section.getUniqueValue());
                field.orderBy("position");
                field.query();
                while (field.next()) {
                    switch (format) {
                        case "json":
                            r[field.element.getValue()] = {};
                            break;
                        default:
                            r.push(field.element.getValue());
                            break;
                    }
                }
            }
        }

        switch (format) {
            case "string":
                return r.toString();
            default:
                return r;
        }
    },

    getFieldsFromFormView: function(_table, _view, _format) {

        var table = this.getParameter("sysparm_table_form") || _table;
        var view = this.getParameter("sysparm_view_form") || _view;
        var format = this.getParameter("sysparm_format_form") || _format;

        // gs.info(table + " " + view)

        var r = (format == 'json') ? {} : [];
        var form_view = new GlideRecord("sys_ui_view");
        if (form_view.get("name", view)) {
            var form_container = new GlideRecord("sys_ui_form");
            form_container.addQuery("view", form_view.getUniqueValue());
            form_container.addQuery("name", table);
            form_container.addNullQuery("sys_user");
            form_container.setLimit(1);
            form_container.query();
            gs.log("sys_ui_form query: " + form_container.getEncodedQuery(), "Export PDF - ITSM");
            while (form_container.next()) {
                var form_container_section = new GlideRecord("sys_ui_form_section");
                form_container_section.addQuery("sys_ui_form", form_container.getUniqueValue());
                form_container_section.orderBy("position");
                form_container_section.query();
                while (form_container_section.next()) {
                    var section = new GlideRecord("sys_ui_section");
                    if (section.get(form_container_section.sys_ui_section + '')) {
                        var field = new GlideRecord("sys_ui_element");
                        field.addQuery("sys_ui_section", section.getUniqueValue());
                        field.orderBy("position");
                        field.query();
                        while (field.next()) {
                            switch (format) {
                                case "json":
                                    r[field.element.getValue()] = {};
                                    break;
                                default:
                                    r.push(field.element.getValue());
                                    break;
                            }
                        }
                        switch (format) {
                            case "json":
                            default:
                                r.push(".end_section");
                                break;
                        }
                    }
                }
            }
        }
        // gs.log("fields: " + r, "Export PDF - ITSM")
        switch (format) {
            case "string":
                return r.toString();
            default:
                return r;
        }
    },

    getRelatedListsFromFormView: function(_table, _view) {

        var table = this.getParameter("sysparm_table_form") || _table;
        var view = this.getParameter("sysparm_view_form") || _view;
        var r = [];

        var form_view = new GlideRecord("sys_ui_view");
        if (form_view.get("name", view)) {
            var related_list = new GlideRecord("sys_ui_related_list");
            related_list.addQuery("view", form_view.getUniqueValue());
            related_list.addQuery("name", table);
            related_list.query();
            if (related_list.next()) {
                var related_list_entry = new GlideRecord("sys_ui_related_list_entry");
                related_list_entry.addQuery("list_id", related_list.getUniqueValue())
                related_list_entry.addQuery("related_list", "DOES NOT CONTAIN", "REL:");
                related_list_entry.orderBy("position");
                related_list_entry.query();
                while (related_list_entry.next()) {
                    r.push(related_list_entry.related_list.getValue());
                }

            }
        }

        return r;
    },

    getFieldsFromListView: function(table, view, parentTable, user) {
        var r = [];
        var form_view = new GlideRecord("sys_ui_view");
        if (form_view.get("name", view)) {

            var user_view = this.getviewForUser(table, view, parentTable, user, form_view.getUniqueValue());

            if (!user_view.hasNext()) {
                user_view = this.getviewForUser(table, view, parentTable, "", form_view.getUniqueValue());
                if (!user_view.hasNext()) {
                    user_view = this.getviewForUser(table, view, "", user, form_view.getUniqueValue());
                    if (!user_view.hasNext()) {
                        user_view = this.getviewForUser(table, view, "", "", form_view.getUniqueValue());
                        user_view.next();
                    } else {
                        user_view.next();
                    }
                } else {
                    user_view.next();
                }
            } else {
                user_view.next();
            }
            //return user_view.getUniqueValue()
            var list_element = new GlideRecord("sys_ui_list_element");
            list_element.addQuery("list_id", user_view.getUniqueValue());
            list_element.orderBy("position");
            list_element.query();
            while (list_element.next()) {
                r.push(list_element.element.getValue())
            }
        }
        return r;
    },

    getviewForUser: function(table, view, parentTable, user, viewId) {
        var sys_ui_list = new GlideRecord("sys_ui_list");
        sys_ui_list.addQuery("name", table);

        if (parentTable)
            sys_ui_list.addQuery("parent", parentTable);
        else
            sys_ui_list.addNullQuery("parent");
        if (user)
            sys_ui_list.addQuery("sys_user", user);
        else
            sys_ui_list.addNullQuery("sys_user");

        sys_ui_list.addQuery("view", viewId);
        sys_ui_list.setLimit(1);
        sys_ui_list.query();
        return sys_ui_list;
    },

    fontFamilyArial: function() {
        return gs.getProperty("hc.itms.font_family.arial.sys_id");
    },

    pdfTemplateUIPage: function() {
        return gs.getProperty("hc.itms.ui_page.pdf_template.sys_id");
    },

    isValidSysId: function(sysId) {
        // Check if the sys_id is exactly 32 characters long
        if (sysId.length !== 32) {
            return false;
        }

        // Check if the sys_id contains only hexadecimal characters (0-9, a-f, A-F)
        var regex = /^[0-9a-fA-F]{32}$/;
        return regex.test(sysId);
    },

    generatePDF: function(_table, _view, _sysId) {
        var table = this.getParameter("sysparm_table_form") || _table;
        var view = _view || this.getParameter("sysparm_view_form") || "";
        var sysId = this.getParameter("sysparm_format_sysId") || _sysId;
        var format = "string";

        gs.log("Table " + table + "  " + "View " + view + ' ' + 'sysID ' + sysId, 'pdfSource');

        var target = new GlideRecord(table);
        target.get(sysId);

        var fields = this.getFieldsFromFormView(table, view, format);
        fields = fields.split(",");
        gs.log("fields " + fields, 'pdfSource');

        var row = "";
        var globalBody = "";

        var displays1 = [];
        var displays2 = [];
        var displaysglobal = [];

        var isInSplit = false;
        var colspanValue = 1;
        var auxDisplays = [];

        var fieldsCount = fields.length;

        var not_allowed_fields = ["com_glideapp_servicecatalog_veditor", "activity.xml", "sc_req_item_delivery_plan.xml", "cxs_table_search.xml", "attached_knowledge"];
        // gs.info("FIELDS : " + fields)

        for (var i = 0; i < fieldsCount; i++) {
            gs.log("fieldscount  " + fieldsCount, 'pdfSource');


            if (fields[i] == ".begin_split") {
                gs.log("insideif  ", 'pdfSource');
                if (i > 0) {
                    displays1 = auxDisplays
                    globalBody += this.generateHTMLSection(target, displays1, [], isInSplit)
                    gs.log("1 - globalBody : " + globalBody, "Export PDF - ITSM")

                    displays1 = [];
                    displays2 = [];
                    auxDisplays = [];
                }


                isInSplit = true;
                continue
            }

            if (fields[i] == ".split") {

                gs.print(
                    "[ES SPLIT1]\n" +
                    displays1.toString() + "\n" +
                    auxDisplays.toString() + "\n" +
                    "[ES SPLIT1]"
                );

                isInSplit = true;
                displays1 = auxDisplays
                auxDisplays = [];

                gs.print(
                    "\n[ES SPLIT2]\n" +
                    "1-->" + displays1.toString() + "\n" +
                    "2-->" + auxDisplays.toString() + "\n" +
                    "3-->fieldsCount:" + fieldsCount + " -->" + i + "\n" +
                    "[ES SPLIT2]"
                );

                continue;
            }

            if (fields[i] == ".end_split") {
                displays2 = auxDisplays
                globalBody += this.generateHTMLSection(target, displays1, displays2, isInSplit);
                // gs.log("2 - globalBody : " + globalBody, "Export PDF - ITSM")

                displays1 = [];
                displays2 = [];
                auxDisplays = [];

                isInSplit = false;

                continue;
            }

            if (fields[i] == ".end_section") {
                if (isInSplit)
                    displays2 = auxDisplays;
                else
                    displays1 = auxDisplays;


                globalBody += this.generateHTMLSection(target, displays1, displays2, isInSplit);
                // gs.log("3 - globalBody : " + globalBody, "Export PDF - ITSM")

                displays1 = [];
                displays2 = [];
                auxDisplays = [];
                isInSplit = false;
                continue
            }


            if (this.isValidSysId(fields[i]))
                continue;

            if (not_allowed_fields.indexOf(fields[i]) == -1)
                auxDisplays.push(fields[i]);

            if ((fieldsCount - 1) == i) {
                if (isInSplit)
                    displays2 = auxDisplays;
                else
                    displays1 = auxDisplays;
                globalBody += this.generateHTMLSection(target, displays1, displays2, isInSplit)
            }

        }

        var pdfGenerator = new sn_pdfgeneratorutils.PDFGenerationAPI;
        var pageProperties = {
            "PageSize": "LETTER",
            "PageOrientation": 'PORTRAIT',
            "TopOrBottomMargin": "36",
            "LeftOrRightMargin": "24",
            "GeneratePageNumber": "false",
            "fontFamilySysId": this.fontFamilyArial(),
        };

        var modifiedHTML = "";
        var ui_page_template = new GlideRecord("sys_ui_page");
        ui_page_template.get(this.pdfTemplateUIPage());
        modifiedHTML = ui_page_template.html.getValue().toString();
        var tableLabel = target.getClassDisplayValue();
        var tableName = target.getTableName();
        var stats = {
            "title": tableLabel + " Details",
            "datetime": new GlideDateTime() + " " + gs.getSession().getTimeZoneName(),
            "runby": gs.getUserDisplayName(),
            "tablename": tableName
        };

        var attachmentsHTML = this.getAttachmentsHTML(target);
        var related_listHTML = "";

        var related_lists = this.getRelatedListsFromFormView(target.getTableName(), view, target.getUniqueValue());
        var related_lists_info = this.getRelatedListInfo(target, related_lists, view);

        for (var related_list in related_lists_info) {
            var current_rl = related_lists_info[related_list];
            var current_fields = current_rl.fields;

            if (current_rl.data.length == 0)
                continue

            var headers = "";
            var rows = "";
            for (var i = 0; i < current_rl.labels.length; i++) {
                headers += (
                    "<th class='form-title'  >" + (i == 0 ? "&#8593;" : "") + current_rl.labels[i] + "</th>"
                );
            }
            for (var i = 0; i < current_rl.data.length; i++) {
                var row = "";
                for (var j = 0; j < current_fields.length; j++) {
                    row += (
                        "<td>" + current_rl.data[i][current_fields[j]] + "</td>"
                    );
                }
                rows += "<tr " + ((i % 2) == 1 ? "style='background-color:#eee;'" : "") + " >" + row + "</tr>";
            }
            related_listHTML += (
                "<table class='stats'>" +
                "<tbody>" +
                "<tr>" +
                "<td class='font-weight-bold' colspan='1'> Table: </td>" +
                "<td> " + related_lists_info[related_list].table + "(" + related_list + ") </td>" +
                "</tr>" +
                "<tr>" +
                "<td class='font-weight-bold' colspan='1'> Query condition: </td>" +
                "<td> " + related_lists_info[related_list].query + " </td>" +
                "</tr>" +
                "<tr>" +
                "<td class='font-weight-bold' colspan='1'> Sort order: </td>" +
                "<td> " + related_lists_info[related_list].order + " </td>" +
                "</tr>" +
                "</tbody>" +
                "</table>" +

                "<table class='table'>" +
                "<thead>" +
                "<tr>" + headers + "</tr>" +
                "</thead>" +
                "<tbody>" +
                rows +
                "</tbody>" +
                "</table><br/>"
            );
        }


        modifiedHTML = modifiedHTML.
        replaceAll("$body_string$", globalBody).
        replaceAll("$form_title$", tableLabel + " - " + target.getDisplayValue()).
        replaceAll("$attachments$", attachmentsHTML).
        replaceAll("$related_list$", related_listHTML).
        replaceAll("$email_chain_html$", this.getEmailsHTML(sysId));
        for (var key in stats) {
            modifiedHTML = modifiedHTML.replaceAll("$stats." + key + "$", stats[key]);
        }

        // gs.log( "modifiedHTML: " + modifiedHTML, "Export PDF - ITSM");
        var newModifiedHTML = this.replaceIixImageSources(modifiedHTML);

        // gs.log( "newModifiedHTML: " + newModifiedHTML, "Export PDF - ITSM");

        var result = pdfGenerator.convertToPDF(newModifiedHTML, table, sysId, tableLabel + " - " + target.getDisplayValue(), this.fontFamilyArial());
        return JSON.stringify(result);
        //return modifiedHTML;
    },
    deletePDF: function(_attachment_id) {
        var attachment_id = this.getParameter("sysparm_attachment_id") || _attachment_id;
        var att = new GlideRecord("sys_attachment");
        if (att.get(attachment_id))
            att.deleteRecord();

    },
    getRelatedListInfo: function(target, related_lists, view) {
        var r = {};
        for (var i = 0; i < related_lists.length; i++) {



            var rlist_info = related_lists[i].split(".");
            var table = rlist_info[0];
            var fieldForQuery = rlist_info[1];
            var queryDisplay = "";
            var sortDisplay = "";
            var query = fieldForQuery + "=" + target.getUniqueValue();
            var fields = this.getFieldsFromListView(table, view, target.getTableName(), gs.getUserID());
            if (view && fields.length == 0)
                fields = this.getFieldsFromListView(table, "", target.getTableName(), gs.getUserID());

            gs.print("[RELATED LIST]: " + table + " - " + fields + " -> " + view)

            var fieldsDisplay = [];
            var data = [];
            var rl = new GlideRecord(table);
            rl.addEncodedQuery(query);
            rl.orderBy(fields[0]);
            rl.query();
            var recour_counter = 0;
            while (rl.next()) {
                if (!queryDisplay)
                    queryDisplay = rl.getElement(fieldForQuery).getLabel() + "=" + target.getDisplayValue();
                if (!sortDisplay)
                    sortDisplay = rl.getElement(fields[0]).getLabel() + " in ascending order";

                var obj = {};
                for (var j = 0; j < fields.length; j++) {
                    obj[fields[j]] = rl.getElement(fields[j]).getDisplayValue();
                    if (recour_counter == 0)
                        fieldsDisplay.push(rl.getElement(fields[j]).getLabel())
                }
                recour_counter++;
                data.push(obj)
            }
            r[table] = {
                "table": rl.getClassDisplayValue(),
                "query": queryDisplay,
                "order": sortDisplay,
                "data": data,
                "fields": fields,
                "labels": fieldsDisplay,
            }
        }
        return r;
    },
    generateHTMLSection: function(target, col1, col2, separated) {
        var arrayUtil = new global.ArrayUtil();
        var checkfields;

        var joiner = gs.getProperty("hc.itsm.joiner.fields");
        joiner = joiner.split(",");

        var leaver = gs.getProperty("hc.itsm.leaver.fields");
        leaver = leaver.split(",");

        var orderguide = gs.getProperty("hc.itsm.order_guide.fields");
        orderguide = orderguide.split(",");

        var mover = gs.getProperty("hc.itsm.mover.fields");
        mover = mover.split(",");

        var category = target.getElement("u_employee_movement_category");
        if (category == "leaver") {
            col1 = arrayUtil.diff(col1, joiner);
            col1 = arrayUtil.diff(col1, mover);
        } else if (category == "joiner") {
            col1 = arrayUtil.diff(col1, leaver);
            col1 = arrayUtil.diff(col1, mover);
        } else if (!category) {
            col1 = arrayUtil.diff(col1, joiner);
            col1 = arrayUtil.diff(col1, leaver);
            col1 = arrayUtil.diff(col1, mover);
            col1 = arrayUtil.diff(col1, orderguide);
        }
        var maxLength;
        if (col1.length > col2.length)
            maxLength = col1.length;
        else
            maxLength = col2.length;
        var colspanValue = separated ? "1" : "3";
        var row = "";

        for (var i = 0; i < maxLength; i++) {
            row += "<tr>";
            if (col1[i]) {
                if (!target.getElement(col1[i])) {
                    gs.print("A >>> " + col1[i])
                }

                row += (
                    "<td class='form-label' colspan='1' > " + target.getElement(col1[i]).getLabel() + " </td>" +
                    "<td class='form-value' colspan='" + colspanValue + "' > <div style='max-width:675px;'> " + target.getElement(col1[i]).getDisplayValue() + "</div> </td>"
                );
            } else {
                row += (
                    "<td colspan='1'></td> <td colspan='1'></td>"
                );
            }

            if (separated && col2[i]) {
                row += (
                    "<td class='form-label' colspan='1' > " + target.getElement(col2[i]).getLabel() + " </td>" +
                    "<td class='form-value' colspan='" + colspanValue + "' > <div> " + target.getElement(col2[i]).getDisplayValue() + "</div> </td>"
                );
            }
            row += "</tr>";
        }
        return row;
    },

    getAttachmentsHTML: function(target) {
        var r = "";
        var attachmentAPI = new GlideSysAttachment();
        var attachment = attachmentAPI.getAttachments(target.getTableName(), target.getUniqueValue());
        while (attachment.next()) {
            if (attachment.content_type.getValue().indexOf("image") > -1) {
                r += (
                    "<div> <img src='" + this.getAttachmentBase64(attachment) + "' /> <br> <span>" + attachment.file_name.getValue() + "</span></div>"
                );
            } else {
                r += (
                    "<div style='width:100%;'><span>" + attachment.file_name.getValue() + "</span></div>"
                );
            }



        }
        return r;
    },

    getAttachmentBase64: function(attachmentGR) {
        var base64ImageStr = GlideStringUtil.base64Encode(
            new GlideSysAttachment().getBytes(attachmentGR)
        );
        return "data&colon;image/png;base64," + base64ImageStr + "";
    },

    getEmailsHTML: function(targetID) {
        var emails = new GlideRecord("sys_email");
        emails.addEncodedQuery("instance=" + targetID + "^headersLIKEX-ServiceNow-Source:EmailClient^type=sent^NQinstance=" + targetID + "^type=received^ORDERBYsys_created_on");
        emails.query();
        var response = "";
        while (emails.next()) {
            response += (
                "<div class='email_container_iterator' >" +
                "<b>Subject: </b>" + emails.subject + "<br>" +
                "<b>To: </b>" + emails.direct + "<br>" +
                "<b>CC: </b>" + emails.copied + "<br>" +
                "<b>Attachments: </b>" + this.getAttachmentsName(emails.getUniqueValue()) + "<br>" +
                emails.body + "\n" +
                "</div>"
            );
        }
        return response;
    },

    getAttachmentsName: function(emailID) {
        var r = [];
        var sys_email_attachment = new global.TicketCaseEmailUtils().getList(
            "sys_email_attachment",
            "email=" + emailID + "^content_disposition=attachment"
        );
        while (sys_email_attachment.next()) {
            r.push(sys_email_attachment.file_name + '');
        }
        return r.toString()
    },

    /**
     * Processes a raw HTML string, finds <img> tags with src="/[sys_id].iix",
     * and replaces them with src="/sys_attachment.do?sys_id=[sys_id]".
     *
     * @Param {string} htmlString - The HTML content to process.
     * @returns {string} - The updated HTML with fixed <img> src values.
     */
    replaceIixImageSources: function(htmlString) {
        // Define the regex pattern to match "/[sys_id].iix"
        var regex = /src="\/([a-f0-9]{32})\.iix"/gi;

        return htmlString.replace(regex, (match, sysId) => {
            return `src="/sys_attachment.do?sys_id=${sysId}"`;
        });
    },

    type: 'CustomExportPDF'
});
4 REPLIES 4

KrishnaMohan
Giga Sage

Hi @practicalin 


Could you provide the use case or what is your requirement? 

 

Regards,
Krishnamohan

Hello Krishna,

 

Thanks for the response.

The Export Button is working fine on my browsers. (All browsers including Edge).

 

But when one of the user clicks on this button on a REQ or RITM (this can be random) the pdf is getting generated with empty pdf. No data.

 

When i impersonate and do it, it is working fine from my browsers.

He is able to export 9 out of 10. And that 1 ticket which he is not able to open can be any random ticket.

 

 

Hello @KrishnaMohan 

 

User is able to export 9 out of 10 tickets. But that 1 ticket is not exporting will data, its giving empty PDF.

But when i impersonate and do its good on my end.

User cant use any browser other than edge. 

Ankur Bawiskar
Tera Patron
Tera Patron

@practicalin 

why so much customization?

what's your exact business requirement?

Sometimes you can achieve your requirement with OOTB feature.

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader