/**
* @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 Attendance Sync from HRIMS
*
* REVISION HISTORY
*
****************************************************** *****************************************/
define([
"N/record",
"N/https",
"N/format",
"N/file",
"./jj_cm_hrims_module"
], (record, https, format, file, _hrims_module) => {
// Employee Attendance Mapping Fields
const MAPPING_FIELDS = {
"TotalTimeinOfficeHours": "custrecord_jj_total_time_in_office",
"OutTime": "custrecord_jj_out_time",
"LastModifiedDate": "custrecord_last_modified_date",
"InTime": "custrecord_jj_in_time",
"DailyAttendanceRecordId": "custrecord_jj_hrims_attendance_rec_id",
"AttendanceStatus": "custrecord_jj_attendance_status",
"AttendanceDate": "custrecord_jj_attendance_date",
"EmployeeNumber": "custrecord_jj_hrims_emp_number",
"NetsuiteEmployeeId": "custrecord_jj_netsuite_employee",
}
/**
* Function will prepare the Attendance Data
* @param {Object} attendanceObj
* @param {String} hrimsEmployeeNumber
* @param {String} netSuiteEmployeeId
* @returns Object
*/
const prepareAttendanceData = (attendanceObj, hrimsEmployeeNumber, netSuiteEmployeeId) => {
try {
return {
"TotalTimeinOfficeHours": attendanceObj["TotalTimeinOfficeHours"],
"OutTime": attendanceObj["OutTime"],
"LastModifiedDate": attendanceObj["LastModifiedDate"],
"InTime": attendanceObj["InTime"],
"DailyAttendanceRecordId": attendanceObj["DailyAttendanceRecordId"],
"AttendanceStatus": attendanceObj["AttendanceStatus"],
"AttendanceDate": attendanceObj["AttendanceDate"],
"EmployeeNumber": hrimsEmployeeNumber,
"NetsuiteEmployeeId": netSuiteEmployeeId
};
} catch (error) {
log.error("Error in prepareAttendanceData", error);
}
}
/**
* Function will create Attendance Record
* @param {Object} attendanceObj
* @param {String} hrimsEmployeeNumber
* @param {String} netSuiteEmployeeId
* @returns Object
*/
const createAttendanceRecord = (attendanceObj, hrimsEmployeeNumber, netSuiteEmployeeId) => {
try {
let attendanceData = prepareAttendanceData(attendanceObj, hrimsEmployeeNumber, netSuiteEmployeeId);
log.error("Attendance Data", attendanceData);
let createAttendanceRec = record.create({
type: "customrecord_jj_hrims_emp_attendance",
});
for (let key in attendanceData) {
if (['OutTime', 'InTime', 'LastModifiedDate'].includes(key) && attendanceData[key]) {
createAttendanceRec.setValue({
fieldId: MAPPING_FIELDS[key],
value: format.parse({ type: format.Type.DATE, value: new Date(attendanceData[key]) })
});
} else if (['AttendanceDate'].includes(key) && attendanceData[key]) {
let attendanceDate = new Date(attendanceData[key]);
attendanceDate.setDate(attendanceDate.getDate() + 1);
createAttendanceRec.setValue({ fieldId: MAPPING_FIELDS[key], value: attendanceDate });
} else {
createAttendanceRec.setValue({ fieldId: MAPPING_FIELDS[key], value: attendanceData[key] });
}
}
return { status: "success", recordId: createAttendanceRec.save(), error: [] };
} catch (error) {
log.error("Error in createAttendanceRecord", error);
return { status: "error", recordId: null, error: [error.message] };
}
}
/**
* // Function will update Attendance Record
* @param {Object} attendanceObj
* @param {String} netSuiteAttendanceId
* @returns Object
*/
const updateAttendanceRecord = (attendanceObj, netSuiteAttendanceId) => {
try {
let isRecordUpdated = false;
let LoadAttendanceRec = record.load({
type: "customrecord_jj_hrims_emp_attendance",
id: netSuiteAttendanceId
});
// TotalTimeinOfficeHours
let netsuiteTotalTime = LoadAttendanceRec.getValue({ fieldId: "custrecord_jj_total_time_in_office" }) || null;
let hrimsTotalTime = attendanceObj["TotalTimeinOfficeHours"];
if (netsuiteTotalTime != hrimsTotalTime) {
LoadAttendanceRec.setValue({ fieldId: "custrecord_jj_total_time_in_office", value: hrimsTotalTime });
isRecordUpdated = true;
}
// InTime
let netsuiteInTime = LoadAttendanceRec.getValue({ fieldId: "custrecord_jj_in_time" }) || null;
let hrimsInTime = attendanceObj["InTime"];
if (new Date(netsuiteInTime).getTime() != new Date(hrimsInTime).getTime()) {
LoadAttendanceRec.setValue({ fieldId: "custrecord_jj_in_time", value: _hrims_module.parseDate(attendanceObj["InTime"]) });
isRecordUpdated = true;
}
// OutTime
let netsuiteOutTime = LoadAttendanceRec.getValue({ fieldId: "custrecord_jj_out_time" }) || null;
let hrimsOutTime = attendanceObj["OutTime"];
if (new Date(netsuiteOutTime).getTime() != new Date(hrimsOutTime).getTime()) {
LoadAttendanceRec.setValue({ fieldId: "custrecord_jj_out_time", value: _hrims_module.parseDate(attendanceObj["OutTime"]) });
isRecordUpdated = true;
}
// LastModifiedDate
let netsuiteLastModifiedDate = LoadAttendanceRec.getValue({ fieldId: "custrecord_last_modified_date" }) || null;
let hrimsLastModifiedDate = attendanceObj["LastModifiedDate"];
if (new Date(netsuiteLastModifiedDate).getTime() != new Date(hrimsLastModifiedDate).getTime()) {
LoadAttendanceRec.setValue({ fieldId: "custrecord_last_modified_date", value: _hrims_module.parseDate(attendanceObj["LastModifiedDate"]) });
isRecordUpdated = true;
}
// AttendanceStatus
let netsuiteAttendanceStatus = LoadAttendanceRec.getValue({ fieldId: "custrecord_jj_attendance_status" }) || null;
let hrimsAttendanceStatus = attendanceObj["AttendanceStatus"];
if (netsuiteAttendanceStatus != hrimsAttendanceStatus) {
LoadAttendanceRec.setValue({ fieldId: "custrecord_jj_attendance_status", value: hrimsAttendanceStatus });
isRecordUpdated = true;
}
// AttendanceDate
let netsuiteAttendanceDate = LoadAttendanceRec.getText({ fieldId: "custrecord_jj_attendance_date" }) || null;
let hrimsAttendanceDate = attendanceObj["AttendanceDate"] || null;
if (hrimsAttendanceDate) {
hrimsAttendanceDate = new Date(attendanceObj["AttendanceDate"]);
let hrimsParsedAttendanceDate = hrimsAttendanceDate ? hrimsAttendanceDate.setDate(hrimsAttendanceDate.getDate() + 1) : null;
hrimsAttendanceDate = _hrims_module.formatDate(hrimsParsedAttendanceDate);
}
if (netsuiteAttendanceDate != hrimsAttendanceDate) {
LoadAttendanceRec.setText({ fieldId: "custrecord_jj_attendance_date", text: hrimsAttendanceDate });
isRecordUpdated = true;
}
log.error(`isRecordUpdated for ${attendanceObj["DailyAttendanceRecordId"]}`, isRecordUpdated);
if (isRecordUpdated) {
return { status: "success", recordId: LoadAttendanceRec.save(), error: [] };
} else {
return { status: "Updation not required", recordId: LoadAttendanceRec.id, error: [] };
}
} catch (error) {
log.error("Error in updateAttendanceRecord", error);
return { status: "error", recordId: null, error: [error.message] };
}
}
const getInputData = (inputContext) => {
try {
log.error("---ATTENDANCE SYNC STARTS---");
// Generate the Access Token
const accessTokenResponse = _hrims_module.generateAccessToken();
if (accessTokenResponse.status != 'success') {
log.error('Access Token is Invalid', accessTokenResponse.result);
return [];
}
// Fetch the Attendance Data from HRIMS
const attendanceApiResponse = _hrims_module.fetchApiData('attendance', accessTokenResponse.result);
if (attendanceApiResponse.status !== 'success') {
log.error('Attendance API is Invalid', attendanceApiResponse.result);
return [];
}
// Prepare the Attendance Data for the Map Reduce
const attendanceData = attendanceApiResponse.result.flatMap(employee =>
employee.AttendanceList.map(attendance => ({
EmployeeNumber: employee.EmployeeNumber,
...attendance
}))
);
return attendanceData;
} catch (error) {
log.error("Error in getInputData", error);
return [];
}
}
const reduce = (reduceContext) => {
try {
let attendanceObj = JSON.parse(reduceContext.values);
let hrimsAttendanceId = attendanceObj['DailyAttendanceRecordId'];
if (!hrimsAttendanceId) {
reduceContext.write({
key: hrimsAttendanceId || reduceContext.key,
value: {
status: "error",
recordId: '',
error: ['Attendance ID is not found in the HRIMS']
}
});
return;
}
let hrimsEmployeeNumber = attendanceObj['EmployeeNumber'];
if (!hrimsEmployeeNumber) {
reduceContext.write({
key: hrimsAttendanceId,
value: {
status: "error",
recordId: '',
error: ['Employee Number is not found in the HRIMS']
}
});
return false;
}
// Search for the HRIMS Employee in NetSuite
let netSuiteEmployeeObj = _hrims_module.findEmployeeInNetsuite(hrimsEmployeeNumber);
if (!netSuiteEmployeeObj.id) {
reduceContext.write({
key: hrimsAttendanceId,
value: {
status: "error",
recordId: '',
error: [`Employee: ${hrimsEmployeeNumber} is not found in NetSuite`]
}
});
return false;
}
let netSuiteAttendanceId = _hrims_module.findAttendanceInNetsuite(hrimsAttendanceId);
let recordActionResponse = {};
if (netSuiteAttendanceId) {
log.error("---ATTENDANCE UPDATION---", attendanceObj["DailyAttendanceRecordId"]);
/****************************
* ATTENDANCE RECORD UPDATION
*****************************/
recordActionResponse = updateAttendanceRecord(attendanceObj, netSuiteAttendanceId);
log.error('Attendance Record Action', recordActionResponse);
} else {
log.error("---ATTENDANCE CREATION---", attendanceObj["DailyAttendanceRecordId"]);
/****************************
* ATTENDANCE RECORD CREATION
*****************************/
recordActionResponse = createAttendanceRecord(attendanceObj, hrimsEmployeeNumber, netSuiteEmployeeObj.id);
log.error('Attendance Record Action', recordActionResponse);
}
reduceContext.write({ key: hrimsAttendanceId, value: recordActionResponse });
} catch (error) {
log.error("Error in reduce", error);
reduceContext.write({ key: hrimsAttendanceId, 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,
contents: csvFileData
});
fileID = fileObj.save();
log.error("Error File Created", fileID);
}
log.error("---ATTENDANCE SYNC COMPLETED---");
} catch (error) {
log.error("Error in summarize", error);
}
}
return { getInputData, reduce, summarize }
});