HRIMS Employee Sync

/**
 * @NApiVersion 2.1
 * @NScriptType MapReduceScript
 */
/***********************************************
 * ATPL-67 - Implementation | HRIMS Integration
 * *********************************************
 *
 * Author: Jobin & Jismi IT Services LLP
 *
 * Date Created : 05-February-2024
 *
 * Created By: JJ0124, Jobin & Jismi IT Services LLP
 *
 * Description : Map Reduce script is used to perfrom the Employee Sync from HRIMS
 *
 * REVISION HISTORY
 *
 ***********************************************************************************************/
define([
    "N/record",
    "N/https",
    "N/runtime",
    "N/file",
    "N/email",
    "N/search",
    "./jj_cm_hrims_module",
], (record, https, runtime, file, email, search, _hrims_module) => {

    /**
     * Function will update the employee record in NetSuite
     * @param {Object} employeeObj 
     * @param {String} employeeId 
     * @returns Object
     */
    const updateEmployee = (employeeObj, empId, rm, netsuiteSubsidiary) => {
        try {
            let ERROR_STACK = [];
            let isRecordUpdated = false;

            let loadEmpRec = record.load({
                type: record.Type.EMPLOYEE,
                id: empId,
                isDynamic: true
            });

            // First Name
            let currentFirstName = loadEmpRec.getValue({ fieldId: "firstname" }) || null;
            let hrimsFirstName = employeeObj["FirstName"];
            if (currentFirstName != hrimsFirstName) {
                loadEmpRec.setValue("firstname", hrimsFirstName);
                isRecordUpdated = true;
            }

            // Last Name
            let currentLastName = loadEmpRec.getValue({ fieldId: "lastname" }) || null;
            let hrimsLastName = employeeObj["LastName"];
            if (currentLastName != hrimsLastName) {
                loadEmpRec.setValue("lastname", hrimsLastName);
                isRecordUpdated = true;
            }

            // Email
            let currentEmail = loadEmpRec.getValue({ fieldId: "email" }) || null;
            let hrimsEmail = employeeObj["EmailAddress"];
            if (currentEmail != hrimsEmail) {
                loadEmpRec.setValue("email", employeeObj["EmailAddress"]);
                isRecordUpdated = true;
            }

            // Mobile
            let currentMobile = loadEmpRec.getText({ fieldId: "mobilephone" }) || null;
            let hrimsMobile = employeeObj["Mobile"];
            if (hrimsMobile != currentMobile) {
                if (hrimsMobile && hrimsMobile.length > 6) {
                    loadEmpRec.setValue("mobilephone", hrimsMobile);
                    isRecordUpdated = true;
                } else {
                    ERROR_STACK.push("Mobile Number should contain atleast 7 digits");
                }
            }

            // Inactive
            currentInactive = loadEmpRec.getValue({ fieldId: "isinactive" });
            let hrimsInactive = employeeObj["InActive"];
            if (currentInactive != hrimsInactive) {
                loadEmpRec.setValue("isinactive", employeeObj["InActive"]);
                isRecordUpdated = true;
            }

            // Job Title
            let currentDesignation = loadEmpRec.getValue({ fieldId: "title" }) || null;
            let hrimsDesignation = employeeObj["Designation"];
            if (hrimsDesignation != currentDesignation) {
                loadEmpRec.setValue("title", hrimsDesignation);
                isRecordUpdated = true;
            }

            // Total Experience
            let currentTotalExperience = loadEmpRec.getValue({ fieldId: "custentity_jj_total_exp" }) || null;
            let hrimsTotalExperience = employeeObj["TotalExperience"];
            if (hrimsTotalExperience != currentTotalExperience) {
                loadEmpRec.setValue("custentity_jj_total_exp", hrimsTotalExperience);
                isRecordUpdated = true;
            }

            // Prior Experience
            let currentPriorExperience = loadEmpRec.getValue({ fieldId: "custentity_jj_prvs_exp" }) || null;
            let hrimsPriorExperience = employeeObj["PriorExperience"];
            if (hrimsPriorExperience != currentPriorExperience) {
                loadEmpRec.setValue("custentity_jj_prvs_exp", hrimsPriorExperience);
                isRecordUpdated = true;
            }

            // Employee Status
            let currentEmployeeStatus = loadEmpRec.getText({ fieldId: "employeetype" }) || null;
            let hrimsEmployeeStatus = employeeObj["EmployeeStatus"];
            if (hrimsEmployeeStatus != currentEmployeeStatus) {
                loadEmpRec.setText("employeetype", hrimsEmployeeStatus);
                isRecordUpdated = true;
            }

            // Is Sales Rep
            let currentIsSalesRep = loadEmpRec.getValue({ fieldId: "issalesrep" });
            let hrimsIsSalesRep = employeeObj["isSalesRep"];
            if (hrimsIsSalesRep != currentIsSalesRep) {
                loadEmpRec.setValue("issalesrep", hrimsIsSalesRep);
                isRecordUpdated = true;
            }

            // Is Project Resource
            let currentIsProjectResource = loadEmpRec.getValue({ fieldId: "isjobresource" });
            let hrimsIsProjectResource = employeeObj["isProjectResource"];
            if (hrimsIsProjectResource != currentIsProjectResource) {
                loadEmpRec.setValue("isjobresource", hrimsIsProjectResource);
                isRecordUpdated = true;
            }

            // Is Project Manager
            let currentIsProjectManager = loadEmpRec.getValue({ fieldId: "isjobmanager" });
            let hrimsIsProjectManager = employeeObj["isProjectManager"];
            if (hrimsIsProjectManager != currentIsProjectManager) {
                loadEmpRec.setValue("isjobmanager", hrimsIsProjectManager);
                isRecordUpdated = true;
            }

            // Location
            let currentLocation = loadEmpRec.getValue({ fieldId: "custentity_jj_emp_work_loc" });
            let locationId = _hrims_module.getLocationId(employeeObj["LocationName"], employeeObj["LocationId"]);
            let hrimsLocation = employeeObj["LocationName"];
            if ((currentLocation != locationId) && hrimsLocation) {
                if (locationId) {
                    loadEmpRec.setValue("custentity_jj_emp_work_loc", locationId);
                    isRecordUpdated = true;
                } else {
                    loadEmpRec.setValue("custentity_jj_emp_work_loc", "");
                    ERROR_STACK.push(`Work Location- ${hrimsLocation} is not found in NetSuite`);
                }
            } else if (!currentLocation && !locationId && hrimsLocation) {
                ERROR_STACK.push(`Work Location- ${hrimsLocation} is not found in NetSuite`);
            }

            // Cost Center
            let currentCostCenter = loadEmpRec.getValue({ fieldId: "department" }) || null;
            let costCenterId = _hrims_module.getCostCenterId(employeeObj["Employee_Costcenter"]);
            let hrimsCostCenter = employeeObj["Employee_Costcenter"];
            if ((currentCostCenter != costCenterId) && hrimsCostCenter) {
                if (costCenterId) {
                    loadEmpRec.setValue("department", costCenterId);
                    isRecordUpdated = true;
                } else {
                    loadEmpRec.setValue("department", "");
                    ERROR_STACK.push(`Cost Center- ${hrimsCostCenter} is not found in NetSuite`);
                }
            } else if (!currentCostCenter && !costCenterId && hrimsCostCenter) {
                ERROR_STACK.push(`Cost Center- ${hrimsCostCenter} is not found in NetSuite`);
            }

            // Date Of Join
            let netsuiteDate = loadEmpRec.getText({ fieldId: "hiredate" }) || null;
            let hrimsDate = employeeObj["DateofJoining"] || null;
            if (hrimsDate) {
                hrimsDate = new Date(employeeObj["DateofJoining"]);
                let hrimsParsedDate = hrimsDate ? hrimsDate.setDate(hrimsDate.getDate() + 1) : null;
                hrimsDate = _hrims_module.formatDate(hrimsParsedDate);
            }
            if (netsuiteDate != hrimsDate) {
                loadEmpRec.setText({ fieldId: "hiredate", text: hrimsDate });
                isRecordUpdated = true;
            }

            // Reporting Manager
            let currentRmId = loadEmpRec.getValue({ fieldId: "supervisor" });
            if (rm.id != currentRmId) {
                if (_hrims_module.checkForParameter(rm.id) && rm.isInactive != 'T') {
                    loadEmpRec.setValue("supervisor", rm.id);
                    isRecordUpdated = true;
                }
            }

            // Last Modified By          
            let currentLastModifiedBy = loadEmpRec.getValue({ fieldId: "custentity_jj_hrims_last_modified_by" });
            let hrimsLastModifiedBy = _hrims_module.findEmployeeInNetsuite(employeeObj["LastModifiedby"]);
            if (hrimsLastModifiedBy.id && (hrimsLastModifiedBy.id != currentLastModifiedBy)) {
                if (_hrims_module.checkForParameter(hrimsLastModifiedBy.id) && (hrimsLastModifiedBy.isInactive != true)) {
                    loadEmpRec.setValue("custentity_jj_hrims_last_modified_by", hrimsLastModifiedBy.id);
                    isRecordUpdated = true;
                }
            }

            // Last Modified Date
            let currentLastModifiedDate = loadEmpRec.getValue({ fieldId: "custentity_jj_hrims_last_modified_date" });
            let hrmisLastModifiedDate = new Date(employeeObj["LastModifieddate"]);
            if (new Date(currentLastModifiedDate).getTime() != hrmisLastModifiedDate.getTime()) {
                loadEmpRec.setValue("custentity_jj_hrims_last_modified_date", _hrims_module.parseDate(employeeObj['LastModifieddate']));
                isRecordUpdated = true;
            }

            // Address Creation/Updation in Employee Record.
            isAddressUpdated = _hrims_module.upsertAddress(employeeObj, loadEmpRec, 'Permanent');
            isAddressUpdated = _hrims_module.upsertAddress(employeeObj, loadEmpRec, 'Present');

            log.error(`isRecordUpdated for ${employeeObj["EmployeeNumber"]}`, isRecordUpdated || isAddressUpdated);
            if (isRecordUpdated || isAddressUpdated) {
                return { status: "success", recordId: loadEmpRec.save(), error: ERROR_STACK };
            } else {
                return { status: "Updation not required", recordId: loadEmpRec.id, error: ERROR_STACK };
            }
        } catch (error) {
            log.error("Error in updateEmployee", error);
            return { status: "error", recordId: null, error: [error.message] };
        }
    }

    /**
     * Function will create the RM Employee record in NetSuite
     * @param {String} hrimsRM 
     * @returns netsuiteRM
     */
    const rmRecordCreation = (hrimsRM) => {
        try {
            const accessTokenResponse = _hrims_module.generateAccessToken();
            if (accessTokenResponse.status != 'success') {
                return { status: 'error', result: accessTokenResponse.result };
            }

            const employeeApiResponse = _hrims_module.fetchApiData('employee', accessTokenResponse.result, hrimsRM);
            if (employeeApiResponse.status !== 'success') {
                return { status: 'error', result: employeeApiResponse.result };
            }

            let empObject = employeeApiResponse.result[0]; // RM Employee Object
            let hrimsEmpId = empObject["EmployeeNumber"];
            let isNameProvided = empObject["FirstName"] || empObject["LastName"];
            let hrimsSubsidiary = empObject["Subsidiary"];

            // Checks whether the mandatory fields for creating RM Employee in NetSuite. 
            if (!hrimsEmpId || !isNameProvided || !hrimsSubsidiary) {
                return { status: 'error', result: 'Name and Subsidairy are required for Employee Creation' };
            }

            // Checks whether the Subsidiary is present in NetSuite
            let netsuiteSubsidiary = _hrims_module.getSubsidiaryId(hrimsSubsidiary);
            if (!netsuiteSubsidiary) {
                return { status: 'error', result: `Following Subsidiary: ${hrimsSubsidiary} is not found in NetSuite` };
            }

            let currentRm = _hrims_module.findEmployeeInNetsuite(empObject["ReportingManager"]);
            let netsuiteRM = _hrims_module.createEmployee(empObject, netsuiteSubsidiary, currentRm);

            return netsuiteRM;
        } catch (error) {
            log.error('Error in rmRecordCreation', error);
            return { status: 'error', result: error.message };
        }
    }

    const getInputData = (inputContext) => {
        try {
            log.error('--- EMPLOYEE SYNC STARTS ---');

            const accessTokenResponse = _hrims_module.generateAccessToken();

            if (accessTokenResponse.status != 'success') {
                log.error('Access Token is Invalid', accessTokenResponse.result);
                return [];
            }

            const employeeApiResponse = _hrims_module.fetchApiData('employee', accessTokenResponse.result);

            if (employeeApiResponse.status !== 'success') {
                log.error('Employee API is Invalid', employeeApiResponse.result);
                return [];
            }

            return employeeApiResponse.result;
        } catch (error) {
            log.error("Error in getInputData", error);
            return [];
        }
    }

    const reduce = (reduceContext) => {
        try {
            let scriptObj = runtime.getCurrentScript();
            let employeeObj = JSON.parse(reduceContext.values);
            log.error("Employee Object", employeeObj);
            let hrimsEmpId = employeeObj["EmployeeNumber"];
            let isNameProvided = employeeObj["FirstName"] || employeeObj["LastName"];
            let hrimsSubsidiary = employeeObj["Subsidiary"];

            // Checks whether the mandatory fields for creating Employee in NetSuite. 
            if (!hrimsEmpId || !isNameProvided || !hrimsSubsidiary) {
                reduceContext.write({
                    key: hrimsEmpId || reduceContext.key,
                    value: {
                        status: "error",
                        recordId: '',
                        error: ['Name and Subsidairy are required for Employee Creation']
                    }
                });
                return false;
            }

            // Checks whether the Subsidiary is present in NetSuite
            let netsuiteSubsidiary = _hrims_module.getSubsidiaryId(hrimsSubsidiary);
            if (!netsuiteSubsidiary) {
                reduceContext.write({
                    key: hrimsEmpId,
                    value: {
                        status: "error",
                        recordId: null,
                        error: [`Following Subsidiary: ${hrimsSubsidiary} is not found in NetSuite`]
                    }
                });
                return false;
            }

            let hrimsRM = employeeObj["ReportingManager"];
            let netsuiteRM = _hrims_module.findEmployeeInNetsuite(hrimsRM);
            // Check the RM is exists in NetSuite. If not create RM employee record.
            if (!netsuiteRM.id && hrimsRM) {
                let rmRecordResponse = rmRecordCreation(hrimsRM);
                log.error('rmRecordResponse', rmRecordResponse)
                if (rmRecordResponse.status == 'success') {
                    netsuiteRM = { id: rmRecordResponse.recordId, isInactive: false };
                }
            }

            let netsuiteEmp = _hrims_module.findEmployeeInNetsuite(hrimsEmpId);
            let recordActionResponse = "";
            if (_hrims_module.checkForParameter(netsuiteEmp.id)) {
                log.error("---EMPLOYEE UPDATION---", netsuiteEmp);
                /********************
                 * EMPLOYEE UPDATION
                 ********************/
                recordActionResponse = updateEmployee(employeeObj, netsuiteEmp.id, netsuiteRM, netsuiteSubsidiary);
                log.error("UPDATION RESPONSE", recordActionResponse);
            } else {
                let isInactive = employeeObj["InActive"];
                if (isInactive) { return false; }
              
                log.error("---EMPLOYEE CREATION---", hrimsEmpId);
                /********************
                 * EMPLOYEE CREATION
                 ********************/
                recordActionResponse = _hrims_module.createEmployee(employeeObj, netsuiteSubsidiary, netsuiteRM);
                log.error("CREATION RESPONSE", recordActionResponse);
            }

            reduceContext.write({ key: hrimsEmpId, value: recordActionResponse });
        } catch (error) {
            log.error("Error in reduce", error);
            reduceContext.write({ key: hrimsEmpId, value: { status: "error", recordId: null, error: [error.message] } });
        }
    }

    const summarize = (summaryContext) => {
        try {
            let titleArray = ["HRIMS ID", "Error Description"];
            let csvFileData = titleArray.toString() + 'rn';
            let flag = 0, fileID = "";

            summaryContext.output.iterator().each(function (key, value) {
                let parseSummary = JSON.parse(value);
                if (parseSummary.error.length > 0) {
                    flag = flag + 1;
                    let hrimsId = key
                    let errors = parseSummary.error.join(' ; ');
                    csvFileData += hrimsId + ',' + errors.replace(',', " ") + 'rn';
                }

                return true;
            });

            if (flag > 0) {
                let fileObj = file.create({
                    name: 'ERROR-File Created' + '-' + Math.floor(Date.now() / 1000) + '.csv',
                    fileType: file.Type.CSV,
                    folder: 1170, // Error Folder ID in Acsia Production Account 1170
                    contents: csvFileData
                });
                let hrimConfigLookup = search.lookupFields({
                    type: "customrecord_jj_hrims_configuration",
                    id: 1,
                    columns: ["custrecord_hrims_email_recipient"]
                });
                let emailRecipientStr = hrimConfigLookup["custrecord_hrims_email_recipient"] || "";
                let reciepientArray = emailRecipientStr.split(",")
                fileID = fileObj.save();
                log.error("Error File Created", fileID);
  
                let body = 'This is an automated email from the NetSuite system.nn' +
                       'Errors were detected during the HRIMS Employee synchronization process to NetSuite. ' +
                       'Please find the attached document containing the details of the errors.';
                email.send({
                     author: 1610,
                     recipients: reciepientArray,
                     subject: 'Action Required: Errors Detected in HRIMS Employee Sync to NetSuite',
                     body: body,
                     attachments: [fileObj],
                });
            }
            log.error("--- EMPLOYEE SYNC COMPLETED ---");
        } catch (error) {
            log.error("Error in summarize", error);
        }
    }

    return { getInputData, reduce, summarize }
});

Leave a comment

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