Custom PDF generation

Ballela Siva Te
Tera Contributor

Hi Everyone,

We have a requirement where, when a RITM (Request Item) is submitted in ServiceNow, the computations will be done and some information will be sent via email and customized PDF attachment.

  • The PDF should have a header and other details populated with the computed information.

Question:
Is it possible to achieve this in ServiceNow? If yes, what would be the best approach or recommended practices to implement this?

4 REPLIES 4

Max4
Tera Contributor

Hi 

It is absolutely possible to develop this as a custom solution:

https://www.servicenow.com/docs/de-DE/bundle/yokohama-api-reference/page/app-store/dev_portal/API_re...


However, I would recommend considering this solution as well:
https://store.servicenow.com/store/app/52996b221b246a50a85b16db234bcb88

The ROI is reached very quickly, everything is fully managed, and it all runs entirely within ServiceNow. End users can also operate it easily.

If you have any questions, feel free to reach out anytime.

adityahubli
Tera Contributor

Hello @Ballela Siva Te ,

You can acheive this requirnment using flow designer and by creating custom action .

First create custom action which take  input as sys_id of your ritm record and create script action as i mentioned below 

adityahubli_0-1764690604587.png       

adityahubli_2-1764690903135.pngadityahubli_3-1764690926518.pngadityahubli_4-1764691044195.pngadityahubli_5-1764691064432.png

 

 

Code snippet : 

(function execute(inputs, outputs) {

    var v = new sn_pdfgeneratorutils.PDFGenerationAPI();
    var html = '';

    var gr = new GlideRecord('sc_req_item');
    if (!gr.get(inputs.id)) {
        gs.addErrorMessage('Requested Item not found for id: ' + inputs.id);
        outputs.flag = 0;
        return;
    }

    // Safely read variables (avoid null errors)
    var laptopModel = gr.variables.laptop_model ? gr.variables.laptop_model.toString() : '';
    var type = gr.variables.type ? gr.variables.type.toString() : '';

    // Build HTML with header + styling
    html += '<html>';
    html += '<head>';
    html += '<meta charset="utf-8" />';
    html += '<style>';
    html += 'body { font-family: Arial, sans-serif; font-size: 12px; color: #333; }';
    html += '.header { text-align: center; font-size: 20px; font-weight: bold;';
    html += '         padding: 10px 0; border-bottom: 2px solid #444; margin-bottom: 20px; }';
    html += '.sub-header { text-align: center; font-size: 11px; color: #777;';
    html += '             margin-top: -10px; margin-bottom: 20px; }';
    html += '.meta-table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }';
    html += '.meta-table th, .meta-table td { padding: 6px 8px; border: 1px solid #ccc; text-align: left; }';
    html += '.meta-table th { background: #f2f2f2; font-weight: bold; }';
    html += '.section-title { font-size: 14px; font-weight: bold; margin: 10px 0 5px 0; }';
    html += '.section-box { border: 1px solid #ccc; padding: 8px; min-height: 30px; }';
    html += '</style>';
    html += '</head>';
    html += '<body>';

    // Header
    html += '<div class="header">Requested Item Summary</div>';
    html += '<div class="sub-header">Generated from ServiceNow</div>';

    // Basic details
    html += '<table class="meta-table">';
    html += '<tr><th>Item</th><td>' + gr.getDisplayValue('cat_item') + '</td></tr>';
    html += '<tr><th>Requested For</th><td>' + gr.getDisplayValue('requested_for') + '</td></tr>';
    html += '<tr><th>Requested Item Number</th><td>' + gr.number + '</td></tr>';
    html += '<tr><th>Request (REQ)</th><td>' + gr.getDisplayValue('request') + '</td></tr>';
    html += '<tr><th>Opened On</th><td>' + gr.getDisplayValue('opened_at') + '</td></tr>';
    html += '<tr><th>Opened By</th><td>' + gr.getDisplayValue('opened_by') + '</td></tr>';
    html += '</table>';

    // Variables section
    html += '<div class="section-title">Requested Configuration</div>';
    html += '<table class="meta-table">';
    html += '<tr><th>Laptop Model</th><td>' + laptopModel + '</td></tr>';
    html += '<tr><th>Type</th><td>' + type + '</td></tr>';
    html += '</table>';

    html += '</body></html>';

    // Generate PDF attached to sc_req_item
    var result = v.convertToPDF(html, 'sc_req_item', inputs.id, 'Req Item PDF - ' + gr.number);

    if (result.status === 'success' && result.attachment_id) {
        outputs.flag = 1;
        // Optional: expose useful outputs if your Action has them defined
        // outputs.pdf_sys_id = result.attachment_id;
        // outputs.pdf_url = gs.getProperty('glide.servlet.uri') + 'sys_attachment.do?sys_id=' + result.attachment_id;
    } else {
        gs.addErrorMessage('PDF generation failed or no attachment ID returned.');
        outputs.flag = 0;
    }

})(inputs, outputs);

 

 

 

 

adityahubli_1-1764690800070.png

This is how pdf look like .

 

If this helps you then mark it as helpful and  accept as solution.

Regards,

Aditya

 

ben_hollifield
Tera Guru

Hi @Ballela Siva Te - the comments above are correct in that you can build this as a custom solution - the building blocks exist in-platform. If you need a turn-key solution with more flexibility, Yansa Labs offers a certified ServiceNow Store app that facilitates the creation of templates, the merging of record data, and the generation/attachment of a PDF to a record. It includes both a Flow Action as well as an interactive UI for when technicians need to generate on-demand or customize before attachment. If it's useful, it's free to trial at the link below. Feel free to reach out to me directly if we can help!

adityahubli
Tera Contributor

Hello @Ballela Siva Te ,

If above soilution helps you then mark it as helpful and accept as solution for further future queries.

Regards,

Aditya