Send Invoice Due emails for past due invoices.

 define([“N/search”, “N/email”, “N/record”, “N/runtime”, “N/format”],

 (search, email, record, runtime, format) => {

     ‘use strict’

/**

      * @description the function to check whether a value exists in parameter

      * @param parameter -passing parameter

      * @param parameterName – passing parameter name

      * @returns{Boolean}

      */

function checkForParameter(parameter, parameterName) {

 try{

 if (

     parameter != “” &&

     parameter != null &&

     parameter != undefined &&

     parameter != “null” &&

     parameter != “undefined” &&

     parameter != ” “ &&

     parameter != false

 ) {

     return true;

 } else {

     if (parameterName)

         log.debug(

             “Empty Value found”,

             “Empty Value for parameter “ + parameterName

         );

     return false;

 }

}catch(e){

 log.error(“error@checkForParameter”)

 return false;

}

}

     /***********

      * Function to get invoices that are due for 45 days

      */

     function getInvoicesDueFourtyFiveDays() {

         try {

             let invoiceSearchObj = search.create({

                 type: “invoice”,

                 filters:

                     [

                         [“type”, “anyof”, “CustInvc”],

                         “AND”,

                         [“mainline”, “is”, “T”],

                         “AND”,

                         [“shipping”, “is”, “F”],

                         “AND”,

                         [“cogs”, “is”, “F”],

                         “AND”,

                         [“taxline”, “is”, “F”],

                         “AND”,

                         [“status”, “noneof”, “CustInvc:B”],

                         “AND”,

                         [“formulanumeric: ROUND({today}-{trandate})”, “equalto”, “45”],

                         “AND”,

                         [“custbody_jj_inv_due_email_sent”, “is”, “F”],

                         “AND”,

                         [“trandate”, “onorafter”, “10/1/2023”]

                     ],

                 columns:

                     [

                         search.createColumn({ name: “internalid”, label: “Internal ID” }),

                         search.createColumn({ name: “tranid”, label: “Document Number” }),

                         search.createColumn({ name: “amountremaining”, label: “Amount Remaining” }),

                         search.createColumn({

                             name: “internalid”,

                             join: “customer”,

                             label: “Internal ID”

                         }),

                         search.createColumn({

                             name: “formulatext”,

                             formula: “NVL({customer.custentity_jj_accounting_email},{customer.email})”,

                             label: “Formula (Text)”

                         })

                     ]

             });

             let resultArray = []

           

             log.debug(“COUNT”, invoiceSearchObj.runPaged().count)

             invoiceSearchObj.run().each(function (result) {

                 let resultObject = {}

                 resultObject.dueDays = 45

                 resultObject.internalId = result.getValue({ name: “internalid”, label: “Internal ID” })

                 resultObject.doumentNumber = result.getValue({ name: “tranid”, label: “Document Number” })

                 resultObject.amountRemaining = result.getValue({ name: “amountremaining”, label: “Amount Remaining” })

                 resultObject.customerIds = result.getValue({ name: “internalid”, join: “customer”, label: “Internal ID” })

                 resultObject.custEmails= result.getValue({

                     name: “formulatext”,

                     formula: “NVL({customer.custentity_jj_accounting_email},{customer.email})”,

                     label: “Formula (Text)”

                 })

                 resultArray.push(resultObject)

                 return true;

             });

             log.debug(“results 45”, resultArray)

             return resultArray

         } catch (e) {

             log.error(“error@getInvoicesDueFourtyFiveDays”, e)

             return []

         }

     }

     /************

     * Function to get invoices that are due for 30 days

     ************/

     function getInvoicesThirtyIntervals() {

         try {

             let invoiceSearchObj = search.create({

                 type: “invoice”,

                 filters:

                     [

                         [“type”, “anyof”, “CustInvc”],

                         “AND”,

                         [“mainline”, “is”, “T”],

                         “AND”,

                         [“shipping”, “is”, “F”],

                         “AND”,

                         [“cogs”, “is”, “F”],

                         “AND”,

                         [“taxline”, “is”, “F”],

                         “AND”,

                         [“status”, “noneof”, “CustInvc:B”],

                         “AND”,

                         [“formulanumeric: ROUND({today}-{custbody_jj_date_intervals})”, “equalto”, “11”],

                         “AND”,

                         [“trandate”, “after”, “10/1/2023”],

                         “AND”,

                         [“custbody_jj_inv_due_email_sent”, “is”, “T”]

                     ],

                 columns:

                     [

                         search.createColumn({ name: “internalid”, label: “Internal ID” }),

                         search.createColumn({ name: “tranid”, label: “Document Number” }),

                         search.createColumn({ name: “amountremaining”, label: “Amount Remaining” }),

                         search.createColumn({

                             name: “internalid”,

                             join: “customer”,

                             label: “Internal ID”

                         }),

                         search.createColumn({

                             name: “formulatext”,

                             formula: “NVL({customer.custentity_jj_accounting_email},{customer.email})”,

                             label: “Formula (Text)”

                         })

                     ]

             });

             let resultArray = []

             

             log.debug(“COUNT”, invoiceSearchObj.runPaged().count)

             invoiceSearchObj.run().each(function (result) {

                 let resultObject = {}

                 resultObject.dueDays = 30

                 resultObject.internalId = result.getValue({ name: “internalid”, label: “Internal ID” })

                 resultObject.doumentNumber = result.getValue({ name: “tranid”, label: “Document Number” })

                 resultObject.amountRemaining = result.getValue({ name: “amountremaining”, label: “Amount Remaining” })

                 resultObject.customerIds = result.getValue({ name: “internalid”, join: “customer”, label: “Internal ID” })

                 resultObject.custEmails= result.getValue({

                 name: “formulatext”,

                 formula: “NVL({customer.custentity_jj_accounting_email},{customer.email})”,

                 label: “Formula (Text)”

             })

                 resultArray.push(resultObject)

                 return true;

             });

             log.debug(“results 30”, resultArray)

             return resultArray

         } catch (e) {

             log.error(“error@getInvoicesThirtyIntervals”, e.message)

             return []

         }

     }

     /***********

      * Function to sent invoices due emails

      * @param penaltyAmount : penalty required to apply for the invoice

      * @param respEmail : recipients of the email

      * @param documentNumber: document number of invoice

      * @param customerIds : customer’s internal id

      * @param penaltyApplied: percentage of the penalty

      */

     function sentEmails(penaltyAmount, respEmail, doumentNumber, customerIds, penaltyApplied) {

         try {

             let emailBody = “Hi,” + “<br/><br/>” + “Thank you for being a valued partner and a prompt payer, we appreciate it very much. This is just a friendly reminder that the invoice “ + doumentNumber + ” is now overdue, incurring a “ + penaltyApplied + “% penalty, bringing the total amount due to $” + penaltyAmount.toFixed(2) + “<br/>” + “To avoid any potential late fees or inconvenience, kindly arrange the payment for this invoice at your earliest convenience.” + “<br/><br/>” + “Thanks.”

             email.send({

                 author: 2528,

                 recipients: respEmail,

                 body: emailBody,

                 subject: “Invoice Past Due Reminder”,

                 relatedRecords: {

                     entityId: parseInt(customerIds)

                 }

             });

             return true;

         } catch (e) {

             log.error(“error@sentEmails”, e);

             return false;

         }

     }

     /***********

      * Function to add penalty item to the line level

      * @param invoiceObject : invoice’s data object

      * @param penaltyPercentage : percentage of the penalty

      * @param penaltyApplied : penalty applied for the invoice

      */

     function addPenaltyItems(invoiceObject, penaltyPercentage, penaltyApplied, custEmailId) {

         try {

             let penaltyAmount = penaltyPercentage * (invoiceObject.amountRemaining)

             let totalDue = Number(penaltyAmount) + Number(invoiceObject.amountRemaining)

             let invObject = record.load({

                 type: record.Type.INVOICE,

                 id: invoiceObject.internalId,

                 isDynamic: true,

             })

             // Add a new item line to invoice

             invObject.selectNewLine({

                 sublistId: ‘item’,

             });

             invObject.setCurrentSublistValue({

                 sublistId: ‘item’,

                 fieldId: ‘item’,

                 value: 5087

             });

             invObject.setCurrentSublistValue({

                 sublistId: ‘item’,

                 fieldId: ‘1’,

                 value: 1

             });

             invObject.setCurrentSublistValue({

                 sublistId: ‘item’,

                 fieldId: ‘amount’,

                 value: penaltyAmount

             });

             invObject.commitLine({

                 sublistId: ‘item’

             })

             if (checkForParameter(custEmailId)) {

                 log.debug(“Entered ***”)

                 let emailSent = sentEmails(totalDue, custEmailId, invoiceObject.doumentNumber, invoiceObject.customerIds, penaltyApplied)

                 let ordDate = new Date();

                 let newDate = ordDate.getDate(), newMonth = ordDate.getMonth() + 1, newYear = ordDate.getFullYear();

                 let newFormattedDate = newMonth + “/” + newDate + “/” + newYear;

                 log.debug(“newFormattedDate”, newFormattedDate)

                 let parsedDateIs = format.parse({

                     value: newFormattedDate,

                     type: format.Type.DATE,

                 });

                 if (emailSent && invoiceObject.dueDays == 45) {

                    invObject.setValue({

                        fieldId:‘custbody_jj_date_intervals’,

                        value: parsedDateIs

                    });

                    invObject.setValue({

                        fieldId:‘custbody_jj_inv_due_email_sent’,

                        value: true

                    });

                    invObject.save({

                             enableSourcing: true,

                             ignoreMandatoryFields: true

                         });

                   

                 }

                 else if (emailSent && invoiceObject.dueDays == 30) {

                    invObject.setValue({

                        fieldId:‘custbody_jj_date_intervals’,

                        value: parsedDateIs

                    });

                    invObject.save({

                             enableSourcing: true,

                             ignoreMandatoryFields: true

                         });

                   

                 }

             }

         } catch (e) {

             log.error(“error@addPenaltyItems”, e)

             return false;

         }

     }

     /**

      * Defines the function that is executed at the beginning of the map/reduce process and generates the input data.

      * @param {Object} inputContext

      * @param {boolean} inputContext.isRestarted – Indicates whether the current invocation of this function is the first

      *     invocation (if true, the current invocation is not the first invocation and this function has been restarted)

      * @param {Object} inputContext.ObjectRef – Object that references the input data

      * @typedef {Object} ObjectRef

      * @property {string|number} ObjectRef.id – Internal ID of the record instance that contains the input data

      * @property {string} ObjectRef.type – Type of the record instance that contains the input data

      * @returns {Array|Object|Search|ObjectRef|File|Query} The input data to use in the map/reduce process

      * @since 2015.2

      */

     const getInputData = (inputContext) => {

         try {

             let invoiceOrderArrayFourtyFive = getInvoicesDueFourtyFiveDays()

             let invoiceArrayThirty = getInvoicesThirtyIntervals()

             if (invoiceOrderArrayFourtyFive.length > 0 || invoiceArrayThirty.length > 0) {

                 log.debug(“RESULTS”, invoiceOrderArrayFourtyFive.concat(invoiceArrayThirty))

                 return invoiceOrderArrayFourtyFive.concat(invoiceArrayThirty);

             } else {

                 return [];

             }

         } catch (e) {

             log.error(“error@getInputData”, e)

             return []

         }

     }

     /**

      * Defines the function that is executed when the reduce entry point is triggered. This entry point is triggered

      * automatically when the associated map stage is complete. This function is applied to each group in the provided context.

      * @param {Object} reduceContext – Data collection containing the groups to process in the reduce stage. This parameter is

      *     provided automatically based on the results of the map stage.

      * @param {Iterator} reduceContext.errors – Serialized errors that were thrown during previous attempts to execute the

      *     reduce function on the current group

      * @param {number} reduceContext.executionNo – Number of times the reduce function has been executed on the current group

      * @param {boolean} reduceContext.isRestarted – Indicates whether the current invocation of this function is the first

      *     invocation (if true, the current invocation is not the first invocation and this function has been restarted)

      * @param {string} reduceContext.key – Key to be processed during the reduce stage

      * @param {List<String>} reduceContext.values – All values associated with a unique key that was passed to the reduce stage

      *     for processing

      * @since 2015.2

      */

     const reduce = (reduceContext) => {

         try {

             let invoiceObject = JSON.parse(reduceContext.values)

             let scriptObj = runtime.getCurrentScript();

             let penaltyPercentageFourtyFive = scriptObj.getParameter({ name: ‘custscript_jj_penalty_percentage45’ });

             let penaltyPercentageThirty = scriptObj.getParameter({ name: ‘custscript_jj_penalty_percentage30’ });

             let custEmailId=invoiceObject.custEmails

             if (invoiceObject.dueDays == 45) {

                 let penaltyfourtyFive = (Number(penaltyPercentageFourtyFive)) / 100

                 log.debug(“penaltyfourtyFive 45”, penaltyfourtyFive)

                 addPenaltyItems(invoiceObject, penaltyfourtyFive, penaltyPercentageFourtyFive,custEmailId)

             } else if (invoiceObject.dueDays == 30) {

                 let penaltyThirty = (Number(penaltyPercentageThirty)) / 100

                 log.debug(“penaltyThirty 30”, penaltyThirty)

                 addPenaltyItems(invoiceObject, penaltyThirty, penaltyPercentageThirty,custEmailId)

             }

         } catch (e) {

             log.error(“error@reduce”, e)

         }

     }

     return { getInputData, reduce }

 });

Leave a comment

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