PDF Template for Customer Payment

J-curve would like to create the Customer Payment PDF template as per the given layout 

Our Solution 

The requirement can be achieved by creating a script for adding a custom button named Receipt in the Customer Payment. When the user clicks the custom button, then the script will render the custom pdf template and will generate the corresponding printout. 

Field Mapping can be followed as per the given mapping file. 

The “TH Sarabun New” font can be used for the content 

The layout of the PDF will be designed as below 

  • Headers will be displayed on every page. 
  • The item body table can be considered as the dynamic. So, the table will end immediately after the item lines. 
  • If there are multiple pages, the “ยังมีรายการต่อ” (Continue with next page) label needs to be added at the end of all the pages, except the last page. 
/**
 * @NApiVersion 2.1
 * @NScriptType UserEventScript
 */
/*******************************************************************************
 * JCurve Solutions
 *
 ******************************************************************************
 * Date: 07 July 2022
 * Author: Jobin & Jismi IT Services LLP
 * Script Description: User event script for adding a button(Receipt) in the customer payment  record.
 * Date created :  07 July 2022
 ******************************************************************************/
define([],
    
    () => {
        /**
         * Defines the function definition that is executed before record is loaded.
         * @param {Object} scriptContext
         * @param {Record} scriptContext.newRecord - New record
         * @param {string} scriptContext.type - Trigger type; use values from the context.UserEventType enum
         * @param {Form} scriptContext.form - Current form
         * @param {ServletRequest} scriptContext.request - HTTP request information sent from the browser for a client action only.
         * @since 2015.2
         */
        const beforeLoad = (scriptContext) =>
        {
            if (scriptContext.type === 'view')
            {
                scriptContext.form.addButton({
                    id: 'custpage_customer_payment_receipt_button',
                    label: 'Receipt',
                    functionName: 'customerPaymentReceipt()'
                });
                scriptContext.form.clientScriptFileId = 6087; //client script for button action
                }
        }
        return {beforeLoad}
    });
/**
 * @NApiVersion 2.x
 * @NScriptType ClientScript
 * @NModuleScope SameAccount
 */
/*******************************************************************************
 * JCurve Solutions
 *
 ******************************************************************************
 * Date: 07 July 2022
 * Author: Jobin & Jismi IT Services LLP
 * Script Description: The client script is  for the button action.
 * Date created :  07 July 2022
 ******************************************************************************/
define(['N/currentRecord', 'N/url'],
/**
 * @param{currentRecord} currentRecord
 * @param{url} url
 */
function(currentRecord, url) {
    
    /**
     * Function to be executed after page is initialized.
     *
     * @param {Object} scriptContext
     * @param {Record} scriptContext.currentRecord - Current form record
     * @param {string} scriptContext.mode - The mode in which the record is being accessed (create, copy, or edit)
     *
     * @since 2015.2
     */
    function pageInit(scriptContext)
    {
    }

    function customerPaymentReceipt()
    {
        try
        {
            let internalId = currentRecord.get().id;
            log.debug({title: "internalId", details: internalId});

            let currenturl = url.resolveScript({
                scriptId: "customscript_jj_sl_customer_payment",
                deploymentId: "customdeploy_jj_sl_customer_payment",
                params: {internalIds: internalId, custBtnClick: 0}         // SuiteLet for PDF template page.
            })
            window.open(currenturl + "&internalIds=" + internalId)
        }
        catch (e)
        {
            log.error({title: "error@customerPaymentReceipt", details: e});
        }
    }
    return {pageInit: pageInit, customerPaymentReceipt:customerPaymentReceipt};
});
/**
 * @NApiVersion 2.1
 * @NScriptType Suitelet
 */
/*******************************************************************************
* JCurve Solutions
*
******************************************************************************
* Date: 07 July 2022
* Author: Jobin & Jismi IT Services LLP
* Script Description: Suite let script is created for PDF generation.
* Date created :  07 July 2022
******************************************************************************/
define(['N/currentRecord', 'N/https', 'N/record', 'N/render', 'N/search'],
    /**
 * @param{currentRecord} currentRecord
 * @param{https} https
 * @param{record} record
 * @param{render} render
 * @param{search} search
 */
    (currentRecord, https, record, render, search) => {
        /**
         * Defines the Suitelet script trigger point.
         * @param {Object} scriptContext
         * @param {ServerRequest} scriptContext.request - Incoming request
         * @param {ServerResponse} scriptContext.response - Suitelet response
         * @since 2015.2
         */
        const onRequest = (scriptContext) => {
            try {
                if (scriptContext.request.method === 'GET')
                {
                    let cpRecID = scriptContext.request.parameters.internalIds
                    log.debug({title: "cpRecID", details: cpRecID});
                    let invoiceDetails = exports.invoiceAddress(cpRecID);
                    let headerDetails = exports.cpHeaderDetails(cpRecID);
                    let generatedPdf = exports.generateCPReceipt(117, cpRecID,invoiceDetails,headerDetails);// 117 is the Internal id of PDF Template.
                    scriptContext.response.writeFile({file: generatedPdf, isInline: true});
                }
            }
            catch (e)
            {
                log.error({title: "error@on Request", details: e});
            }
        }

        const exports = {
            /**
             * @description Function for generating  customer payment using render module.
             * @param tempId Advance PDF template id.
             * @param cpRecID customer payment record internal id.
             * @param invoiceDetails invoice address details.
             * @param headerDetails header object for PDF template.
             * @returns {*}
             */
            generateCPReceipt(tempId, cpRecID,invoiceDetails,headerDetails) {
                let renderer = render.create();
                renderer.setTemplateById(tempId);
                renderer.addRecord({
                    templateName: 'record',
                    record: record.load({type: record.Type.CUSTOMER_PAYMENT, id: cpRecID})
                });
                renderer.addCustomDataSource({
                    format: render.DataSource.OBJECT,
                    alias: "invoiceObj",
                    data: invoiceDetails
                });
                renderer.addCustomDataSource({
                    format: render.DataSource.OBJECT,
                    alias: "headerObj",
                    data: headerDetails
                });

                let pdfFile = renderer.renderAsPdf();
                return pdfFile;
            },
            /**
             * @description Function for getting value of invoice address.
             * @param cpRecID customer payment record internal id.
             * @returns {*}
             */
            invoiceAddress(cpRecID)
            {
                try
                {
                    let cpRecord = record.load({type:"customerpayment",id :cpRecID});
                    let invoiceId = cpRecord.getSublistValue({sublistId:"apply",fieldId:'internalid',line:0});
                    let invoiceObj ={}
                    let invoiceSearchObj = search.create({
                        type: "invoice",
                        filters:
                            [
                                ["type","anyof","CustInvc"],
                                "AND",
                                ["internalid","anyof",invoiceId]
                            ],
                        columns:
                            [
                                search.createColumn({name: "billaddress1", label: "Billing Address 1"}),
                                search.createColumn({name: "billaddress2", label: "Billing Address 2"}),
                                search.createColumn({name: "billaddress3", label: "Billing Address 3"}),
                                search.createColumn({name: "billcity", label: "Billing City"}),
                                search.createColumn({name: "billzip", label: "Billing Zip"})
                            ]
                    });
                    let searchResultCou = invoiceSearchObj.runPaged().count;
                    if(searchResultCou>0)
                    {
                        invoiceSearchObj.run().each(function(result)
                        {
                            let billAdd1 = result.getValue(invoiceSearchObj.columns[0]);
                            let billAdd2 = result.getValue(invoiceSearchObj.columns[1]);
                            let billAdd3 = result.getValue(invoiceSearchObj.columns[2]);
                            let billCity = result.getValue(invoiceSearchObj.columns[3]);
                            let billZip = result.getValue(invoiceSearchObj.columns[4]);

                            invoiceObj.billAdd1 = exports.escapeXml(billAdd1);
                            invoiceObj.billAdd2 = exports.escapeXml(billAdd2);
                            invoiceObj.billAdd3 = exports.escapeXml(billAdd3);
                            invoiceObj.billCity = exports.escapeXml(billCity);
                            invoiceObj.billZip = exports.escapeXml(billZip);

                            return true;
                        });
                    }
                    return invoiceObj;
                }
                catch (e)
                {
                    log.error({title:"error@invoiceAddress",details:e});
                }
            },
            /**
             * @description Function for getting value of entity branch.
             * @param cpRecID customer payment record internal id.
             * @returns {*}
             */
            cpHeaderDetails(cpRecID)
            {
                try
                {
                    let headerObj ={}
                    let customerpaymentSearchObj = search.create({
                        type: "customerpayment",
                        filters:
                            [
                                ["type","anyof","CustPymt"],
                                "AND",
                                ["internalid","anyof",cpRecID]
                            ],
                        columns:
                            [
                                search.createColumn({name: "custbody_rapid_tht_entitybranch", label: "Entity Branch (Thai Tax)"})
                            ]
                    });
                    let searchResultCount = customerpaymentSearchObj.runPaged().count;
                    if(searchResultCount>0)
                    {
                        customerpaymentSearchObj.run().each(function(result)
                        {
                            let entityBranch = result.getValue(customerpaymentSearchObj.columns[0]);
                             if(entityBranch === "0" || entityBranch === null || entityBranch === "" || entityBranch === 0 )
                             {
                                 entityBranch = "สำนักงานใหญ่";
                             }
                             else
                             {
                                 entityBranch = "สาขา " + exports.padLeadingZeros(entityBranch,5);
                             }
                            headerObj.entityBranch = exports.escapeXml(entityBranch);

                            return true;
                        });
                    }
                    return headerObj;
                }
                catch (e)
                {
                    log.error({title:"error@cpHeaderDetails",details:e});
                }
            },
            /**
             * @description function for handling the escape characters
             * @param unsafe Data
             * @return {*}
             */
            escapeXml(unsafe) {
                try{
                    if(unsafe) {
                        return unsafe.replace(/[<>&'"]/g, function (c) {
                            switch (c) {
                                case '<':
                                    return '&lt;';
                                case '>':
                                    return '&gt;';
                                case '&':
                                    return '&amp;';
                                case '\'':
                                    return '&apos;';
                                case '"':
                                    return '&quot;';
                            }
                        });
                    }
                }
                catch (e)
                {
                    log.error({title:"error@unsafe",details:e});
                }
            },
            padLeadingZeros(num, size)
            {
            let s = num+"";
            while (s.length < size) s = "0" + s;
            return s;
            }
        }
        return {onRequest}
    });
<?xml version="1.0"?><!DOCTYPE pdf PUBLIC "-//big.faceless.org//report" "report-1.1.dtd">
<pdf>
  <head>
    <link name="thai-font" type="font" subtype="opentype" src="https://7842116-sb1.app.netsuite.com/core/media/media.nl?id=5258&amp;c=7842116_SB1&amp;h=v7ivNbRa0Z0IMO0IolWo2dD4aTfRntJHzHNXBXAU0b-YKdqN&amp;_xt=.ttf" src-bold="https://7842116-sb1.app.netsuite.com/core/media/media.nl?id=5259&amp;c=7842116_SB1&amp;h=ZN4hCrShmr93pQ3cytYE66or4wE4Qah_aHxOv3vEYs1d4HcW&amp;_xt=.ttf" bytes="2" />

    <macrolist>
      <macro id="nlheader">

      </macro>

      <macro id="nlfooter">
        <table style="width: 60%; font-size: 14pt;">
          <tr><td align="left">การชำระเงินด้วยเช็คจะสมบูรณ์เมื่อบริษัทได้รับเงินตามเช็คเรียบร้อย</td></tr>
        </table>
        <table style="width: 100%; font-size: 14pt;">
          <tr>
            <td style="width: 25%;" align="left">เงินสด&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_________________</td>
            <td style="width: 25%;" align="center"></td>
            <td style="width: 25%;" align="center"></td>
            <td style="width: 25%;" align="right"></td>
          </tr>
          <tr>
            <td style="width: 25%;" align="left">เช็คธนาคาร _________________</td>
            <td style="width: 25%;" align="center">เช็คเลขที่   _________________</td>
            <td style="width: 25%;" align="center">ลงวันที่ ___/___/___</td>
            <td style="width: 25%;" align="right">จำนวนเงิน _______________</td>
          </tr>
          <tr>
            <td style="width: 25%;" align="left">เช็คธนาคาร _________________</td>
            <td style="width: 25%;" align="center">เช็คเลขที่   _________________</td>
            <td style="width: 25%;" align="center">ลงวันที่ ___/___/___</td>
            <td style="width: 25%;" align="right">จำนวนเงิน _______________</td>
          </tr>
        </table>
        <table align="right" style="width: 55%; font-size: 14pt;">
          <tr><td align="left">ในนามบริษัท ${record.subsidiary.custrecord_rapid_tht_company_legalname}</td></tr>
        </table>
        <table style="width: 80%; font-size: 14pt;">
          <tr>
            <td align="left">ผู้รับเงิน___________</td>
            <td align="left">วันที่ ${record.trandate}</td>
            <td align="right">ผู้รับมอบอำนาจ_______________</td>
          </tr>
        </table>
      </macro>
    </macrolist>

    <style type="text/css">
      *{
      font-family:       thai-font,sans-serif;
      }
      table{
      table-layout:      fixed;
      }
      .itemHeader, .itemHeaderEnd{
      padding:           5px;
      font-size:         14pt;
      border-top:        1px solid black;
      border-left:       1px solid black;
      border-bottom:     1px solid black;
      }
      .itemHeaderEnd{
      border-right:      1px solid black;
      }
      .itemDetail, .itemDetailEnd{
      padding-top:     5px;
      padding-right:	 5px;
      padding-bottom:	 0px;
      padding-left:	 5px;
      border-left:     1px solid black;
      }
      .itemDetailEnd{
      border-right:      1px solid black;
      }
      .itemTotal{
      padding-top: 	 5px;
      padding-right:	 5px;
      padding-bottom:	 0px;
      padding-left:	 5px;
      border-top:       1px solid black;
      border-left:      1px solid black;
      border-right:     1px solid black;
      border-bottom:    1px solid black;
      }
      td.horizontalLine {
      border:      0;
      border-top:  1px solid black;
      width:       100%;
      }
    </style>
  </head>

  <body header="nlheader" header-height="1%" footer="nlfooter" footer-height="12%" padding="0.4in 0.4in 0.4in 0.4in" size="A4">

    <table  style="width: 100%; font-size: 14pt;">
      <thead >
        <tr><td colspan="20" align="left" style="font-size: 18pt;">${record.subsidiary.custrecord_rapid_tht_company_legalname}</td></tr>
        <tr><td colspan="20" align="left" style="font-size: 14pt;">${record.subsidiary.custrecord_rapid_tht_company_addr1},</td></tr>
        <tr><td colspan="20" align="left" style="font-size: 14pt;">${record.subsidiary.custrecord_rapid_tht_company_addr2},</td></tr>
        <tr><td colspan="20" align="left" style="font-size: 14pt;">${record.subsidiary.custrecord_rapid_tht_company_addr3},</td></tr>
        <tr><td colspan="20" align="left" style="font-size: 14pt;">${record.subsidiary.custrecord_rapid_tht_company_city},</td></tr>
        <tr><td colspan="20" align="left" style="font-size: 14pt;">${record.subsidiary.custrecord_rapid_tht_company_zip}</td></tr>
        <tr>
          <td colspan="20" align="left" style="font-size: 14pt;">${record.subsidiary.custrecord_phone}</td>
          <td colspan="10" align="left" style="font-size: 18pt; font-weight: bold;">ใบเสร็จรับเงิน</td>
        </tr>
        <tr>
          <td colspan="10" align="left" style=" font-size: 14pt;">เลขประจำตัวผู้เสียภาษี ${record.subsidiary.taxidnum}</td>
          <td colspan="20" align="left" style=" font-size: 14pt;">สำนักงานใหญ่</td>
        </tr>
        <tr>
          <td colspan="18">
            <table style="width: 100%;">
              <tr><td align="left" style="font-size: 14pt;">ลูกค้า ${record.customer.entityid}</td></tr>
              <tr><td align="left" style="font-size: 14pt;">${record.customer.companyname}</td></tr>
              <tr><td align="left" style="font-size: 14pt;">${invoiceObj.billAdd1}&nbsp;${invoiceObj.billAdd2}</td></tr>
              <tr><td align="left" style="font-size: 14pt;">${invoiceObj.billAdd3}&nbsp;${invoiceObj.billCity}&nbsp;${invoiceObj.billZip}</td></tr>
            </table>
          </td>
          <td colspan="12">
            <table style="width: 100%;">
              <tr><td align="left" style="font-size: 14pt;">เลขที่ใบเสร็จ</td>  <td align="left" style="padding-left:20px;">${record.tranid}</td></tr>
              <tr><td align="left" style="font-size: 15pt;">วันที่</td>        <td align="left" style="padding-left:20px;">${record.trandate}</td></tr>
              <tr><td align="left" style="font-size: 14pt;">พนักงานขาย</td>  <td align="left" style="padding-left:20px;">-</td></tr>
            </table>
          </td>
        </tr>
        <tr>
          <td colspan="13" style="font-size: 14pt;" align="left">เลขประจำตัวผู้เสียภาษี ${record.customer.vatregnumber}</td>
          <td colspan="17" style="font-size: 14pt; padding-left:20px;" align="left">${headerObj.entityBranch}</td>
        </tr>
        <tr>
          <td colspan="2" class="itemHeader" align="center">No.</td>
          <td colspan="5" class="itemHeader" align="center">ใบกำกับภาษี</td>
          <td colspan="4" class="itemHeader" align="center">วันที่</td>
          <td colspan="4" class="itemHeader" align="center">ครบกำหนด</td>
          <td colspan="5" class="itemHeader" align="center">จำนวนเงิน</td>
          <td colspan="5" class="itemHeader" align="center">ยอดคงค้าง</td>
          <td colspan="5" class="itemHeaderEnd" align="center">ยอดชำระ</td>
        </tr>
      </thead>
      <tbody>
        <#assign sNo = 0 />
        <#list  record.apply as Apply>
        <#assign sNo = sNo + 1/>
        <#assign tranId = Apply.refnum/>
        <#assign tranDate = Apply.applydate/>
        <#assign dueDate = Apply.duedate/>
        <#assign orgAmt = Apply.amount/>
        <#assign amtDue = Apply.due/>
        <#assign payment = Apply.total/>
        <tr>
          <td colspan="2" class="itemDetail" align="center">${sNo}</td>
          <td colspan="5" class="itemDetail" align="center">${tranId}</td>
          <td colspan="4" class="itemDetail" align="center">${tranDate}</td>
          <td colspan="4" class="itemDetail" align="center">${dueDate}</td>
          <td colspan="5" class="itemDetail" align="right">${orgAmt}</td>
          <td colspan="5" class="itemDetail" align="right">${amtDue}</td>
          <td colspan="5" class="itemDetailEnd" align="right">${payment}</td>
        </tr>
      </#list>
      <tr>
        <td colspan="20" align="center" style="border-top:1px solid black;">${record.custbody_amount_to_text}</td>
        <td colspan="5" align="right" style="border-top:1px solid black;" >รวมเป็นเงิน</td>
        <td colspan="5" align="right" class ="itemTotal" >${record.applied}</td>
      </tr>
    </tbody>
    <tfoot style="padding-top:1px;">
      <tr><td colspan="30" class="horizontalLine"></td></tr>
      <tr><td colspan="30" align="right" style="font-size:14pt;">ยังมีรายการต่อ</td></tr>
    </tfoot>
  </table>
  <table>
    <tr><td colspan="30" align="right" style="margin-top:-32.5px;border:0px;padding-right:0px;" ><img src="https://7842116-sb1.app.netsuite.com/core/media/media.nl?id=5370&amp;c=7842116_SB1&amp;h=Sb_L-GZJW8Ck_lxUg8SujpvB1dgM3aCW-Bib_DXCvbYbiVeU" width="620" height="30"/></td></tr>
  </table>
</body>
        </pdf>

Leave a comment

Your email address will not be published. Required fields are marked *