/**
* @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 }
});