Custom Page For Sending Statements To The Specific Emails

Requirement

HTL will create 4 Custom fields that hold email addresses for Invoices: Email Invoice 1, Email Invoice 2, Email Invoice 3, and Email Invoice 4. So on the creation of a new invoice, HTL would like to send the Invoice PDF to the email address added in the custom fields. If the custom field is empty, then no need to send an email to an additional email address. The invoices will be generated by HTL at the end of the day by going to NetSuite>Transactions>Sales>Invoice Sales Orders, the Invoice is to be emailed as a PDF to all 4 email addresses (If populated) of that Customer. The settings are to display and default to Customer = All, Posting Period = current, Date = today, To be Printed = Respect Customer Preference, To be emailed = Yes.

HTL will create 4 Customer fields that hold email addresses for statements (HTL not sharing the first email address with Invoices like NetSuite normally does – HTL Have separated out the NetSuite Invoice/Statement email address): Email Statements 1, Email Statements 2, Email Statements 3, and Email Statements 4. HTL wants to send the statement to the email address added in the custom fields rather than sending it to the Customer’s Email. If all the custom fields are empty, then the statement has to be sent to the Customer’s email. The statement email needs to be triggered by the Accounting person manually. For that a custom page needs to be included as a link in the Transaction Tab for “HTL – Accounts All” role. This will include the input fields and a button “Send Email Statements” to initiate the email send action. The statement is to be emailed as a PDF to all 4 email addresses (If populated) of that Customer.

The settings are to display and default to:

STATEMENT DATE = Last day of previous month

START DATE = First day of previous month

Tick Consolidated Statement

FORM = Select HTL Advanced Statement

The emails will need to have no restriction in how many that can run (NetSuite normally limits to batches of 100)

Solution

The requirement of sending the Invoice Copy is achieved by deploying a script on the creation of an Invoice/Cash sale. The proposed script sends a copy of the invoice as a PDF to all 4 custom email addresses (If populated) on the corresponding customer record.

The requirement of sending the Statement can be achieved by creating a custom page. The proposed custom page is included as a link in the Transaction Tab for “HTL – Accounts All” Role and for the administrators. The page includes the following input fields and a button “Send Email Statements” to initiate the email send action.

STATEMENT DATE: Date field and the default value will be the last day of the previous month

START DATE: Date field and the default value will be the First Day of the previous month

Consolidated Statement: Checkbox field and checked by default

Form: List field and Defaulted to “HTL Advanced Statement”

Users can update the above fields if required. After updating the field values and upon clicking the “Send Email Statements” button, a scheduled script triggers on the background to send the email for all the Active customers. The current page shows an alert that says “Your request is under process. We will notify you by email once the process completes” and current page reloads if the user clicks the Ok button on the alert. The script sends the statement to the email address on the Email Invoice 1, Email Invoice 2, Email Invoice 3, and Email Invoice 4 field corresponding to the customer record if that field is not empty. All the 4 email addresses of a single customer are included in a single email as recipients. The statement is  generated with the following conditions:

STATEMENT DATE: Date from a custom page

START DATE: Date from the custom page

SHOW ONLY OPEN TRANSACTIONS: Unticked

CONSOLIDATED STATEMENT: Value based on checkbox field on a custom page

FORM: Value from the Form List field on a custom page

After completion of the email sending process, the script sends an email to the initiated user to notify the process completion. The email content is sent statically in the script.

Known Issues

The form fields in the custom ‘Generate Statement’ page will list only the currently available forms. So when a new form is created for the statement then, this needs to be added to this list by updating the script.

Invoice Copy Send Script

/**
* @NApiVersion 2.x
* @NScriptType UserEventScript
* @NModuleScope SameAccount
*/
/** Script Description
* The script is used to send a copy of the invoice as PDF to the all 4 custom 
* email addresses (If populated) on the corresponding customer record.
******************************************************************************************************
HTN-70
******************************************************************************************************
* DATE:15/09/2020
*
* AUTHOR: JOBIN AND JISMI IT SERVICES LLP
*
******************************************************************************/


define(['N/record', 'N/search', 'N/render', 'N/runtime', 'N/email', 'N/config'], function (record, search, render, runtime, email, config) {

    var main = {
        // Function to check whether a value exists for a parameter
        checkForParameter: function (parameter, parameterName) {
            if (parameter !== "" && parameter !== null && parameter !== undefined && parameter !== false && parameter !== "null" && parameter !== "undefined" && parameter !== " " && parameter !== 'false') {
                return true;
            } else {
                if (parameterName)
                    log.debug('Empty Value found', 'Empty Value for parameter ' + parameterName);
                return false;
            }
        },
        // Function to render a PDF for the transaction
        renderRecordToPdfWithTemplate: function (INVOICE_ID) {
            try {
                log.debug('INVOICE_ID', INVOICE_ID);

                var invoicePdf = render.transaction({
                    entityId: INVOICE_ID,
                    printMode: render.PrintMode.PDF,
                    // inCustLocale: true
                });

                log.debug('invoicePdf', invoicePdf);

                return invoicePdf;

            } catch (er) {
                log.debug('er@renderRecordToPdfWithTemplate', er.message);
            }
        }

    }

    return {

        afterSubmit: function (context) {
            try {

                log.debug('Context Type', context.type);

                if (context.type == 'create') { // Sending email works only in create mode
                    log.debug('context.newRecord', context.newRecord)
                    var invoiceRecId = context.newRecord.id;
                    var type = context.newRecord.type
                    log.debug('type', type);
                    log.debug('invoiceRecId', invoiceRecId);

                    var invoiceRec = record.load({ // Load Invoice record
                        type: type,//record.Type.INVOICE,
                        id: invoiceRecId
                    });

                    var invoiceNumber = invoiceRec.getValue({
                        fieldId: 'tranid'
                    });
                    log.debug('invoiceNumber', invoiceNumber);

                    var customerId = invoiceRec.getValue({
                        fieldId: 'entity'
                    });
                    log.debug('customerId', customerId);
                    var customerName = invoiceRec.getText({
                        fieldId: 'entity'
                    });
                    log.debug('customerName', customerName);
                    var customerRec = record.load({ // Load Customer record
                        type: record.Type.CUSTOMER,
                        id: customerId
                    });

                    // Fetch values from the custom (email) fields from the Customer record
                    var emailOne = customerRec.getValue({
                        fieldId: 'email'
                    });
                    log.debug('emailOne', emailOne);
                    var emailTwo = customerRec.getValue({
                        fieldId: 'custentity68'
                    });
                    log.debug('emailTwo', emailTwo);
                    var emailThree = customerRec.getValue({
                        fieldId: 'custentity71'
                    });
                    log.debug('emailThree', emailThree);
                    var emailFour = customerRec.getValue({
                        fieldId: 'custentity72'
                    });
                    log.debug('emailFour', emailFour);

                    var invoicePdf = main.renderRecordToPdfWithTemplate(context.newRecord.id); // Function call will return a PDF object
                    log.debug('invoicePdf', invoicePdf);
                    var userObj = runtime.getCurrentUser();


                    var emailArr = [];
                    //not taking email 1 as the mail will send to this email id defaultly.
                    // if (emailOne)
                    //     emailArr.push(emailOne);
                    if (emailTwo)
                        emailArr.push(emailTwo);
                    if (emailThree)
                        emailArr.push(emailThree);
                    if (emailFour)
                        emailArr.push(emailFour);

                    if (emailArr.length) // An email will be sent if array contains a non-zero positive number - Array will contain values only if the Customer record contains atleast single email id
                        email.send({
                            author: userObj.id,//senderId,
                            recipients: emailArr,
                            subject: "Hygiene Technologies Ltd Invoice " + invoiceNumber,//"'Hygiene Technologies NZ : " + invoiceNumber + "'",
                            body: '<span style="color:black;">Please find attached your PDF Invoice number ' + invoiceNumber + '</span><br><span style="color:black;">Thank you for your business!</span><br><br><br><span style="color:black;">FROM YOUR HYGIENE TECHNOLOGIES TEAM</span><br>www.hygienetech.co.nz',
                            attachments: [invoicePdf],
                        });
                    // else {
                    //     invoiceRec.setValue({
                    //         fieldId: 'custbody_jj_train_error_log',
                    //         value: 'The customer has no associated email addresses'
                    //     });
                    //     invoiceRec.save({
                    //         // enableSourcing: true | false,
                    //         ignoreMandatoryFields: true
                    //     });
                    // }
                    log.debug('SUCCESS');
                }

            } catch (er) {
                log.debug('er@afterSubmit', er);
                invoiceRec.setValue({
                    fieldId: 'custbody_jj_train_error_log',
                    value: er.message
                });
                invoiceRec.save({
                    // enableSourcing: true | false,
                    ignoreMandatoryFields: true
                });
            }
        }
    };
});

Statement Copy Sending Script

/**
 * @NApiVersion 2.x
 * @NScriptType Suitelet
 * @NModuleScope SameAccount
 */
/*******************************************************************************
 * CLIENTNAME:Hygiene Technologies NZ | HTN-70
 * 
 * **************************************************************************
 * Date : 08-09-2020
 *
 * Author: Jobin & Jismi IT Services LLP
 * Script Description :Customer statement need to be sent to an additional
 * email id that is added on custom fields in customer record.           
 * Date created :08-09-2020
 *
 * REVISION HISTORY
 *
 * Revision 1.0 ${08-09-2020} Gloria : created
 * 
 ******************************************************************************/
define(['N/ui/serverWidget', 'N/task'],
    function (serverWidget, task) {
        var para;
        function onRequest(context) {// entry point
            try {
                //GET
                log.debug('method', context.request.method);
                if (context.request.method == 'GET') {
                    log.debug("get inn..")
                    //Create the form
                    var today = new Date();
                    log.debug("today", today);
                    var month = today.getMonth();
                    var year = today.getFullYear();

                    //Day 0 is the last day in the previous month
                    var numberOfDays = new Date(year, month, 0).getDate();
                    // return new Date(year, month+1, 0).getDate();
                    var form = serverWidget.createForm({ title: "Email Statements" });
                    form.clientScriptFileId = 3432277;
                    var statementDate = form.addField({ id: 'statement_date', label: 'STATEMENT DATE', type: serverWidget.FieldType.DATE })
                    statementDate.defaultValue = numberOfDays + '/' + month + '/' + year;
                    statementDate.isMandatory = true;
                    var startDate = form.addField({ id: 'start_date', label: 'START DATE', type: serverWidget.FieldType.DATE });
                    startDate.defaultValue = 1 + '/' + month + '/' + year;
                    var consolstatement = form.addField({ id: 'consolidated_statement', label: 'Consolidated Statement', type: serverWidget.FieldType.CHECKBOX });
                    consolstatement.defaultValue = 'T';
                    var selectForm = form.addField({ id: 'form', label: 'Form', type: serverWidget.FieldType.SELECT });
                    selectForm.addSelectOption({ value: '81', text: 'Standard Statement' });
                    selectForm.addSelectOption({ value: '121', text: 'HTL Adv Statement' });
                    selectForm.defaultValue = '121';
                    form.addSubmitButton({
                        label: 'Send Email Statements'
                    });
                    context.response.writePage(form);
                } else {
                    para = context.request.parameters;
                    log.debug("para", para);

                    var mrTask = task.create({
                        taskType: task.TaskType.MAP_REDUCE,
                        scriptId: "customscript_jj_mr_statement_copy_htn_70",
                        deploymentId: "customdeploy_jj_mr_statement_copy_htn_70",
                        params: {
                            custscript_jj_statement_date: para.statement_date,
                            custscript_jj_start_date: para.start_date,
                            custscript_jj_consolstatement: para.consolidated_statement,
                            custscript_jj_formnumber: para.form,
                        }
                    });
                    log.debug("mrTask", mrTask);
                    var scriptTaskId = mrTask.submit();
                    log.debug("scriptTaskId", scriptTaskId);
                    var client = 3432277;
                    var type = 'normal'
                    postForm(context, type, para)


                }
            } catch (e) {
                log.debug("error", e)
                if (e.name == 'MAP_REDUCE_ALREADY_RUNNING') {
                    // var client=3450109;
                    var type = 'error'
                    postForm(context, type, para)
                    // context.response.write("<!DOCTYPE html><html><head><style>h1{display: inline-block;font-size: 22px;font-weight: bold;color: #4d5f79;line-height: 33px;vertical-align: top;margin-bottom: 4px;font-family: Open Sans,Helvetica,sans-serif;} </style><title>Email Statements</title></head><body><h1> Email Statements</h1><p>Your request is failed to process. The script is already running and cannot be started until it has completed.</p></body></html>")
                }
            }
        }
        function postForm(context, type, para) {
            var form = serverWidget.createForm({ title: "Email Statements" });

            // form.clientScriptFileId = Number(client)//3432277;
            form.clientScriptFileId = 3432277;
            var statementDate = form.addField({ id: 'statement_date', label: 'STATEMENT DATE', type: serverWidget.FieldType.DATE })
           
            // .updateDisplayType({
            //     displayType : serverWidget.FieldDisplayType.DISABLED
            // });
            statementDate.defaultValue = para.statement_date;
            statementDate.isMandatory = true;
            var startDate = form.addField({ id: 'start_date', label: 'START DATE', type: serverWidget.FieldType.DATE })
            // .updateDisplayType({
            //     displayType : serverWidget.FieldDisplayType.DISABLED
            // });
            startDate.defaultValue = para.start_date;
            var consolstatement = form.addField({ id: 'consolidated_statement', label: 'Consolidated Statement', type: serverWidget.FieldType.CHECKBOX })
            // .updateDisplayType({
            //     displayType : serverWidget.FieldDisplayType.DISABLED
            // });;
            consolstatement.defaultValue = para.consolidated_statement;
            var selectForm = form.addField({ id: 'form', label: 'Form', type: serverWidget.FieldType.SELECT })
            // .updateDisplayType({
            //     displayType : serverWidget.FieldDisplayType.DISABLED
            // });;
            selectForm.addSelectOption({ value: '81', text: 'Standard Statement' });
            selectForm.addSelectOption({ value: '121', text: 'HTL Adv Statement' });
            selectForm.defaultValue = para.form;
            if (type == 'error') {
                var error = form.addField({ id: 'page_error', label: 'error', type: serverWidget.FieldType.TEXT }).updateDisplayType({
                    displayType: serverWidget.FieldDisplayType.HIDDEN
                });
                error.defaultValue = 'error';
            }
            form.addSubmitButton({
                label: 'Send Email Statements'
            });
            context.response.writePage(form);
        }
        return {
            onRequest: onRequest
        }
    });
Map-reduce script to process the bulk sending of Statements
/**
 * @NApiVersion 2.x
 * @NScriptType MapReduceScript
 */
/*******************************************************************************
 * CLIENTNAME:Hygiene Technologies NZ | HTN-70
 * 
 * **************************************************************************
 * Date : 08-09-2020
 *
 * Author: Jobin & Jismi IT Services LLP
 * Script Description :Customer statement need to be sent to an additional
 * email id that is added on custom fields in customer record.           
 * Date created :08-09-2020
 *
 * REVISION HISTORY
 *
 * Revision 1.0 ${08-09-2020} Gloria : created
 * 
 ******************************************************************************/
define(['N/search', 'N/runtime', 'N/render', 'N/email', 'N/file', 'N/config'],
    function (search, runtime, render, email, file, config) {
        var userObj = runtime.getCurrentUser();
        function getInputData() {
            try {
                var script = runtime.getCurrentScript();
                log.debug("script", script);
                var statementDate = script.getParameter("custscript_jj_statement_date");

                var startDate = script.getParameter("custscript_jj_start_date");
                var customerSearchObj = search.create({
                    type: "customer",
                    filters:
                        [
                            ["internalid", "anyof", "35502", "35503", "35501"],
                            "AND",
                            ["stage", "anyof", "CUSTOMER"],
                            "AND",
                            ["isinactive", "is", "F"],
                            "AND",
                            [[["transaction.trandate", "onorbefore", statementDate], "AND", ["transaction.amountremainingisabovezero", "is", "T"]], "OR", [["transaction.type", "anyof", "CustInvc", "CashSale"], "AND", ["transaction.status", "anyof", "CashSale:C", "CustInvc:B"], "AND", ["transaction.trandate", "within", startDate, statementDate]]]
                        ],
                    columns:
                        [
                            search.createColumn({
                                name: "internalid",
                                summary: "GROUP",
                                label: "Internal ID"
                            }),
                            search.createColumn({
                                name: "entityid",
                                summary: "GROUP",
                                sort: search.Sort.ASC,
                                label: "ID"
                            }),
                            search.createColumn({
                                name: "altname",
                                summary: "GROUP",
                                label: "Name"
                            }),
                            search.createColumn({
                                name: "email",
                                summary: "GROUP",
                                label: "Email"
                            }),
                            search.createColumn({
                                name: "custentity69",
                                summary: "GROUP",
                                label: "Email Statement 1"
                            }),
                            search.createColumn({
                                name: "custentity70",
                                summary: "GROUP",
                                label: "Email Statement 2"
                            }),
                            search.createColumn({
                                name: "custentity73",
                                summary: "GROUP",
                                label: "Email Statement 3"
                            }),
                            search.createColumn({
                                name: "custentity74",
                                summary: "GROUP",
                                label: "Email Statement 4"
                            })
                        ]
                });

                var response = []
                var searchPageRanges;
                try {
                    searchPageRanges = customerSearchObj.runPaged({
                        pageSize: 1000
                    });
                } catch (err) {
                    return [];
                }
                if (searchPageRanges.pageRanges.length < 1)
                    return [];

                var pageRangeLength = searchPageRanges.pageRanges.length;
                // log.debug('pageRangeLength', pageRangeLength);

                for (var pageIndex = 0; pageIndex < pageRangeLength; pageIndex++)
                    searchPageRanges.fetch({
                        index: pageIndex
                    }).data.forEach(function (result) {
                        response.push({
                            id: result.getValue({ name: "internalid", summary: "GROUP", label: "Internal ID" }),
                            entityid: result.getValue({
                                name: "entityid",
                                summary: "GROUP",
                                sort: search.Sort.ASC,
                                label: "ID"
                            }),
                            name: result.getValue({ name: "altname", summary: "GROUP", label: "Name" }),
                            email: result.getValue({ name: "email", summary: "GROUP", label: "Email" }),
                            email1: result.getValue({ name: "custentity69", summary: "GROUP", label: "Email Statement 1" }),
                            email2: result.getValue({ name: "custentity70", summary: "GROUP", label: "Email Statement 2" }),
                            email3: result.getValue({ name: "custentity73", summary: "GROUP", label: "Email Statement 3" }),
                            email4: result.getValue({ name: "custentity74", summary: "GROUP", label: "Email Statement 4" })
                        });
                    });
                log.debug("response", response);
                return response;
            } catch (e) {
                log.debug("error@getInputData", e)
            }
        }
        var content = new Array();


        function reduce(context) {//sending email to each customer
            try {
                // var obj = JSON.parse(context.values);
                var obj = JSON.parse(context.values[0]);
                log.debug('obj', obj)
                var script = runtime.getCurrentScript();
                log.debug("script", script);
                var statementDate = script.getParameter("custscript_jj_statement_date");

                var startDate = script.getParameter("custscript_jj_start_date");
                var consolidateStatements = script.getParameter("custscript_jj_consolstatement");
                log.debug('consolidateStatements', consolidateStatements)
                var formId = script.getParameter("custscript_jj_formnumber");
                var transactionFile = render.statement({//creating statement pdf file
                    entityId: Number(obj.id),
                    printMode: render.PrintMode.PDF,
                    startDate: startDate,
                    statementDate: statementDate,
                    openTransactionsOnly: false,
                    consolidateStatements: consolidateStatements == 'T' ? true : false,
                    formId: Number(formId),
                    inCustLocale: true
                });
                var error = false;

                // var fileObj = file.load({
                //     id: 3441195
                // })
                // var emailBody = fileObj.getContents();
                // var companyInfo = config.load({
                //     type: config.Type.COMPANY_INFORMATION
                // });
                // var companyEmail = companyInfo.getValue({
                //     fieldId: 'email'
                // });
                // var webAddress = companyInfo.getValue({
                //     fieldId: 'url'
                // });

                // emailBody = emailBody.replace('-Company email address-', companyEmail)
                // emailBody = emailBody.replace('-Company Web address-', webAddress)
                var emailarr = [];
                var emailstr = '';
                if (obj.email1 || obj.email2 || obj.email3 || obj.email4) {
                    for (var i = 1; i <= 4; i++) {
                        if (obj['email' + i] && obj['email' + i] != '- None -') {
                            emailarr.push(obj['email' + i])
                            emailstr += '- ' + obj['email' + i];
                            // if (obj['email' + (i + 1)]) {
                            //     emailstr += '';
                            // }
                        }
                    }
                }

                log.debug('emailarr', emailarr);
                log.debug('emailstr', emailstr);
                try {
                    email.send({
                        author: userObj.id,
                        recipients: obj.email1 || obj.email2 || obj.email3 || obj.email4 ? emailarr : [obj.email],
                        subject: 'Hygiene Technologies Ltd – Statement ' + statementDate,
                        body: '<span style="color:black;">Please find attached your PDF Statement  ' + statementDate + '</span><br><span style="color:black;">Thank you for your business!</span><br><br><br><span style="color:black;">FROM YOUR HYGIENE TECHNOLOGIES TEAM</span><br>www.hygienetech.co.nz',
                        attachments: [transactionFile]
                    });
                } catch (e) {//catching error emails to create failed email csv file
                    log.debug('error@email', e)
                    error = true;
                    var temp = new Array();
                    temp[0] = obj.entityid;
                    temp[1] = obj.email1 || obj.email2 || obj.email3 || obj.email4 ? emailstr : obj.email;

                }
                log.debug('temp', temp)

                context.write({
                    key: 'errorEmail',
                    value: error ? temp.length ? temp : '' : ''
                });
            } catch (e) {
                log.debug("error@reduce", e)
            }
        }
        function summarize(summary) {//senting email to the intiator of the mailing process to notify the completion.
            try {
                var contents = '';
                contents += ['Entityid', 'Emails'].join(",") + "\r\n";
                summary.output.iterator().each(function (key, value) {
                    log.debug('sumary value', value)
                    if (value) {
                        content.push(JSON.parse(value).join(","));
                        contents += JSON.parse(value).join(",") + "\r\n";
                    }
                    return true;
                });
                log.debug('contents', contents)
                log.debug('sumary contents', content)

                if (content && content.length) {
                    log.debug('summer if')
                    var fileObj = file.create({// creating csv file of failed emails.
                        name: 'Failed statement emails.csv',
                        fileType: file.Type.CSV,
                        contents: contents
                    });
                    email.send({
                        author: userObj.id, //118,
                        recipients: [userObj.email],// [userObj.email, 'accounts@hygienetech.co.nz'],
                        subject: 'Failed Statement Emails',
                        body: '<span style="color:black;">Hi ' + userObj.name + '</span>,<br><br><span style="color:black;">The emailing of statements are completed. The failed emails are attached as a csv document<span><br><br><span style="color:black; font-size: 14px;">Thank you</span><br><span style="color:black;">The Hygiene Technologies Team</span><br>www.hygienetech.co.nz',
                        attachments: [fileObj]
                    });
                } else {
                    log.debug("summer else")
                    email.send({
                        author: userObj.id,//118,
                        recipients: [userObj.email],//[userObj.email, 'accounts@hygienetech.co.nz'],
                        subject: 'Email Statements ',
                        body: '<span style="color:black;">Hi ' + userObj.name + '</span>,<br><br><span style="color:black;"> The emailing of statements are completed.<span><br><br><span style="color:black; font-size: 14px;">Thank you</span><br><span style="color:black;">The Hygiene Technologies Team</span><br>www.hygienetech.co.nz'
                    });
                }
            } catch (e) {
                log.debug('error@summer', e);
            }
        }

        return {
            getInputData: getInputData,
            reduce: reduce,
            summarize: summarize
        }
    });
Client script to support the custom page
/**
 *@NApiVersion 2.x
 *@NScriptType ClientScript
 */
define(['N/ui/message'],
    function (message) {
        function saveRecord(context) {

            // window.close();
            var v = confirm('Your request is under process. We will notify you by email once the process completes')
            if (v) {
                return true;
            } else {
                return false;
            }
        }
        function pageInit(context) {
            var rec = context.currentRecord;
            var er = rec.getValue({
                fieldId: 'page_error'
            })
            console.log("error field",er);
            if (er == 'error') {
                var myMsg = message.create({
                    title: "Request is failed to process",
                    message: "Your request is failed to process. The script is already running a previous request and cannot be started until it has completed.",
                    type: message.Type.ERROR
                });
                myMsg.show();
            }
        }
        return {
            saveRecord: saveRecord,
            pageInit: pageInit
        }
    });

Leave a comment

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