const onAction = (scriptContext) => {
try {
//log.debug('Script Execution Started', scriptContext);
let recordObj = scriptContext.newRecord;
let getdate = recordObj.getValue({ fieldId: 'trandate' });
let hoursTracked = recordObj.getValue({ fieldId: 'hours' });
let project = recordObj.getValue({ fieldId: 'customer' });
let employee = recordObj.getValue({ fieldId: 'employee' });
let projectAllocationId = recordObj.getValue({ fieldId: 'custcol_jj_project_allocation' });
log.debug('Record Details', { date: getdate, hoursTracked, project, employee, projectAllocationId });
let date = new Date(getdate);
let month = date.getMonth() + 1;
let year = date.getFullYear();
let formattedStartDate = format.format({ value: date, type: format.Type.DATE });
//log.debug('Formatted start date', formattedStartDate);
let employeeWorkCalendarId = getEmployeeWorkCalendar(employee);
let minWorkHours = getWorkCalendarHours(employeeWorkCalendarId);
log.debug('Employee min Work hr', minWorkHours)
let payrollId = getPayrollDetails(employee, month, year, project);
let timeBillDetails = getTimeBillsData(employee, formattedStartDate);
log.debug('Payroll & TimeBill Details', { payrollId, timeBillDetails });
let approvedTimebill = timeBillDetails.approvedTimesheets || [];
let existingEntry = approvedTimebill.find(entry => entry.projectAllocationId === projectAllocationId);
if (existingEntry) {
// If the projectAllocationId already exists, add to the existing hours
existingEntry.hours += hoursTracked;
} else {
// If it doesn't exist, push a new entry
if (project !== LEAVE_PROJECT) {
approvedTimebill.push({
employee: employee,
donor: project,
hours: hoursTracked,
projectAllocationId: projectAllocationId
});
}
}
log.debug('Approved Time Sheets After Addition', approvedTimebill);
if ((approvedTimebill.length === 1) && (project !== LEAVE_PROJECT)) {
updateTrackedHoursForProjectAllocation(projectAllocationId, minWorkHours, formattedStartDate);
}
else {
// let totalTime = approvedTimebill.reduce((sum, item) => sum + item.hours, 0);
// log.debug('Total Time Calculated', totalTime);
let updatedApprovedTimebill = [...approvedTimebill]; // Copy existing timebill entries
if (project === LEAVE_PROJECT) {
let allProjectAllocationArray = getAllProjectsAllocations(payrollId);
log.debug('All Project Allocations', allProjectAllocationArray);
allProjectAllocationArray.forEach(allocation => {
let projectAllocationId = allocation.ProjectAllocationId;
let budgetAllocationPercent = parseFloat(allocation.budgetedAllocationPercent) || 0;
let budgetAllocation = budgetAllocationPercent / 100;
// Calculate prorated leave hours for this project allocation
let proratedHours = hoursTracked * budgetAllocation;
let existingEntry = updatedApprovedTimebill.find(entry => entry.projectAllocationId === projectAllocationId);
if (existingEntry) {
// If found, update existing entry by adding prorated hours
existingEntry.hours += proratedHours;
} else {
// If not found, create a new entry
updatedApprovedTimebill.push({
projectAllocationId: projectAllocationId,
hours: proratedHours,
donor: allocation.donor // Ensure donor is included for checking LEAVE_PROJECT
});
}
});
// Step 1: Create a Set of projectAllocationIds already in updatedApprovedTimebill
let existingProjectAllocationIds = new Set(updatedApprovedTimebill.map(entry => entry.projectAllocationId));
// Step 2: Append only non-duplicate entries from approvedTimebill
approvedTimebill.forEach(entry => {
if (!existingProjectAllocationIds.has(entry.projectAllocationId) && entry.donor !== LEAVE_PROJECT) {
updatedApprovedTimebill.push(entry);
existingProjectAllocationIds.add(entry.projectAllocationId); // Add to Set to track duplicates
}
});
// Step 3: Log the final updated time allocations
log.debug('Final Approved Timebill after Leave Hours Distribution', updatedApprovedTimebill);
}
let totalTime = updatedApprovedTimebill.reduce((sum, item) => sum + item.hours, 0);
log.debug('Total Time after Leave Distribution', totalTime);
for (let entry of updatedApprovedTimebill) {
//log.debug('Processing Approved Time Bill', entry);
if (entry.donor !== LEAVE_PROJECT) {
// **Regular Project Allocation Logic**
log.debug('currentApprovedProHrs Calculation',
`(${minWorkHours} * (${entry.hours} ) / ${totalTime}`);
let currentApprovedProHrs = (minWorkHours * entry.hours) / totalTime;
currentApprovedProHrs = currentApprovedProHrs !== 0 ? parseFloat(currentApprovedProHrs) : 0;
log.debug('Current Approved Pro-rated Hours', { projectAllocationId: entry.projectAllocationId, currentApprovedProHrs });
updateTrackedHoursForProjectAllocation(entry.projectAllocationId, currentApprovedProHrs, formattedStartDate);
}
}
}
updatePayrollTrackedHours(payrollFlag, payrollId, minWorkHours);
} catch (e) {
log.error('Error in onAction', e);
}
};
return { onAction };
});
Retrieve Key Record Values
Extracts important field values from the transaction record, such as date, hours tracked, project, employee, and project allocation ID.
Format Date & Get Employee Work Hours
Converts the transaction date into a formatted string.
Fetches the employee's work calendar to determine their minimum required work hours.
Retrieve Payroll & Time Bill Data
Fetches payroll details for the employee for the given month and year.
Retrieves previously approved time entries for the employee on that date.
Check for Existing Time Entries
Searches for an existing entry with the same project allocation ID in the approved time bills.
If found, adds the new tracked hours to the existing entry.
If not found, creates a new entry (excluding leave projects).
Update Time Tracking for Single Entry
If there is only one non-leave project entry, updates the project allocation’s tracked hours with the minimum work hours.
Handle Leave Project Hours
Retrieves all project allocations associated with the employee’s payroll.
Distributes leave hours proportionally across project allocations based on budgeted allocation percentages.
Merges newly calculated leave hours with existing approved time bills, avoiding duplicate project allocations.
Calculate Total Time & Normalize Work Hours
Computes the total tracked hours, including prorated leave.
Distributes the minimum required work hours proportionally across all project allocations based on tracked hours.
Update Project Allocations
Iterates through the updated list of time-tracked entries.
Updates each project allocation’s tracked hours, excluding leave projects.
Update Payroll Tracked Hours
Updates the total tracked hours in the payroll record.
Error Handling
Wraps the entire logic in a try-catch block to capture and log any unexpected errors.