From 890e3763d80c968ae7f1d1b66afd8224f099a064 Mon Sep 17 00:00:00 2001 From: Tomasz Stalka Date: Fri, 24 May 2019 14:26:22 +0200 Subject: [PATCH 1/5] Time future upload and hours blocking part 1 - UI: Employee and Employee List, CSV Upload, Handling templates, Time Allocation, Tests --- src/classes/DContractTriggerController.cls | 38 + .../DContractTriggerController.cls-meta.xml | 5 + src/classes/FTEController.cls | 1 - src/classes/FTECsvUploadController.cls | 58 +- src/classes/FTEDataManager.cls | 703 +++++++ src/classes/FTEDataManager.cls-meta.xml | 5 + src/classes/FTEEmployeeController.cls | 278 +-- src/classes/FTEEmployeeMonthWrapper.cls | 47 + .../FTEEmployeeMonthWrapper.cls-meta.xml | 5 + src/classes/FTEEmployeeTime.cls | 105 +- src/classes/FTEEmployeeWrapper.cls | 25 + src/classes/FTEEmployeeWrapper.cls-meta.xml | 5 + .../FTEGenerateEmployeesWorkCardBatch.cls | 153 +- .../FTEGenerateEmployeesWorkCardScheduler.cls | 3 +- .../FTEIndividualProjectController.cls | 7 +- src/classes/FTETimeAllocator.cls | 94 + src/classes/FTETimeAllocator.cls-meta.xml | 5 + src/classes/FTETrackerController.cls | 54 +- src/classes/FTETrackerHelper.cls | 44 +- src/classes/FTETrackerTest.cls | 1728 +++++++++-------- src/classes/FTETriggerHelper.cls | 69 + src/classes/FTETriggerHelper.cls-meta.xml | 5 + src/classes/FTEUpdateTagsBatch.cls | 2 +- src/classes/FTEUploadData.cls | 35 +- src/classes/TimeCardCaseUpdateBatch.cls | 7 +- src/classes/TimeCardTriggerController.cls | 13 +- src/pages/FTE_CSV_Upload.page | 29 - src/pages/FTE_Employee_List_View.page | 64 +- src/pages/FTE_Employee_View.page | 309 ++- src/pages/FTE_Project_List_View.page | 2 +- .../DContractFTETrackerTrigger.trigger | 32 +- 31 files changed, 2583 insertions(+), 1347 deletions(-) create mode 100644 src/classes/DContractTriggerController.cls create mode 100644 src/classes/DContractTriggerController.cls-meta.xml create mode 100644 src/classes/FTEDataManager.cls create mode 100644 src/classes/FTEDataManager.cls-meta.xml create mode 100644 src/classes/FTEEmployeeMonthWrapper.cls create mode 100644 src/classes/FTEEmployeeMonthWrapper.cls-meta.xml create mode 100644 src/classes/FTEEmployeeWrapper.cls create mode 100644 src/classes/FTEEmployeeWrapper.cls-meta.xml create mode 100644 src/classes/FTETimeAllocator.cls create mode 100644 src/classes/FTETimeAllocator.cls-meta.xml create mode 100644 src/classes/FTETriggerHelper.cls create mode 100644 src/classes/FTETriggerHelper.cls-meta.xml diff --git a/src/classes/DContractTriggerController.cls b/src/classes/DContractTriggerController.cls new file mode 100644 index 00000000..6085d2c1 --- /dev/null +++ b/src/classes/DContractTriggerController.cls @@ -0,0 +1,38 @@ +public class DContractTriggerController { + + public static void handleBeforeUpdate(List updated, Map beforeUpdate) { + for (DContract__c upsertedContract : updated) { + DContract__c oldValue = beforeUpdate.get(upsertedContract.Id); + if ((oldValue == null || oldValue.FTE_Tracker__c != upsertedContract.FTE_Tracker__c)) { + upsertedContract.addError('FTE Tracker is currently calculating Empolyee Work Cards, try update FTE Tracker field later.'); + } + } + } + + public static void handleAfterUpdate(List updated, Map beforeUpdate) { + Set contracts = new Set(); + List contractsToUpdate = new List(); + Boolean fteJob = FTETrackerHelper.loadWorkCardJobStatus().isRunning; + + for (DContract__c upsertedContract : updated) { + DContract__c oldValue = beforeUpdate.get(upsertedContract.Id); + if ((oldValue == null || oldValue.FTE_Tracker__c != upsertedContract.FTE_Tracker__c) && (upsertedContract.Skip_FTE_Tracker_Trigger__c == false)) { + contracts.add(upsertedContract.Id); + } else if (upsertedContract.Skip_FTE_Tracker_Trigger__c == true) { // we want skip this batch job FTE Contract is uploaded by CSV File, we want have full controll and run moving hours batch job after Generating work cards + contractsToUpdate.add(new DContract__c(Id = upsertedContract.Id, Skip_FTE_Tracker_Trigger__c = false)); + } + } + + if (contractsToUpdate.size() > 0) { + update contractsToUpdate; + } + + FTETrackerHelper.markTemplates(contractsToUpdate); + + if (contracts.size() > 0) { + if (!Test.isRunningTest()) { + Database.executeBatch(new FTETimeAllocator(false), 1); + } + } + } +} \ No newline at end of file diff --git a/src/classes/DContractTriggerController.cls-meta.xml b/src/classes/DContractTriggerController.cls-meta.xml new file mode 100644 index 00000000..cbddff8c --- /dev/null +++ b/src/classes/DContractTriggerController.cls-meta.xml @@ -0,0 +1,5 @@ + + + 38.0 + Active + diff --git a/src/classes/FTEController.cls b/src/classes/FTEController.cls index 9f681e01..ab90407d 100644 --- a/src/classes/FTEController.cls +++ b/src/classes/FTEController.cls @@ -3,7 +3,6 @@ public virtual class FTEController { public JobWrapper workCardJobStatus {get; set;} public FTEController() { - } public virtual PageReference goToEmployeeListView() { diff --git a/src/classes/FTECsvUploadController.cls b/src/classes/FTECsvUploadController.cls index 01398ed8..cae50bf2 100644 --- a/src/classes/FTECsvUploadController.cls +++ b/src/classes/FTECsvUploadController.cls @@ -10,6 +10,9 @@ public class FTECsvUploadController extends FTEController { public Pagination fteStatusPagination { get; set; } public Map records { get; set; } + private Id contractId; + private Set employees; + private Decimal uploadedYear; private Map employeeMap; public FTECsvUploadController() { @@ -17,31 +20,30 @@ public class FTECsvUploadController extends FTEController { loadWorkCardJobStatus(); } - public List getFTEStatusRecords() { - List result = [SELECT Status__c, Status_Message__c, Line_Number__c, Line_Number_Text__c FROM FTE_Data_Record_Status__c - ORDER BY Line_Number__c LIMIT : this.fteStatusPagination.pageSize OFFSET : this.fteStatusPagination.getOffsetValue()]; - this.fteStatusPagination.handleResulSize([SELECT count() FROM FTE_Data_Record_Status__c]); - return result; - } + public Boolean processFTEDataRecords() { + Map mappedTemplates = new Map(); + for (FTE_Data_Record__c rec : [SELECT Id, Employee__c, Year__c, + Month_1__c, Month_2__c, Month_3__c, Month_4__c, Month_5__c, Month_6__c, + Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, Month_12__c, + Month_Updated_1__c, Month_Updated_2__c, Month_Updated_3__c, Month_Updated_4__c, Month_Updated_5__c, Month_Updated_6__c, + Month_Updated_7__c, Month_Updated_8__c, Month_Updated_9__c, Month_Updated_10__c, Month_Updated_11__c, Month_Updated_12__c + FROM FTE_Data_Record__c + WHERE Contract__c =: this.contractId AND Employee__c IN: this.employees AND Year__c =: this.uploadedYear]) { + mappedTemplates.put(rec.Employee__c, rec); + } - public void removeFTEDataStatusRecords() { - List toRemove = [SELECT Id FROM FTE_Data_Record_Status__c]; - if (toRemove.size() > 0) { - delete toRemove; - ApexPages.getMessages().clear(); + List finalDataList = new List(); + for (FTEUploadData rec : this.records.values()) { + finalDataList.add(rec.mergeData(mappedTemplates.get(rec.getEmployeeId()))); } - } - public Boolean processFTEDataRecords() { loadWorkCardJobStatus(); if (this.workCardJobStatus.isRunning == false) { - removeFTEDataStatusRecords(); // Remove status of last batch upload + upsert finalDataList; if (!Test.isRunningTest()) { - Database.executeBatch(new FTEHoursUploadBatch(this.records.values()), 1); - } else { - Database.executeBatch(new FTEHoursUploadBatch(this.records.values())); // no more then one batch execute can be invoked from test - } + Database.executeBatch(new FTETimeAllocator(true), 1); + } // In test we want test only parsing and how records was upserted, Time allocator has seprate tests loadWorkCardJobStatus(); ApexPages.getMessages().clear(); @@ -105,6 +107,7 @@ public class FTECsvUploadController extends FTEController { Integer csvYear = Integer.valueOf(numbers.get(1)); if (year == -1) { year = csvYear; + this.uploadedYear = csvYear; } if (!validateColumnHeaderData(year, csvYear, csvMonth, lineNum, strHelper, monthMapping)) { @@ -126,10 +129,15 @@ public class FTECsvUploadController extends FTEController { fteContract = getContract(contractName); if (fteContract == null) { return null; + } else if (fteContract.FTE_Tracker__c != 'Yes') { + ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR, 'Contract : "' + contractName + '" is not a FTE Tracker contract, please add it to Tracker before uploading CSV Template')); + return null; } + this.contractId = fteContract.Id; csvPattern = Pattern.compile('(\\d*\\.\\d+)|(\\d+\\.\\d*)'); this.records = new Map(); + this.employees = new Set(); loadEmployeeMap(); Boolean wasData = false; @@ -144,6 +152,7 @@ public class FTECsvUploadController extends FTEController { FTEUploadData emplDataRec = null; Id emplId = this.employeeMap.get(employeeName).Id; + this.employees.add(emplId); if (this.records.containsKey(emplId)) { emplDataRec = this.records.get(emplId); } else { @@ -157,12 +166,14 @@ public class FTECsvUploadController extends FTEController { } Integer index = monthMapping.get(i - 1 - columnsToSkip); - if (strHelper.isNumeric() || csvPattern.matcher(strHelper).matches()) { + if (strHelper.isNumeric() || csvPattern.matcher(strHelper).matches()) { // number 0 - ... emplDataRec.addMonthTime(index, Decimal.valueOf(strHelper)); wasData = true; - } else if (!String.isBlank(strHelper)) { + } else if (!String.isBlank(strHelper)) { // wrong number ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR, 'Line ' + lineNum + ' : ' + 'bad number format - ' + strHelper)); return null; + } else { // blank value we must set -1 to it will mean that threshold is removed + emplDataRec.addMonthTime(index, -1); } } this.records.put(emplId, emplDataRec); @@ -175,9 +186,10 @@ public class FTECsvUploadController extends FTEController { Boolean success = processFTEDataRecords(); if (success) { - ApexPages.addMessage(new ApexPages.message(ApexPages.severity.INFO, 'CSV file ' + fileName + ' was parsed. Upload job was scheduled, please wait for results.')); + ApexPages.addMessage(new ApexPages.message(ApexPages.severity.INFO, 'CSV file ' + fileName + ' was parsed. ' + + this.records.values().size() + 'records was added for ' + this.records.keySet().size() + ' employees.')); } else { - ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR, 'Cannot upload csv file. FTE Tracker is calculating time.')); + ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR, 'Cannot upload csv file. FTE Tracker is currently calculating time.')); } return null; @@ -189,7 +201,7 @@ public class FTECsvUploadController extends FTEController { } private DContract__c getContract(String contractName) { - List contracts = [SELECT Id, Name FROM DContract__c WHERE Name =: contractName]; + List contracts = [SELECT Id, Name, FTE_Tracker__c FROM DContract__c WHERE Name =: contractName]; if (contracts.size() > 0) { return contracts.get(0); } diff --git a/src/classes/FTEDataManager.cls b/src/classes/FTEDataManager.cls new file mode 100644 index 00000000..332b0028 --- /dev/null +++ b/src/classes/FTEDataManager.cls @@ -0,0 +1,703 @@ +/** + * FTEDataManager for loading Employee time and managing it. It contains methods which allow moving time between contracts. + */ +public class FTEDataManager { + + private Boolean monthMode; + private SFDC_Employee__c employee; + private Integer fteMonth; + private Integer fteYear; + private Boolean skipWorkCard; + private List timeCardsToUpdate; + + public Integer employeeNetworkDays { get; set;} + public FTEEmployeeTime unassigned { get; set;} + public Map assignedMap { get; set;} + public Map unassignedMap { get; set;} + + public FTEDataManager(Integer year, Integer month, Id employeeId, Boolean skipWorkCard) { + this(year, employeeId, skipWorkCard); + this.fteMonth = month; + this.monthMode = true; + } + + public FTEDataManager(Integer year, Id employeeId, Boolean skipWorkCard) { + this.monthMode = false; + this.fteYear = year; + this.skipWorkCard = skipWorkCard; + this.assignedMap = new Map(); + this.unassignedMap = new Map(); + this.unassigned = new FTEEmployeeTime('Unassigned', null); // Sum of all unassigned employee contracts + this.employee = [SELECT Id, Name FROM SFDC_Employee__c WHERE Id =: employeeId LIMIT 1]; + } + + public FTEDataManager(Integer year, Id employeeId) { + this(year, employeeId, true); + } + + /** + * Helper method to remove negative time. Negative time can be possible when client in time cards was updated. + */ + public void removeNegativeTime() { + removeNegativeTime(this.fteMonth); + } + + public void removeNegativeTime(Integer month) { + + } + + /** + * Sets threshold time and moves hours if possible. Threshold is loaded from the uploaded CSV template + */ + public void setTime(Id contractId, Decimal thresholdHours) { + setTime(contractId, thresholdHours, this.fteMonth); + } + + public void setTime(Id contractId, Decimal thresholdHours, Integer month) { + if (thresholdHours < 0) { + return; + } + Decimal availableTime = this.unassigned.hoursArray[month - 1]; + Decimal missingTime = thresholdHours; + if (this.assignedMap.containsKey(contractId)) { + missingTime = thresholdHours - this.assignedMap.get(contractId).hoursArray[month - 1]; + } + + if (missingTime > 0) { + addTime(contractId, availableTime > missingTime ? missingTime : availableTime); + } else if (missingTime < 0) { + removeTime(contractId, (-1) * missingTime); + } + } + + /** + * Set given threshold in month and upserst template for blocking hours and future time allocation. + */ + public void upsertTimeTemplate(Id contractId, Decimal threshold, Integer month) { + List templates = [SELECT Id, Month_1__c, Month_2__c, Month_3__c, Month_4__c, Month_5__c, Month_6__c, + Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, Month_12__c + FROM FTE_Data_Record__c + WHERE Contract__c =: contractId AND Employee__c =: this.employee.Id AND Year__c =: this.fteYear]; + + FTE_Data_Record__c template = null; + if (templates.size() > 0) { + template = templates.get(0); + } else { + template = new FTE_Data_Record__c(Contract__c = contractId, Employee__c = this.employee.Id, Year__c = this.fteYear); + } + + SObject templateSObj = (SObject) template; + templateSObj.put(FTETrackerHelper.getFieldName(month), threshold); + upsert template; + + setTime(contractId, threshold, month); + } + + /** + * Set -1 in time template, it means that we remove blocking hours and future time allocation for given month and contract. + */ + public void removeTimeTemplate(Id contractId, Integer month) { + List templates = [SELECT Id, Month_1__c, Month_2__c, Month_3__c, Month_4__c, Month_5__c, Month_6__c, + Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, Month_12__c + FROM FTE_Data_Record__c + WHERE Contract__c =: contractId AND Employee__c =: this.employee.Id AND Year__c =: this.fteYear]; + if (templates.size() > 0) { + FTE_Data_Record__c template = templates.get(0); + SObject templateSObj = (SObject) template; + templateSObj.put(FTETrackerHelper.getFieldName(month), -1); + upsert template; + } + } + + /** + * Move time to assigned. + */ + public void addTime(Id contractId, Decimal hours) { + addTime(contractId, hours, this.fteMonth); + } + + public void addTime(Id contractId, Decimal fteHours, Integer month) { + Date monthStart = Date.newInstance(this.fteYear, month, 1); + Date endMonth = Date.newInstance(this.fteYear, month, Date.daysInMonth(this.fteYear, month)); + this.timeCardsToUpdate = new List(); + + Decimal hoursToAssign = fteHours; + Decimal availableTime = this.unassigned.hoursArray[month - 1]; + hoursToAssign = availableTime >= hoursToAssign ? hoursToAssign : availableTime; + + // Step 1. If we have time between FTE contract we want remove such tags. + List timeCardsFromDB = [SELECT Id, Client__c, Client__r.FTE_Tracker__c, Client__r.Name, + Total__c, FTE_hours__c, FTE_Contract__c, + FTE_Contract__r.FTE_Tracker__c, FTE_Contract__r.Name, + Date__c FROM Time_Card__c + WHERE Employee__c =: this.employee.Id AND Client__c != null + AND FTE_Contract__r.FTE_Tracker__c = 'Yes' + AND Client__c =: contractId + AND Date__c >=: monthStart AND Date__c <=: endMonth]; + for (Time_Card__c tc : timeCardsFromDB) { + Decimal movedHours = tc.FTE_Hours__c; + Decimal hours = movedHours > hoursToAssign ? hoursToAssign : movedHours; + + if (hours > 0) { + tc.FTE_hours__c = tc.FTE_hours__c - hours; + hoursToAssign -= hours; + + if (this.assignedMap.containsKey(tc.FTE_Contract__c)) { + this.assignedMap.get(tc.FTE_Contract__c).hoursArray[month - 1] -= hours; + } + if (this.assignedMap.containsKey(contractId)) { + this.assignedMap.get(contractId).hoursArray[month - 1] += hours; + } + + if (tc.FTE_hours__c <= 0) { + tc.FTE_Contract__c = null; + tc.FTE_hours__c = 0; + } + this.timeCardsToUpdate.add(tc); + + if (hours > 0) { // Step 2. Check description below + hours = assignExistingTagToUnassigned(tc.FTE_Contract__c, hours, month, monthStart, endMonth); + } + + if (hours > 0) { // Step 3. Check description below + hours = assignExistingTagsFromUnassigned(tc.FTE_Contract__c, hours, month, monthStart, endMonth); + } + + if (hours > 0) { // Step 4. Check description below + hours = assignWithNewTag(tc.FTE_Contract__c, hours, month, monthStart, endMonth); + } + + if (hours > 0) { // Step 5. Check description below + hours = assignWithNewTagAndTimeCard(tc.FTE_Contract__c, hours, month, monthStart); + } + + if (hoursToAssign <= 0) { + hoursToAssign = 0; + break; + } + } + } + + // Step 2. If we have moved hours from assigned to unassigned we want take these hours back. + if (hoursToAssign > 0) { + hoursToAssign = assignExistingTagToUnassigned(contractId, hoursToAssign, month, monthStart, endMonth); + } + + // Step 3. If we already have tag from unassigned we want take more hours from that tag. + if (hoursToAssign > 0) { + hoursToAssign = assignExistingTagsFromUnassigned(contractId, hoursToAssign, month, monthStart, endMonth); + } + + // Step 4. If we still need hours we will take time cards without any tag and add tag there. + if (hoursToAssign > 0) { + hoursToAssign = assignWithNewTag(contractId, hoursToAssign, month, monthStart, endMonth); + } + + // Step 5. If we have available time we need create empty time card with tag. + if (hoursToAssign > 0) { + hoursToAssign = assignWithNewTagAndTimeCard(contractId, hoursToAssign, month, monthStart); + } + + if (this.timeCardsToUpdate.size() > 0) { + upsert this.timeCardsToUpdate; + this.timeCardsToUpdate.clear(); + } + + if (this.skipWorkCard == false) { + recalculateWorkCardMonth(month); + } + } + + /** + * Move time to unassigned. + */ + public void removeTime(Id contractId, Decimal hours) { + removeTime(contractId, hours, this.fteMonth); + } + + public void removeTime(Id contractId, Decimal fteHours, Integer month) { + Date monthStart = Date.newInstance(this.fteYear, month, 1); + Date endMonth = Date.newInstance(this.fteYear, month, Date.daysInMonth(this.fteYear, month)); + this.timeCardsToUpdate = new List(); + + Decimal hoursToUnassign = fteHours; + if (this.assignedMap.containsKey(contractId)) { + Decimal availableTime = this.assignedMap.get(contractId).hoursArray[month - 1]; + hoursToUnassign = availableTime >= hoursToUnassign ? hoursToUnassign : availableTime; + } + + // Step 1. If we have time between FTE contract we want remove such tags. + List timeCardsFromDB = [SELECT Id, Client__c, Client__r.FTE_Tracker__c, Client__r.Name, + Total__c, FTE_hours__c, FTE_Contract__c, + FTE_Contract__r.FTE_Tracker__c, FTE_Contract__r.Name, + Date__c FROM Time_Card__c + WHERE Employee__c =: this.employee.Id AND Client__c != null + AND Client__r.FTE_Tracker__c = 'Yes' + AND FTE_Contract__c =: contractId + AND Date__c >=: monthStart AND Date__c <=: endMonth]; + for (Time_Card__c tc : timeCardsFromDB) { + Decimal movedHours = tc.FTE_Hours__c; + Decimal hours = movedHours > hoursToUnassign ? hoursToUnassign : movedHours; + + if (hours > 0) { + tc.FTE_hours__c = tc.FTE_hours__c - hours; + hoursToUnassign -= hours; + if (this.assignedMap.containsKey(contractId)) { + this.assignedMap.get(contractId).hoursArray[month - 1] -= hours; + } + if (this.assignedMap.containsKey(tc.Client__c)) { + this.assignedMap.get(tc.Client__c).hoursArray[month - 1] += hours; + } + + if (tc.FTE_hours__c <= 0) { + tc.FTE_Contract__c = null; + tc.FTE_hours__c = 0; + } + this.timeCardsToUpdate.add(tc); + + if (hours > 0) { // Step 2. Check description below + hours = unassignExistingTagToFTE(tc.Client__c, hours, month, monthStart, endMonth); + } + + if (hours > 0) { // Step 3. Check description below + hours = unassignExistingTagFromFTE(tc.Client__c, hours, month, monthStart, endMonth); + } + + if (hours > 0) { // Step 4. Check description below + hours = unassignWithNewTag(tc.Client__c, hours, month, monthStart, endMonth); + } + + if (hours > 0) { // Step 5. Check description below + hours = unassignWithNewTagAndTimeCard(tc.Client__c, hours, month, monthStart); + } + + if (hoursToUnassign <= 0) { + hoursToUnassign = 0; + break; + } + } + } + + // Step 2. If we have moved hours from unassigned to assigned we want take these hours back, we want decrease number of tags. + if (hoursToUnassign > 0) { + hoursToUnassign = unassignExistingTagToFTE(contractId, hoursToUnassign, month, monthStart, endMonth); + } + + Decimal hoursMapHelper = hoursToUnassign; + // Step 3. If we already have tag from assigned we want take more hours from that tag, we want decrease number of tags. + if (hoursToUnassign > 0) { + hoursToUnassign = unassignExistingTagFromFTE(contractId, hoursToUnassign, month, monthStart, endMonth); + } + + // Step 4. If we don't have any tag we need add one in time cards. + if (hoursToUnassign > 0) { + hoursToUnassign = unassignWithNewTag(contractId, hoursToUnassign, month, monthStart, endMonth); + } + + // Step 5. If we don't have any empty time card we need create a empty one to move hours. + if (hoursToUnassign > 0) { + hoursToUnassign = unassignWithNewTagAndTimeCard(contractId, hoursToUnassign, month, monthStart); + } + + if (this.timeCardsToUpdate.size() > 0) { + upsert this.timeCardsToUpdate; + this.timeCardsToUpdate.clear(); + } + + if (this.skipWorkCard == false) { + recalculateWorkCardMonth(month); + } + } + + private Decimal assignExistingTagToUnassigned(Id contractId, Decimal timeToAssign, Integer month, Date monthStart, Date endMonth) { + List timeCardsFromDB = [SELECT Id, Client__c, Client__r.FTE_Tracker__c, Client__r.Name, + Total__c, FTE_hours__c, FTE_Contract__c, + FTE_Contract__r.FTE_Tracker__c, FTE_Contract__r.Name, + Date__c FROM Time_Card__c + WHERE Employee__c =: this.employee.Id AND Client__c != null + AND Client__r.FTE_Tracker__c = 'Yes' AND FTE_Hours__c > 0 + AND Client__c =: contractId AND FTE_Contract__c != null + AND (FTE_Contract__r.FTE_Tracker__c = 'No' OR FTE_Contract__r.FTE_Tracker__c = '') + AND Date__c >=: monthStart AND Date__c <=: endMonth]; + + for (Time_Card__c tc : timeCardsFromDB) { + Decimal freeHours = this.unassignedMap.get(tc.FTE_Contract__c).hoursArray[month - 1]; + Decimal movedHours = tc.FTE_Hours__c; + Decimal hours = movedHours > freeHours ? freeHours : movedHours; + + if (hours > 0) { // we try remove tag from tc + Decimal toAssign = timeToAssign > hours ? hours : timeToAssign; + tc.FTE_hours__c = tc.FTE_hours__c - toAssign; + timeToAssign -= toAssign; + + this.unassignedMap.get(tc.FTE_Contract__c).hoursArray[month - 1] -= toAssign; + this.unassigned.hoursArray[month - 1] -= toAssign; + if (this.assignedMap.containsKey(contractId)) { + this.assignedMap.get(contractId).hoursArray[month - 1] += toAssign; + } else { + FTEEmployeeTime fteData = new FTEEmployeeTime('', contractId); + fteData.hoursArray[month - 1] += toAssign; + this.assignedMap.put(contractId, fteData); + } + + if (tc.FTE_hours__c <= 0) { + tc.FTE_Contract__c = null; + } + this.timeCardsToUpdate.add(tc); + if (timeToAssign <= 0) { + timeToAssign = 0; + break; + } + } + } + + return timeToAssign; + } + + private Decimal assignExistingTagsFromUnassigned(Id contractId, Decimal timeToAssign, Integer month, Date monthStart, Date endMonth) { + List timeCardsFromDB = [SELECT Id, Client__c, Client__r.FTE_Tracker__c, Client__r.Name, + Total__c, FTE_hours__c, FTE_Contract__c, + FTE_Contract__r.FTE_Tracker__c, FTE_Contract__r.Name, + Date__c FROM Time_Card__c + WHERE Employee__c =: this.employee.Id AND Client__c != null + AND (Client__r.FTE_Tracker__c = 'No' OR Client__r.FTE_Tracker__c = '') + AND FTE_Contract__c =: contractId + AND Date__c >=: monthStart AND Date__c <=: endMonth]; + + for (Time_Card__c tc : timeCardsFromDB) { + Decimal hours = this.unassignedMap.get(tc.Client__c).hoursArray[month - 1]; + if (hours > 0) { + Decimal toAssign = timeToAssign > hours ? hours : timeToAssign; + tc.FTE_hours__c = tc.FTE_hours__c != null ? tc.FTE_hours__c + toAssign : toAssign; + timeToAssign -= toAssign; + + this.unassignedMap.get(tc.Client__c).hoursArray[month - 1] -= toAssign; + this.unassigned.hoursArray[month - 1] -= toAssign; + if (this.assignedMap.containsKey(contractId)) { + this.assignedMap.get(contractId).hoursArray[month - 1] += toAssign; + } else { + FTEEmployeeTime fteData = new FTEEmployeeTime('', contractId); + fteData.hoursArray[month - 1] += toAssign; + this.assignedMap.put(contractId, fteData); + } + + this.timeCardsToUpdate.add(tc); + if (timeToAssign <= 0) { + timeToAssign = 0; + break; + } + } + } + return timeToAssign; + } + + private Decimal assignWithNewTag(Id contractId, Decimal timeToAssign, Integer month, Date monthStart, Date endMonth) { + List timeCardsFromDB = [SELECT Id, Client__c, Client__r.FTE_Tracker__c, Client__r.Name, + Total__c, FTE_hours__c, FTE_Contract__c, + FTE_Contract__r.FTE_Tracker__c, FTE_Contract__r.Name, + Date__c FROM Time_Card__c + WHERE Employee__c =: this.employee.Id AND Client__c != null + AND (Client__r.FTE_Tracker__c = 'No' OR Client__r.FTE_Tracker__c = '') + AND (FTE_Contract__c = null OR FTE_Contract__c = '') + AND Date__c >=: monthStart AND Date__c <=: endMonth]; + + Set emptyContracts = new Set(); + for (Time_Card__c tc : timeCardsFromDB) { + if (emptyContracts.contains(tc.Client__c)) { + continue; + } + + Decimal hours = this.unassignedMap.get(tc.Client__c).hoursArray[month - 1]; + if (hours > 0) { + Decimal toAssign = timeToAssign > hours ? hours : timeToAssign; + tc.FTE_hours__c = tc.FTE_hours__c != null ? tc.FTE_hours__c + toAssign : toAssign; + tc.FTE_Contract__c = contractId; + timeToAssign -= toAssign; + + this.unassignedMap.get(tc.Client__c).hoursArray[month - 1] -= toAssign; + this.unassigned.hoursArray[month - 1] -= toAssign; + if (this.assignedMap.containsKey(contractId)) { + this.assignedMap.get(contractId).hoursArray[month - 1] += toAssign; + } else { + FTEEmployeeTime fteData = new FTEEmployeeTime('', contractId); + fteData.hoursArray[month - 1] += toAssign; + this.assignedMap.put(contractId, fteData); + } + + this.timeCardsToUpdate.add(tc); + if (timeToAssign <= 0) { + timeToAssign = 0; + break; + } + + emptyContracts.add(tc.Client__c); + } else { + emptyContracts.add(tc.Client__c); + } + } + + return timeToAssign; + } + + private Decimal assignWithNewTagAndTimeCard(Id contractId, Decimal timeToAssign, Integer month, Date monthStart) { + for (Id conId : this.unassignedMap.keySet()) { + Decimal hours = this.unassignedMap.get(conId).hoursArray[month - 1]; + if (hours > 0) { + Decimal toAssign = timeToAssign > hours ? hours : timeToAssign; + Time_Card__c tc = new Time_Card__c(Client__c = conId, Employee__c = this.employee.Id, Date__c = monthStart, + FTE_only__c = true, Total__c = 0, FTE_hours__c = toAssign, + FTE_Contract__c = contractId); + timeToAssign -= toAssign; + + this.unassignedMap.get(conId).hoursArray[month - 1] -= toAssign; + this.unassigned.hoursArray[month - 1] -= toAssign; + if (this.assignedMap.containsKey(contractId)) { + this.assignedMap.get(contractId).hoursArray[month - 1] += toAssign; + } else { + FTEEmployeeTime fteData = new FTEEmployeeTime('', contractId); + fteData.hoursArray[month - 1] += toAssign; + this.assignedMap.put(contractId, fteData); + } + + this.timeCardsToUpdate.add(tc); + if (timeToAssign <= 0) { + break; + } + } + } + return 0; + } + + private Decimal unassignExistingTagToFTE(Id contractId, Decimal timeToUnassign, Integer month, Date monthStart, Date endMonth) { + List timeCardsFromDB = [SELECT Id, Client__c, Client__r.FTE_Tracker__c, Client__r.Name, + Total__c, FTE_hours__c, FTE_Contract__c, + FTE_Contract__r.FTE_Tracker__c, FTE_Contract__r.Name, + Date__c FROM Time_Card__c + WHERE Employee__c =: this.employee.Id AND Client__c != null + AND (Client__r.FTE_Tracker__c = 'No' OR Client__r.FTE_Tracker__c = '') + AND FTE_Contract__c =: contractId + AND Date__c >=: monthStart AND Date__c <=: endMonth]; + + for (Time_Card__c tc : timeCardsFromDB) { + Decimal movedHours = tc.FTE_Hours__c; + Decimal hours = movedHours > timeToUnassign ? timeToUnassign : movedHours; + + if (hours > 0) { + tc.FTE_hours__c = tc.FTE_hours__c - hours; + timeToUnassign -= hours; + + this.assignedMap.get(contractId).hoursArray[month - 1] -= hours; + this.unassignedMap.get(tc.Client__c).hoursArray[month - 1] += hours; + this.unassigned.hoursArray[month - 1] += hours; + + if (tc.FTE_hours__c <= 0) { + tc.FTE_Contract__c = null; + tc.FTE_hours__c = 0; + } + + this.timeCardsToUpdate.add(tc); + if (timeToUnassign <= 0) { + timeToUnassign = 0; + break; + } + } + } + return timeToUnassign; + } + + private Decimal unassignExistingTagFromFTE(Id contractId, Decimal timeToUnassign, Integer month, Date monthStart, Date endMonth) { + List timeCardsFromDB = [SELECT Id, Client__c, Client__r.FTE_Tracker__c, Client__r.Name, + Total__c, FTE_hours__c, FTE_Contract__c, + FTE_Contract__r.FTE_Tracker__c, FTE_Contract__r.Name, + Date__c FROM Time_Card__c + WHERE Employee__c =: this.employee.Id AND Client__c != null + AND Client__c =: contractId AND FTE_Contract__c != null + AND (FTE_Contract__r.FTE_Tracker__c = 'No' OR FTE_Contract__r.FTE_Tracker__c = '') + AND Date__c >=: monthStart AND Date__c <=: endMonth LIMIT 1]; + if (timeCardsFromDB.size() > 0) { + Time_Card__c tc = timeCardsFromDB.get(0); + tc.FTE_hours__c = tc.FTE_hours__c != null ? tc.FTE_hours__c + timeToUnassign : timeToUnassign; + this.timeCardsToUpdate.add(tc); + + this.assignedMap.get(contractId).hoursArray[month - 1] -= timeToUnassign; + this.unassignedMap.get(tc.FTE_Contract__c).hoursArray[month - 1] += timeToUnassign; + this.unassigned.hoursArray[month - 1] += timeToUnassign; + + timeToUnassign = 0; + } + + return timeToUnassign; + } + + private Decimal unassignWithNewTag(Id contractId, Decimal timeToUnassign, Integer month, Date monthStart, Date endMonth) { + List timeCardsFromDB = [SELECT Id, Client__c, Client__r.FTE_Tracker__c, Client__r.Name, + Total__c, FTE_hours__c, FTE_Contract__c, + FTE_Contract__r.FTE_Tracker__c, FTE_Contract__r.Name, + Date__c FROM Time_Card__c + WHERE Employee__c =: this.employee.Id AND Client__c != null + AND Client__c =: contractId + AND FTE_Contract__c = null + AND Date__c >=: monthStart AND Date__c <=: endMonth LIMIT 1]; + + if (timeCardsFromDB.size() > 0) { + Time_Card__c tc = timeCardsFromDB.get(0); + tc.FTE_Contract__c = this.unassignedMap.values()[getContractIndex()].objId; + tc.FTE_hours__c = timeToUnassign; + this.timeCardsToUpdate.add(tc); + + this.assignedMap.get(contractId).hoursArray[month - 1] -= timeToUnassign; + this.unassignedMap.get(tc.FTE_Contract__c).hoursArray[month - 1] += timeToUnassign; + this.unassigned.hoursArray[month - 1] += timeToUnassign; + + timeToUnassign = 0; + } + + return timeToUnassign; + } + + private Decimal unassignWithNewTagAndTimeCard(Id contractId, Decimal timeToUnassign, Integer month, Date monthStart) { + Time_Card__c tc = new Time_Card__c(Client__c = contractId, Employee__c = this.employee.Id, Date__c = monthStart, + FTE_only__c = true, Total__c = 0, FTE_hours__c = timeToUnassign, + FTE_Contract__c = this.unassignedMap.values()[getContractIndex()].objId); + this.timeCardsToUpdate.add(tc); + + this.assignedMap.get(contractId).hoursArray[month - 1] -= timeToUnassign; + this.unassignedMap.get(tc.FTE_Contract__c).hoursArray[month - 1] += timeToUnassign; + this.unassigned.hoursArray[month - 1] += timeToUnassign; + + return 0; + } + + /** + * Loads employee time for given year / month + */ + public void loadEmployeeTime() { + List timeCards = null; + if (this.monthMode == true) { // only one month data + timeCards = [SELECT Id, Client__c, Client__r.FTE_Tracker__c, Client__r.Name, + Total__c, FTE_hours__c, FTE_Contract__c, + FTE_Contract__r.FTE_Tracker__c, FTE_Contract__r.Name, + Date__c FROM Time_Card__c + WHERE Employee__c =: this.employee.Id AND Client__c != null + AND CALENDAR_YEAR(Date__c) =: this.fteYear AND CALENDAR_MONTH(Date__c) =: this.fteMonth + ORDER BY Client__r.Name]; + } else { // year data used mostly by the UI + timeCards = [SELECT Id, Client__c, Client__r.FTE_Tracker__c, Client__r.Name, + Total__c, FTE_hours__c, FTE_Contract__c, + FTE_Contract__r.FTE_Tracker__c, FTE_Contract__r.Name, + Date__c FROM Time_Card__c + WHERE Employee__c =: this.employee.Id AND Client__c != null + AND CALENDAR_YEAR(Date__c) =: this.fteYear + ORDER BY Client__r.Name]; + } + + FTEEmployeeTime tmpHelper; + for (Time_Card__c timeCard : timeCards) { + calculateLoggedTime(timeCard); // sum hours and moved hours + } + } + + /** + * Loads time templates for given year and employee. + */ + public void loadTemplateTime() { + Integer monthIndex = 1; + Integer maxMonth = 12; + if (this.monthMode == true) { + monthIndex = this.fteMonth; + maxMonth = this.fteMonth; + } + for (FTE_Data_Record__c futureTemplate : [SELECT Contract__c, Contract__r.Name, Employee__c, Month_1__c, Month_2__c, Month_3__c, Month_4__c, + Month_5__c, Month_6__c, Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, Month_12__c + FROM FTE_Data_Record__c + WHERE Employee__c =: this.employee.Id AND Year__c =: this.fteYear AND Contract__r.FTE_Tracker__c = 'Yes']) { + SObject templateSObj = (SObject) futureTemplate; + + for (Integer month = monthIndex; month <= maxMonth; month++) { + Decimal monthValue = (Decimal) templateSObj.get(FTETrackerHelper.getFieldName(month)); + if (monthValue == -1) { + continue; + } + + if (!this.assignedMap.containsKey(futureTemplate.Contract__c)) { + this.assignedMap.put(futureTemplate.Contract__c, new FTEEmployeeTime(futureTemplate.Contract__r.Name, futureTemplate.Contract__c)); + } + + FTEEmployeeTime tmpHelper = this.assignedMap.get(futureTemplate.Contract__c); + + if (tmpHelper.templateArray[month - 1] == -1) { + tmpHelper.templateArray[month - 1] = 0; + } + tmpHelper.templateArray[month - 1] += monthValue; + } + } + } + + /** + * Recalculates Employee Work Month. Work Card object is used by the Employee List View for better performance. + */ + public void recalculateWorkCardMonth(Integer month) { + // TODO + } + + private void moveHoursInFTEWorkCard(Decimal daysValue, Integer month, Id EmployeeId) { + /* + List workCards = [SELECT Id, Month_1__c, Month_2__c, Month_3__c, Month_4__c, Month_5__c, Month_6__c, Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, + Month_12__c, Total__c, Total_Hours__c FROM FTE_Work_Card__c WHERE Employee__c =: EmployeeId]; + if (workCards.size() > 0) { + Decimal totalValue = workCards.get(0).Total__c; + Decimal totalHoursValue = workCards.get(0).Total_Hours__c; + SObject workCard = workCards.get(0); + Decimal monthValue = (Decimal) workCard.get('Month_' + month + '__c'); + + workCard.put('Total__c', TotalValue + daysValue); + workCard.put('Total_Hours__c', totalHoursValue + (daysValue * 8)); + workCard.put('Month_' + month + '__c', monthValue + daysValue); + update workCard; + } + */ + } + + + private void calculateLoggedTime(Time_Card__c timeCard) { + Decimal loggedTime = (timeCard.Total__c != null ? timeCard.Total__c : 0); + Decimal movedTime = (timeCard.FTE_hours__c != null ? timeCard.FTE_hours__c : 0); + + // "Moved from" part this.contractsTime.add(this.unassigned); + sumLoggedTime(timeCard.Client__r.FTE_Tracker__c == 'Yes', timeCard.Client__c, timeCard.Client__r.Name, (loggedTime - movedTime), timeCard.Date__c.month()); + // If no FTE Tag values we don't need to process moved hours + if (timeCard.FTE_Contract__c == null || movedTime == 0) { + return; + } + // "Moved to" part + sumLoggedTime(timeCard.FTE_Contract__r.FTE_Tracker__c == 'Yes', timeCard.FTE_Contract__c, timeCard.FTE_Contract__r.Name, movedTime, timeCard.Date__c.month()); + } + + private void sumLoggedTime(Boolean fteTracker, Id clientId, String clientName, Decimal loggedHours, Integer month) { + FTEEmployeeTime tmpHelper = this.unassigned; + if (fteTracker == true) { + if (!this.assignedMap.containsKey(clientId)) { + this.assignedMap.put(clientId, new FTEEmployeeTime(clientName, clientId)); + } + tmpHelper = this.assignedMap.get(clientId); + tmpHelper.hoursArray[month - 1] += loggedHours; + } else { + if (!this.unassignedMap.containsKey(clientId)) { + this.unassignedMap.put(clientId, new FTEEmployeeTime(clientName, clientId)); + } + tmpHelper.hoursArray[month - 1] += loggedHours; + tmpHelper = this.unassignedMap.get(clientId); + tmpHelper.hoursArray[month - 1] += loggedHours; + } + } + + private Integer getContractIndex() { + Integer upperLimit = this.unassignedMap.size(); + if (upperLimit == 0) { + ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR, 'Cannot find unassigned contract')); + return 0; + } + Integer rand = Math.round(Math.random()*1000); + return Math.mod(rand, upperLimit); + } +} \ No newline at end of file diff --git a/src/classes/FTEDataManager.cls-meta.xml b/src/classes/FTEDataManager.cls-meta.xml new file mode 100644 index 00000000..cbddff8c --- /dev/null +++ b/src/classes/FTEDataManager.cls-meta.xml @@ -0,0 +1,5 @@ + + + 38.0 + Active + diff --git a/src/classes/FTEEmployeeController.cls b/src/classes/FTEEmployeeController.cls index 35ad23ea..7eb729cf 100644 --- a/src/classes/FTEEmployeeController.cls +++ b/src/classes/FTEEmployeeController.cls @@ -4,30 +4,23 @@ public class FTEEmployeeController extends FTEController { private Id employeeId; - private Integer employeeNetworkDays = 0; + public SFDC_Employee__c employee { get; set; } - public Id contractId { get; set;} - public Integer fteYear { get; set;} - public Integer exportMonth { get; set;} - public SFDC_Employee__c employee { get; set;} + public FTEDataManager fteTimeManager { get; set; } + public FTEEmployeeTime totalAssignedDays { get; set; } + public FTEEmployeeTime totalDaysWorked { get; set; } + public List contractsTime { get; set; } - public FTETimeManager fteTimeManager { get; set;} - public FTEEmployeeTime totalAssignedDays { get; set;} - public FTEEmployeeTime totalDaysWorked { get; set;} - public List contractsTime { get; set;} + public List fteContracts { get; set; } + public List fteContractsOptions { get; set; } - public List fteContracts { get; set;} - public List fteContractsOptions { get;set; } - public Id selectedFteContract { get; set;} - public String fteDays { get; set;} - public Integer employeeMonth { get; set;} - public Decimal fteHoursMax { get; set;} - public Decimal fteDaysMax { get; set;} - public Decimal userAvailableDays { get; set;} - public Boolean assignViewError { get; set;} - public Boolean notValidDays {get; set;} - public String monthName {get; set;} - public String contractName { get; set;} + public Integer employeeNetworkDays { get; set; } + public Id contractId { get; set; } + public Integer fteYear { get; set; } + public Integer exportMonth { get; set; } + public Id selectedFteContract { get; set; } + public String fteDays { get; set; } + public Integer employeeMonth { get; set; } public FTEEmployeeController() { String emplId = ApexPages.currentPage().getParameters().get('employeeId'); @@ -41,6 +34,18 @@ public class FTEEmployeeController extends FTEController { } else { this.fteYear = Date.today().year(); } + + this.fteContracts = [SELECT Id, Name FROM DContract__c WHERE FTE_Tracker__c = 'Yes' ORDER BY Name]; + this.fteContractsOptions = new List(); + for (DContract__c con : this.fteContracts) { + this.fteContractsOptions.add(new SelectOption(con.Id, con.Name)); + } + + List emplList = [SELECT Id, Name, Hire_Date__c FROM SFDC_Employee__c WHERE Id =: this.employeeId LIMIT 1]; + if (emplList.size() > 0) { + this.employee = emplList.get(0); + } + this.employeeNetworkDays = FTETrackerHelper.getNetworkDays(this.employee.Hire_Date__c, this.fteYear); } public void initFteEmployeeView() { @@ -49,15 +54,55 @@ public class FTEEmployeeController extends FTEController { return; } - List emplList = [SELECT Id, Name, Hire_Date__c FROM SFDC_Employee__c WHERE Id =: this.employeeId LIMIT 1]; - if (emplList.size() > 0) { - this.employee = emplList.get(0); + this.fteTimeManager = new FTEDataManager(this.fteYear, this.employee.Id, false); + this.fteTimeManager.loadEmployeeTime(); // loads employee time cards with tags + this.fteTimeManager.loadTemplateTime(); // loads uploaded csv templates to allocate future time + buildUITableData(); + } + + public void setThreshold() { + if (this.fteDays != null && this.fteDays != '') { + Decimal value = Decimal.valueOf(this.fteDays); + if (value >= 0) { + FTEDataManager manager = new FTEDataManager(this.fteYear, this.employeeMonth, this.employee.Id, false); + manager.upsertTimeTemplate(this.contractId, value, this.employeeMonth); + manager.loadEmployeeTime(); + manager.loadTemplateTime(); + manager.setTime(this.contractId, value * 8); + } else { + resetThreshold(this.contractId, this.employeeMonth); + } + } else { + resetThreshold(this.contractId, this.employeeMonth); } + } - this.employeeNetworkDays = FTETrackerHelper.getNetworkDays(this.employee.Hire_Date__c, this.fteYear); - this.fteTimeManager = new FTETimeManager(this.employee, this.fteYear); - this.fteTimeManager.loadEmployeeTime(); - buildUITableData(); + public void resetThreshold(Id resetContract, Integer resetMonth) { + this.fteTimeManager.removeTimeTemplate(resetContract, resetMonth); + } + + public void assignTime() { + if (this.fteDays != null && this.fteDays != '') { + Decimal value = Decimal.valueOf(this.fteDays); + if (value > 0) { + FTEDataManager manager = new FTEDataManager(this.fteYear, this.employeeMonth, this.employee.Id, false); + manager.loadEmployeeTime(); + manager.loadTemplateTime(); + manager.addTime(this.selectedFteContract, value * 8); + } + } + } + + public void unassignTime() { + if (this.fteDays != null && this.fteDays != '') { + Decimal value = Decimal.valueOf(this.fteDays); + if (value > 0) { + FTEDataManager manager = new FTEDataManager(this.fteYear, this.employeeMonth, this.employee.Id, false); + manager.loadEmployeeTime(); + manager.loadTemplateTime(); + manager.removeTime(this.contractId, value * 8); + } + } } public override PageReference goToEmployeeListView () { @@ -84,196 +129,49 @@ public class FTEEmployeeController extends FTEController { return pageRef; } - public void loadEmployeeMonth() { - this.assignViewError = false; - this.notValidDays = false; - this.fteDays = '0.25'; - this.userAvailableDays = 0; - - if (this.employeeMonth != null) { - this.fteDaysMax = this.fteTimeManager.unassigned.daysArray[this.employeeMonth]; - this.fteHoursMax = this.fteTimeManager.unassigned.hoursArray[this.employeeMonth]; - this.monthName = DateTime.newInstance(this.fteYear, this.employeeMonth + 1, 1).format('MMMM yyyy'); - this.userAvailableDays = 21 - this.totalAssignedDays.daysArray[this.employeeMonth] > 0 ? 21 - - this.totalAssignedDays.daysArray[this.employeeMonth] : 0; - Decimal helperDecimal = employeeNetworkDays - this.totalAssignedDays.daysArray[12] > 0 ? - employeeNetworkDays - this.totalAssignedDays.daysArray[12] : 0; - this.userAvailableDays = this.userAvailableDays < helperDecimal ? this.userAvailableDays : helperDecimal; - } else { - ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR, 'Cannot load month number')); - this.assignViewError = true; - this.fteHoursMax = 0; - } - - this.fteContracts = [SELECT Id, Name FROM DContract__c WHERE FTE_Tracker__c = 'Yes' ORDER BY Name]; - this.fteContractsOptions = new List(); - for (DContract__c con : this.fteContracts) { - this.fteContractsOptions.add(new SelectOption(con.Id, con.Name)); - } - } - - public void loadEmployeeUnassMonth() { - this.assignViewError = false; - this.notValidDays = false; - this.fteDays = '0.25'; - if (this.employeeMonth != null && this.contractId != null) { - this.contractName = this.fteTimeManager.assignedMap.get(this.contractId).name; - this.fteHoursMax = this.fteTimeManager.assignedMap.get(this.contractId).hoursArray[this.employeeMonth]; - this.fteDaysMax = this.fteTimeManager.assignedMap.get(this.contractId).daysArray[this.employeeMonth]; - this.monthName = DateTime.newInstance(this.fteYear, this.employeeMonth + 1, 1).format('MMMM yyyy'); - } else { - ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR, 'Cannot load contract month')); - this.assignViewError = true; - this.fteHoursMax = 0; - } - } - - public void moveTimeToUnassigned() { - if (notValidDays) { - return; - } - this.assignViewError = false; - if (this.employeeMonth == null) { - ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR, 'Cannot load month number')); - this.assignViewError = true; - return; - } - - Decimal fteDaysdecimal = this.fteDays != null && this.fteDays != '' ? Decimal.valueOf(this.fteDays) : 0; - if (this.fteDaysMax < fteDaysdecimal || fteDaysdecimal < 0) { - ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR, 'Too much hours to assign / hours cannot be negative')); - this.assignViewError = true; - return; - } - - if (String.isEmpty(this.contractId)) { - ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR, 'Cannot find FTE Contract')); - this.assignViewError = true; - return; - } - - if (fteDaysdecimal == 0) { - ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR, 'Cannot move 0 hours')); - this.assignViewError = true; - return; - } - - try { - Decimal hoursToUnassign = fteDaysdecimal * 8; - if (this.fteHoursMax < hoursToUnassign) { - hoursToUnassign = this.fteHoursMax; - } - this.fteTimeManager.moveTimeToUnassigned(hoursToUnassign, this.employeeMonth + 1, this.contractId); - moveHoursInFTEWorkCard((-1) * fteDaysdecimal, this.employeeMonth + 1, this.employee.Id); - } catch (Exception e) { - this.assignViewError = true; - ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR, 'Unexpected error: ' + e.getMessage())); - } - - initFteEmployeeView(); - } - - public void moveTimeFromUnassigned() { - if (notValidDays) { - return; - } - this.assignViewError = false; - if (this.employeeMonth == null) { - ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR, 'Cannot load month number')); - this.assignViewError = true; - return; - } - - Decimal fteDaysdecimal = this.fteDays != null && this.fteDays != '' ? Decimal.valueOf(this.fteDays) : 0; - if (this.fteDaysMax < fteDaysdecimal || fteDaysdecimal < 0) { - ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR, 'Too much hours to assign / hours cannot be negative')); - this.assignViewError = true; - return; - } - - if (String.isEmpty(this.selectedFteContract)) { - ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR, 'Cannot find FTE Contract')); - this.assignViewError = true; - return; - } - - if (fteDaysdecimal == 0) { - ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR, 'Cannot move 0 hours')); - this.assignViewError = true; - return; - } - - try { - Decimal hoursToAssign = fteDaysdecimal * 8; - if (this.fteHoursMax < hoursToAssign) { - hoursToAssign = this.fteHoursMax; - } - this.fteTimeManager.moveTimeToAssigned(hoursToAssign, this.employeeMonth + 1, this.selectedFteContract); - moveHoursInFTEWorkCard(fteDaysdecimal, this.employeeMonth + 1, this.employee.Id); - } catch (Exception e) { - this.assignViewError = true; - ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR, 'Unexpected error: ' + e.getMessage() + ' Line : ' + e.getLineNumber())); - } - initFteEmployeeView(); - } - private void buildUITableData() { this.contractsTime = new List(); this.contractsTime = this.fteTimeManager.assignedMap.values(); this.totalAssignedDays = new FTEEmployeeTime('Total Assigned Days', null); this.totalDaysWorked = new FTEEmployeeTime('Total Days Worked', null); + generateStyles(); + this.contractsTime.add(this.fteTimeManager.unassigned); this.contractsTime.add(this.totalAssignedDays); this.contractsTime.add(this.totalDaysWorked); } private void generateStyles() { - // Calculate totals and labor cost + // Calculate totals for (FTEEmployeeTime empT : this.contractsTime) { - empT.calculateDays(); - this.totalAssignedDays.sumHours(empT); - this.totalDaysWorked.sumHours(empT); + empT.calculateDaysAndTotal(); + this.totalAssignedDays.mergeEmployeeTime(empT); + this.totalDaysWorked.mergeEmployeeTime(empT); } - this.fteTimeManager.unassigned.calculateDays(); - this.totalAssignedDays.calculateDays(); + this.totalDaysWorked.mergeEmployeeTime(this.fteTimeManager.unassigned); + this.fteTimeManager.unassigned.calculateDaysAndTotal(); + this.totalAssignedDays.calculateDaysAndTotal(); + this.totalDaysWorked.calculateDaysAndTotal(); // We add css classes here to avoid complex if sections in visualgforce page for (Integer i = 0; i < 12; i++) { if (this.totalAssignedDays.daysArray[i] > 21) { - this.totalAssignedDays.cssStyle[i] = 'topTotal overbilled'; + this.totalAssignedDays.cssStyle[i] = this.totalAssignedDays.cssStyle[i].remove('fteCell') + ' topTotal overbilled'; } else { - this.totalAssignedDays.cssStyle[i] = 'topTotal'; + this.totalAssignedDays.cssStyle[i] = this.totalAssignedDays.cssStyle[i].remove('fteCell') + ' topTotal'; } - this.totalDaysWorked.cssStyle[i] = ''; + this.totalDaysWorked.cssStyle[i] = this.totalDaysWorked.cssStyle[i].remove('fteCell'); } if (totalAssignedDays.daysArray[12] > employeeNetworkDays) { - this.totalAssignedDays.cssStyle[12] = 'topTotal overbilled'; + this.totalAssignedDays.cssStyle[12] = this.totalAssignedDays.cssStyle[12] + ' topTotal overbilled'; } else { - this.totalAssignedDays.cssStyle[12] = 'topTotal'; + this.totalAssignedDays.cssStyle[12] = this.totalAssignedDays.cssStyle[12] + ' topTotal'; } - this.totalDaysWorked.sumHours(this.fteTimeManager.unassigned); - this.totalDaysWorked.calculateDays(); this.totalDaysWorked.nameCss = ''; this.totalAssignedDays.nameCss = 'topTotal'; this.fteTimeManager.unassigned.nameCss = ''; } - - private void moveHoursInFTEWorkCard(Decimal daysValue, Integer month, Id EmployeeId) { - List workCards = [SELECT Id, Month_1__c, Month_2__c, Month_3__c, Month_4__c, Month_5__c, Month_6__c, Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, - Month_12__c, Total__c, Total_Hours__c FROM FTE_Work_Card__c WHERE Employee__c =: EmployeeId]; - if (workCards.size() > 0) { - Decimal totalValue = workCards.get(0).Total__c; - Decimal totalHoursValue = workCards.get(0).Total_Hours__c; - SObject workCard = workCards.get(0); - Decimal monthValue = (Decimal) workCard.get('Month_' + month + '__c'); - - workCard.put('Total__c', TotalValue + daysValue); - workCard.put('Total_Hours__c', totalHoursValue + (daysValue * 8)); - workCard.put('Month_' + month + '__c', monthValue + daysValue); - update workCard; - } - } } \ No newline at end of file diff --git a/src/classes/FTEEmployeeMonthWrapper.cls b/src/classes/FTEEmployeeMonthWrapper.cls new file mode 100644 index 00000000..b0c1eece --- /dev/null +++ b/src/classes/FTEEmployeeMonthWrapper.cls @@ -0,0 +1,47 @@ +public class FTEEmployeeMonthWrapper implements Comparable { + + private Integer month; + private Integer year; + private Id employeeId; + + public FTEEmployeeMonthWrapper(Id employeeId, Integer month, Integer year) { + this.employeeId = employeeId; + this.month = month; + this.year = year; + } + + public Id getEmployeeId() { + return this.employeeId; + } + + public Integer getMonth() { + return this.month; + } + + public Integer getYear() { + return this.year; + } + + public Boolean equals(Object obj) { + if (obj instanceof FTEEmployeeMonthWrapper) { + FTEEmployeeMonthWrapper toCompare = (FTEEmployeeMonthWrapper) obj; + if (this.employeeId == toCompare.getEmployeeId() + && this.month == toCompare.getMonth() + && this.year == toCompare.getYear()) { + return true; + } + } + return false; + } + + public Integer hashCode() { + return System.hashCode(String.valueOf(this.employeeId) + '-' + this.month + '-' + this.year); + } + + public Integer compareTo(Object objToCompare) { + String empl1 = String.valueOf(this.employeeId) + '-' + this.year; + FTEEmployeeMonthWrapper empWrapper = ((FTEEmployeeMonthWrapper) objToCompare); + String empl2 = String.valueOf(empWrapper.getEmployeeId() + '-' + empWrapper.getYear()); + return empl1.compareTo(empl2); + } +} \ No newline at end of file diff --git a/src/classes/FTEEmployeeMonthWrapper.cls-meta.xml b/src/classes/FTEEmployeeMonthWrapper.cls-meta.xml new file mode 100644 index 00000000..cbddff8c --- /dev/null +++ b/src/classes/FTEEmployeeMonthWrapper.cls-meta.xml @@ -0,0 +1,5 @@ + + + 38.0 + Active + diff --git a/src/classes/FTEEmployeeTime.cls b/src/classes/FTEEmployeeTime.cls index 082f4503..351f8103 100644 --- a/src/classes/FTEEmployeeTime.cls +++ b/src/classes/FTEEmployeeTime.cls @@ -3,32 +3,107 @@ */ public class FTEEmployeeTime { - public String name { get; set;} - public Id objId { get; set;} - public List hoursArray { get; set;} - public List daysArray { get; set;} - public List cssStyle { get; set;} - public String nameCss { get; set;} + public String name { get; set; } + public Boolean merged { get; set; } + public Id objId { get; set; } + public List hoursArray { get; set; } + public List daysArray { get; set; } + public List templateArray { get; set; } + + public List cssStyle { get; set; } + public String nameCss { get; set; } public FTEEmployeeTime (String name, Id objId) { + this.merged = false; this.name = name; this.objId = objId; - this.hoursArray = new Decimal [] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - this.daysArray = new Decimal [] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + this.hoursArray = new Decimal [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + this.daysArray = new Decimal [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + this.templateArray = new Decimal [] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; // Uploaded csv template array, used to merge data an show on UI time projection this.cssStyle = new String [] {'fteCell', 'fteCell', 'fteCell', 'fteCell', 'fteCell', 'fteCell', 'fteCell', 'fteCell', 'fteCell', 'fteCell', - 'fteCell', 'fteCell', '', ''}; + 'fteCell', 'fteCell', '', '' }; this.nameCss = 'fteProjectCell'; } - public void calculateDays() { - for (Integer i = 0 ; i < this.hoursArray.size(); i++) { - this.daysArray[i] = FTETrackerHelper.roundtoDays(this.hoursArray[i]); + public void calculateDaysAndTotal() { + Decimal totalValue = 0; + if (this.merged == false) { + for (Integer i = 0; i < 12; i++) { + Decimal templateValue = (this.templateArray[i] != -1 ? this.templateArray[i] * 8 : -1); + Decimal hoursValue = this.hoursArray[i]; + Decimal finalValue = 0; + + if (templateValue == -1) { + finalValue = hoursValue; + } else { + if (templateValue > hoursValue) { + finalValue = templateValue; + this.cssStyle[i] += ' future'; + } else { + finalValue = hoursValue; + this.cssStyle[i] += ' blocked'; + } + } + + this.daysArray[i] = FTETrackerHelper.roundtoDays(finalValue); + totalValue += finalValue; + } + } else { + for (Integer i = 0; i < 12; i++) { // in merge method css and total was already calculated + this.daysArray[i] = FTETrackerHelper.roundtoDays(this.hoursArray[i]); + totalValue += this.hoursArray[i]; + } + } + this.daysArray[12] = FTETrackerHelper.roundtoDays(totalValue); + } + + public void mergeEmployeeTime(FTEEmployeeTime empTime) { + for (Integer i = 0; i < 12; i++) { + Decimal template1Hours = 8; + Decimal template2Hours = 8; + Decimal templateValue1 = (this.templateArray[i] != -1 ? this.templateArray[i] * (this.merged == true ? 1 : 8): -1); + Decimal templateValue2 = (empTime.templateArray[i] != -1 ? empTime.templateArray[i] * (empTime.merged == true ? 1 : 8): -1); + Decimal hoursValue1 = this.hoursArray[i]; + Decimal hoursValue2 = empTime.hoursArray[i]; + + setStyle(i, hoursValue1, templateValue1); + setStyle(i, hoursValue2, templateValue2); + + if (templateValue1 > -1 && templateValue2 > -1) { + + this.hoursArray[i] = templateValue1 + templateValue2; + this.templateArray[i] = templateValue1 + templateValue2; + + } else if (templateValue1 == -1 && templateValue2 > -1) { + + this.hoursArray[i] = hoursValue1 + templateValue2; + this.templateArray[i] = hoursValue1 + templateValue2; + + } else if (templateValue2 == -1 && templateValue1 > -1) { + + this.hoursArray[i] = templateValue1 + hoursValue2; + this.templateArray[i] = templateValue1 + hoursValue2; + + } else { + + this.hoursArray[i] += hoursValue2; + + } } + this.merged = true; } - public void sumHours(FTEEmployeeTime empTime) { - for (Integer i = 0 ; i < this.hoursArray.size(); i++) { - this.hoursArray[i] += empTime.hoursArray[i]; + private void setStyle(Integer index, Decimal value, Decimal template) { + if (template != -1) { + if (template > value) { + if (!this.cssStyle[index].contains('future')) { + this.cssStyle[index ] = 'fteCell future'; + } + } else { + if (!this.cssStyle[index].contains('future')) { + this.cssStyle[index] = 'fteCell blocked'; + } + } } } } \ No newline at end of file diff --git a/src/classes/FTEEmployeeWrapper.cls b/src/classes/FTEEmployeeWrapper.cls new file mode 100644 index 00000000..974693b9 --- /dev/null +++ b/src/classes/FTEEmployeeWrapper.cls @@ -0,0 +1,25 @@ +public class FTEEmployeeWrapper { + + public Id employeeId { get; set; } + public Integer year { get; set; } + + public FTEEmployeeWrapper(Id employeeId, Integer year) { + this.employeeId = employeeId; + this.year = year; + } + + public Integer hashCode() { + return System.hashCode(String.valueOf(this.employeeId) + '-' + this.year); + } + + public Boolean equals(Object obj) { + if (obj instanceof FTEEmployeeWrapper) { + FTEEmployeeWrapper toCompare = (FTEEmployeeWrapper) obj; + if (this.employeeId == toCompare.employeeId + && this.year == toCompare.year) { + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/src/classes/FTEEmployeeWrapper.cls-meta.xml b/src/classes/FTEEmployeeWrapper.cls-meta.xml new file mode 100644 index 00000000..cbddff8c --- /dev/null +++ b/src/classes/FTEEmployeeWrapper.cls-meta.xml @@ -0,0 +1,5 @@ + + + 38.0 + Active + diff --git a/src/classes/FTEGenerateEmployeesWorkCardBatch.cls b/src/classes/FTEGenerateEmployeesWorkCardBatch.cls index 52c39af8..1cebca1c 100644 --- a/src/classes/FTEGenerateEmployeesWorkCardBatch.cls +++ b/src/classes/FTEGenerateEmployeesWorkCardBatch.cls @@ -1,65 +1,33 @@ /** * Batch job for createing FTE Work Cards for FTE Employee List View. */ -public without sharing class FTEGenerateEmployeesWorkCardBatch implements Database.Batchable, Database.Stateful { +public without sharing class FTEGenerateEmployeesWorkCardBatch implements Database.Batchable, Database.Stateful { private Map> workCardsMap; - private Integer calculationYear; - private Set contractsId; - private Set employeesId; + private Set dataSet; public FTEGenerateEmployeesWorkCardBatch() { this(null); } - public FTEGenerateEmployeesWorkCardBatch(Integer year) { - this(new Set(), new Set(), year); + public FTEGenerateEmployeesWorkCardBatch(Set dataSet) { + this.dataSet = dataSet; } - public FTEGenerateEmployeesWorkCardBatch(Set emplSet, Set contractSet, Integer year) { - this.employeesId = emplSet; - this.contractsId = contractSet; - this.calculationYear = year; - this.workCardsMap = new Map>(); - } - - public List start(Database.BatchableContext BC) { - List result = new List(); + public List start(Database.BatchableContext BC) { + List result = new List(); try { - - if (this.calculationYear == null) { + if (this.dataSet == null || this.dataSet.size() == 0) { result = generateWrapperList([SELECT Id, Name, Hire_Date__c, Termination_Date__c, Employee_Type__c, Employee_Status__c FROM SFDC_Employee__c ORDER BY Name]); List oldCards = [SELECT Id FROM FTE_Work_Card__c]; if (oldCards.size() > 0) { delete oldCards; } - } else if (this.calculationYear != null) { - Integer currentYear = Date.today().year(); - if (this.contractsId.size() > 0) { - List contractTimeCards = [SELECT Id, Employee__c FROM Time_Card__c WHERE - (Client__c IN: this.contractsId OR FTE_Contract__c IN: this.contractsId) - AND CALENDAR_YEAR(Date__c) =: this.calculationYear - AND (Employee__r.Employee_Type__c = 'Employee' OR Employee__r.Employee_Type__c = 'Contractor')]; - for (Time_Card__c tc : contractTimeCards) { - if (!this.employeesId.contains(tc.Employee__c)) { - this.employeesId.add(tc.Employee__c); - } - } - } - - List emplList = null; - if (this.employeesId.size() > 0) { - emplList = [SELECT Id, Name, Hire_Date__c, Termination_Date__c, Employee_Type__c, Employee_Status__c - FROM SFDC_Employee__c WHERE Id IN: this.employeesId AND (Employee_Type__c = 'Employee' OR Employee_Type__c = 'Contractor') ORDER BY Name]; - } else { - emplList = [SELECT Id, Name, Hire_Date__c, Termination_Date__c, Employee_Type__c, Employee_Status__c - FROM SFDC_Employee__c WHERE (Employee_Type__c = 'Employee' OR Employee_Type__c = 'Contractor') ORDER BY Name]; - } - - for (SFDC_Employee__c emplRec : emplList) { - result.add(new EmployeeWrapper(emplRec.Id, currentYear)); + } else if (this.dataSet != null && this.dataSet.size() > 0) { + for (FTE_Work_Card__c emplWorkCard : [SELECT Employee__c, Year__c FROM FTE_Work_Card__c WHERE Id IN: this.dataSet]) { + result.add(new FTEEmployeeWrapper(emplWorkCard.Employee__c, Integer.valueOf(emplWorkCard.Year__c))); } } @@ -72,8 +40,8 @@ public without sharing class FTEGenerateEmployeesWorkCardBatch implements Databa return result; } - public void execute(Database.BatchableContext BC, List scope) { - for (EmployeeWrapper employee : scope) { + public void execute(Database.BatchableContext BC, List scope) { + for (FTEEmployeeWrapper employee : scope) { List employeeWorkCards = [SELECT Id FROM FTE_Work_Card__c WHERE Employee__c =: employee.employeeId AND Year__c =: employee.year]; FTE_Work_Card__c employeeWorkCard = new FTE_Work_Card__c(Employee__c = employee.employeeId, Year__c = employee.year, Month_1__c = 0, Month_2__c = 0, Month_3__c = 0, Month_4__c = 0, Month_5__c = 0, Month_6__c = 0, @@ -82,57 +50,57 @@ public without sharing class FTEGenerateEmployeesWorkCardBatch implements Databa if (employeeWorkCards.size() > 0) { employeeWorkCard.Id = employeeWorkCards.get(0).Id; } - SObject sObj = (SObject) employeeWorkCard; - Decimal totalHours = 0; - Decimal monthHours = 0; - Decimal monthDays = 0; - Integer month = 1; - List employeeYearTimeCards = [SELECT Id, Total__c, Date__c, Client__r.FTE_Tracker__c, FTE_hours__c, FTE_Contract__c, - FTE_Contract__r.FTE_Tracker__c FROM Time_Card__c - WHERE Employee__c =: employee.employeeId AND CALENDAR_YEAR(Date__c) =: employee.year AND (Client__r.FTE_Tracker__c = 'Yes' - OR (Client__r.FTE_Tracker__c != 'Yes' AND FTE_Contract__r.FTE_Tracker__c = 'Yes')) - AND Total__c != null ORDER BY Date__c]; // we need only fetch timcards assigned and unassigned which are moving time to assigned - - for (Time_Card__c tc : employeeYearTimeCards) { - System.debug('TC Date: ' + tc.Date__c); - System.debug('TC Time: ' + tc.Date__c); - if (tc.Date__c.month() != month) { - monthDays = FTETrackerHelper.roundtoDays(monthHours); - sObj.put('Month_' + month + '__c', monthDays); - month = tc.Date__c.month(); - monthHours = 0; - } - Decimal realHours = tc.Total__c; + Map contractAllocationMapping = new Map(); + for (FTE_Data_Record__c futureTemplate : [SELECT Contract__c, Employee__c, Month_1__c, Month_2__c, Month_3__c, Month_4__c, Month_5__c, Month_6__c, + Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, Month_12__c + FROM FTE_Data_Record__c + WHERE Employee__c =: employee.employeeId AND Year__c =: employee.year AND Contract__r.FTE_Tracker__c = 'Yes']) { + contractAllocationMapping.put(futureTemplate.Contract__c, futureTemplate); + } - if (tc.Client__r.FTE_Tracker__c == 'Yes' && tc.FTE_Contract__c != null && tc.FTE_Contract__r.FTE_Tracker__c != 'Yes') { // We must substract hours if moved to unassigned - realHours = realHours - tc.FTE_hours__c; - } else if (tc.Client__r.FTE_Tracker__c != 'Yes' && tc.FTE_Contract__c != null && tc.FTE_Contract__r.FTE_Tracker__c == 'Yes') { // we must move hours from unassigned - realHours = tc.FTE_hours__c; + FTEDataManager dataManager = new FTEDataManager(employee.year, employee.employeeId, true); + dataManager.loadEmployeeTime(); + dataManager.loadTemplateTime(); + + Decimal totalValue = 0; + Decimal[] timeArray = new Decimal [] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + for (Id contractId : dataManager.assignedMap.keySet()) { + FTEEmployeeTime emplTime = dataManager.assignedMap.get(contractId); + for (Integer month = 1; month <= 12; month++) { + Decimal templateTime = (emplTime.templateArray[month - 1] != -1 ? emplTime.templateArray[month - 1] * 8 : -1); + Decimal loggedTime = emplTime.hoursArray[month - 1]; + Decimal finalResult = 0; + + if (templateTime != -1 && templateTime > loggedTime) { + finalResult = templateTime; + sObj.put(FTETrackerHelper.getFieldTemplateFutureName(month), true); // UI metadata, increase performance + } else if (templateTime != -1 && templateTime == loggedTime) { + finalResult = loggedTime; + sObj.put(FTETrackerHelper.getFieldTemplateBlockedName(month), true); // UI metadata increase performance + } else { + finalResult = loggedTime; + } + timeArray[month - 1] += finalResult; + totalValue += finalResult; } - - monthHours += realHours; - totalHours += realHours; } - - monthDays = FTETrackerHelper.roundtoDays(monthHours); - sObj.put('Month_' + month + '__c', monthDays); - - employeeWorkCard = (FTE_Work_Card__c) sObj; - employeeWorkCard.Total_Hours__c = totalHours; - employeeWorkCard.Total__c = FTETrackerHelper.roundtoDays(totalHours); - + employeeWorkCard.Total_Hours__c = totalValue; + employeeWorkCard.Total__c = FTETrackerHelper.roundtoDays(totalValue); + // Merge temlate data and real data + for (Integer month = 1; month <= 12; month++) { + sObj.put(FTETrackerHelper.getFieldName(month), FTETrackerHelper.roundtoDays(timeArray[month - 1])); + } upsert employeeWorkCard; } } public void finish(Database.BatchableContext BC) { - } - private List generateWrapperList(List employees) { - List result = new List(); + private List generateWrapperList(List employees) { + List result = new List(); Integer currentYear = Date.today().year(); Integer twoYearsAhead = currentYear + 2; Integer nextYear = currentYear + 1; @@ -141,36 +109,25 @@ public without sharing class FTEGenerateEmployeesWorkCardBatch implements Databa for (SFDC_Employee__c emplRec : employees) { if (emplRec.Employee_Status__c == 'Active' && (emplRec.Hire_Date__c != null && emplRec.Hire_Date__c.year() <= twoYearsAhead) && emplRec.Termination_Date__c == null) { - result.add(new EmployeeWrapper(emplRec.Id, twoYearsAhead)); + result.add(new FTEEmployeeWrapper(emplRec.Id, twoYearsAhead)); } if (emplRec.Employee_Status__c == 'Active' && (emplRec.Hire_Date__c != null && emplRec.Hire_Date__c.year() <= nextYear) && emplRec.Termination_Date__c == null) { - result.add(new EmployeeWrapper(emplRec.Id, nextYear)); + result.add(new FTEEmployeeWrapper(emplRec.Id, nextYear)); } if ((emplRec.Employee_Status__c == 'Active' && (emplRec.Hire_Date__c != null && emplRec.Hire_Date__c.year() <= currentYear)) || (emplRec.Termination_Date__c != null && emplRec.Termination_Date__c.year() == currentYear)) { - result.add(new EmployeeWrapper(emplRec.Id, currentYear)); + result.add(new FTEEmployeeWrapper(emplRec.Id, currentYear)); } if ((emplRec.Hire_Date__c != null && emplRec.Hire_Date__c.year() <= oneYearAgo) || (emplRec.Termination_Date__c != null && emplRec.Termination_Date__c.year() == oneYearAgo)) { - result.add(new EmployeeWrapper(emplRec.Id, oneYearAgo)); + result.add(new FTEEmployeeWrapper(emplRec.Id, oneYearAgo)); } } return result; } - - public class EmployeeWrapper { - - public Id employeeId { get; set; } - public Integer year { get; set; } - - public EmployeeWrapper(Id employeeId, Integer year) { - this.employeeId = employeeId; - this.year = year; - } - } } \ No newline at end of file diff --git a/src/classes/FTEGenerateEmployeesWorkCardScheduler.cls b/src/classes/FTEGenerateEmployeesWorkCardScheduler.cls index 5bdb4960..8c5ba510 100644 --- a/src/classes/FTEGenerateEmployeesWorkCardScheduler.cls +++ b/src/classes/FTEGenerateEmployeesWorkCardScheduler.cls @@ -1,5 +1,6 @@ /** - * Schedules FTEUpdateTagsBatch job, then FTERemoveNegativeHoursBatch, FTEGenerateEmployeesWorkCardBatch. + * Schedules FTEUpdateTagsBatch job, then FTETimeAllocator and FTEGenerateEmployeesWorkCardBatch. First job checks situation in which FTE Tag was deleted by FB sync, + * Second job is allocationg FTE Time by using uploaded CSV templates, the last job is calculationg work cards used by FTE Tracker Ui to increase performance. */ public without sharing class FTEGenerateEmployeesWorkCardScheduler implements Schedulable { diff --git a/src/classes/FTEIndividualProjectController.cls b/src/classes/FTEIndividualProjectController.cls index 8089ad09..3ed723cb 100644 --- a/src/classes/FTEIndividualProjectController.cls +++ b/src/classes/FTEIndividualProjectController.cls @@ -59,16 +59,15 @@ public class FTEIndividualProjectController extends FTEController { Integer monthIndex = timeCard.Date__c.month() - 1; tmpHelper.hoursArray[monthIndex] += realHours; - tmpHelper.hoursArray[12] += realHours; projectTimeMap.put(timeCard.Employee__c, tmpHelper); } this.individualContractDataList = projectTimeMap.values(); for (FTEEmployeeTime empT : this.individualContractDataList) { - empT.calculateDays(); - totalProjectTime.sumHours(empT); + empT.calculateDaysAndTotal(); + totalProjectTime.mergeEmployeeTime(empT); } - totalProjectTime.calculateDays(); + totalProjectTime.calculateDaysAndTotal(); totalProjectTime.cssStyle[0] = 'topTotal'; totalProjectTime.cssStyle[1] = 'topTotal'; totalProjectTime.cssStyle[2] = 'topTotal'; diff --git a/src/classes/FTETimeAllocator.cls b/src/classes/FTETimeAllocator.cls new file mode 100644 index 00000000..d0eab210 --- /dev/null +++ b/src/classes/FTETimeAllocator.cls @@ -0,0 +1,94 @@ +public without sharing class FTETimeAllocator implements Database.Batchable, Database.Stateful { + + private Integer cacheYear; + private Id cacheEmployee; + private List cacheRecords; + private Set cacheWorkCards; + private Boolean csvUpload; + + public FTETimeAllocator(Boolean csvUpload) { + this.csvUpload = csvUpload; + this.cacheWorkCards = new Set(); + } + + public List start(Database.BatchableContext BC) { // we use data wrapper because we don't want process same month a few times, for example multiple contract updates + List result = null; + + result = [SELECT Id, Employee__c, Year__c, + Month_1__c, Month_2__c, Month_3__c, Month_4__c, Month_5__c, Month_6__c, + Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, Month_12__c, + Month_Updated_1__c, Month_Updated_2__c, Month_Updated_3__c, Month_Updated_4__c, Month_Updated_5__c, Month_Updated_6__c, + Month_Updated_7__c, Month_Updated_8__c, Month_Updated_9__c, Month_Updated_10__c, Month_Updated_11__c, Month_Updated_12__c + FROM FTE_Data_Record__c + WHERE Month_Updated_1__c = true OR Month_Updated_2__c = true OR Month_Updated_3__c = true OR Month_Updated_4__c = true OR + Month_Updated_5__c = true OR Month_Updated_6__c = true OR Month_Updated_7__c = true OR Month_Updated_8__c = true OR + Month_Updated_9__c = true OR Month_Updated_10__c = true OR Month_Updated_11__c = true OR Month_Updated_12__c = true + ORDER BY Employee__c]; + + Set emplDateSet = new Set(); + for (FTE_Data_Record__c fteData : result) { + SObject sObjTemplate = (SObject) fteData; + for (Integer month = 1; month <= 12; month++) { + Boolean needUpdate = (Boolean) sObjTemplate.get(FTETrackerHelper.getFieldUpdatedName(month)); + if (needUpdate) { + emplDateSet.add(new FTEEmployeeMonthWrapper(fteData.Employee__c, month, Integer.valueOf(fteData.Year__c))); + } + } + } + + List batchData = new List(); + batchData.addAll(emplDateSet); + batchData.sort(); // we want employees in the same order to cache DB data + + return batchData; + } + + public void execute(Database.BatchableContext BC, List scope) { + for (FTEEmployeeMonthWrapper employeeMonth : scope) { + // Handle cache reload + if (employeeMonth.getEmployeeId() != this.cacheEmployee) { + this.cacheEmployee = employeeMonth.getEmployeeId(); + this.cacheYear = employeeMonth.getYear(); + List employeeWorkCards = [SELECT Id FROM FTE_Work_Card__c WHERE Employee__c =: this.cacheEmployee AND Year__c =: this.cacheYear]; + if (employeeWorkCards.size() > 0) { + this.cacheWorkCards.add(employeeWorkCards.get(0).Id); + } + this.cacheRecords = [SELECT Id, Employee__c, Year__c, Contract__c, + Month_1__c, Month_2__c, Month_3__c, Month_4__c, Month_5__c, Month_6__c, + Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, Month_12__c, + Month_Updated_1__c, Month_Updated_2__c, Month_Updated_3__c, Month_Updated_4__c, Month_Updated_5__c, Month_Updated_6__c, + Month_Updated_7__c, Month_Updated_8__c, Month_Updated_9__c, Month_Updated_10__c, Month_Updated_11__c, Month_Updated_12__c + FROM FTE_Data_Record__c WHERE Employee__c =: this.cacheEmployee AND Year__c =: this.cacheYear AND Contract__r.FTE_Tracker__c = 'Yes' + ORDER BY LastModifiedDate]; + } + + // Load employee month time table + Integer month = employeeMonth.getMonth(); + FTEDataManager fteManager = new FTEDataManager(this.cacheYear, month, this.cacheEmployee, true); + fteManager.loadEmployeeTime(); + fteManager.removeNegativeTime(); + + // Template time allocation loop + for (FTE_Data_Record__c template : this.cacheRecords) { + SObject sObjTemplate = (SObject) template; + Decimal monthValue = (Decimal) sObjTemplate.get(FTETrackerHelper.getFieldName(month)); // get month threshold + + fteManager.setTime(template.Contract__c, monthValue * 8); // allocate time in hours not days + + sObjTemplate.put(FTETrackerHelper.getFieldUpdatedName(month), false); // rest month flag + } + + if (this.cacheRecords.size() > 0) { + update this.cacheRecords; + } + } + } + + public void finish(Database.BatchableContext BC) { + if (this.csvUpload == false && !Test.isRunningTest()) { // we want run daily update for all work cards and employees + Database.executeBatch(new FTEGenerateEmployeesWorkCardBatch(), 1); + } else if (this.csvUpload == true && this.cacheWorkCards.size() > 0 && !Test.isRunningTest()) { + Database.executeBatch(new FTEGenerateEmployeesWorkCardBatch(this.cacheWorkCards), 1); // refresh only uploaded contract and employees + } + } +} \ No newline at end of file diff --git a/src/classes/FTETimeAllocator.cls-meta.xml b/src/classes/FTETimeAllocator.cls-meta.xml new file mode 100644 index 00000000..cbddff8c --- /dev/null +++ b/src/classes/FTETimeAllocator.cls-meta.xml @@ -0,0 +1,5 @@ + + + 38.0 + Active + diff --git a/src/classes/FTETrackerController.cls b/src/classes/FTETrackerController.cls index 13352d73..eb6729b1 100644 --- a/src/classes/FTETrackerController.cls +++ b/src/classes/FTETrackerController.cls @@ -52,9 +52,14 @@ public class FTETrackerController extends FTEController { QueryBuilder qb = new QueryBuilder('FTE_Work_Card__c'); QueryBuilder qbCount = new QueryBuilder('FTE_Work_Card__c'); - qb.addColumns(new List { 'Id', 'Employee__c', 'Employee__r.Hire_Date__c', 'Employee__r.Name', 'Month_1__c', 'Month_2__c', 'Month_3__c', - 'Month_4__c', 'Month_5__c', 'Month_6__c', 'Month_7__c', 'Month_8__c', 'Month_9__c', 'Month_10__c', 'Month_11__c', - 'Month_12__c', 'Total__c', 'Total_Hours__c', 'Year__c'}); + qb.addColumns(new List { 'Id', 'Employee__c', 'Employee__r.Hire_Date__c', 'Employee__r.Name', 'Total__c', 'Total_Hours__c', + 'Year__c', 'Month_1__c', 'Month_2__c', 'Month_3__c', 'Month_4__c', 'Month_5__c', 'Month_6__c', + 'Month_7__c', 'Month_8__c', 'Month_9__c', 'Month_10__c', 'Month_11__c', 'Month_12__c', + 'Month_Future_1__c', 'Month_Future_2__c', 'Month_Future_3__c', 'Month_Future_4__c', 'Month_Future_5__c', 'Month_Future_6__c', + 'Month_Future_7__c', 'Month_Future_8__c', 'Month_Future_9__c', 'Month_Future_10__c', 'Month_Future_11__c', 'Month_Future_12__c', + 'Month_Blocked_1__c', 'Month_Blocked_2__c', 'Month_Blocked_3__c', 'Month_Blocked_4__c', 'Month_Blocked_5__c', 'Month_Blocked_6__c', + 'Month_Blocked_7__c', 'Month_Blocked_8__c', 'Month_Blocked_9__c', 'Month_Blocked_10__c', 'Month_Blocked_11__c', 'Month_Blocked_12__c' + }); qbCount.addColumn('count()'); if (this.employeeNameSearch != null && this.employeeNameSearch != '') { @@ -87,27 +92,38 @@ public class FTETrackerController extends FTEController { for (FTE_Work_Card__c workCard : workCards) { Integer empNetworkDays = FTETrackerHelper.getNetworkDays(workCard.Employee__r.Hire_Date__c, this.fteYear); FTEEmployeeTime empTime = new FTEEmployeeTime(workCard.Employee__r.Name, workCard.Employee__c); - empTime.daysArray[0] = workCard.Month_1__c; - empTime.daysArray[1] = workCard.Month_2__c; - empTime.daysArray[2] = workCard.Month_3__c; - empTime.daysArray[3] = workCard.Month_4__c; - empTime.daysArray[4] = workCard.Month_5__c; - empTime.daysArray[5] = workCard.Month_6__c; - empTime.daysArray[6] = workCard.Month_7__c; - empTime.daysArray[7] = workCard.Month_8__c; - empTime.daysArray[8] = workCard.Month_9__c; - empTime.daysArray[9] = workCard.Month_10__c; - empTime.daysArray[10] = workCard.Month_11__c; - empTime.daysArray[11] = workCard.Month_12__c; + SObject sObj = (SObject) workCard; + + Boolean wasFuture = false; + Boolean wasBlocked = false; + + for (Integer month = 1; month <= 12; month++) { + Boolean futureValue = (Boolean) sObj.get(FTETrackerHelper.getFieldTemplateFutureName(month)); + Boolean blockedValue = (Boolean) sObj.get(FTETrackerHelper.getFieldTemplateBlockedName(month)); + Decimal realValue = (Decimal) sObj.get(FTETrackerHelper.getFieldName(month)); + empTime.daysArray[month - 1] = realValue; + if (empTime.daysArray[month - 1] > 21) { + empTime.cssStyle[month - 1] = empTime.cssStyle[month - 1] + ' overbilled'; + } + if (futureValue == true) { + wasFuture = true; + empTime.cssStyle[month - 1] = empTime.cssStyle[month - 1] + ' future'; + } else if (blockedValue == true) { + wasBlocked = true; + empTime.cssStyle[month - 1] = empTime.cssStyle[month - 1] + ' blocked'; + } + } + empTime.daysArray[12] = workCard.Total__c; if (workCard.Total__c > empNetworkDays) { empTime.cssStyle[12] = 'fteCell overbilled'; } - for (Integer i = 0; i < 12; i++) { - if (empTime.daysArray[i] > 21) { - empTime.cssStyle[i] = 'fteCell overbilled'; - } + if (wasFuture == true) { + empTime.cssStyle[12] = empTime.cssStyle[12] + ' future'; + } else if (wasBlocked == true) { + empTime.cssStyle[12] = empTime.cssStyle[12] + ' blocked'; } + this.employees.add(empTime); } diff --git a/src/classes/FTETrackerHelper.cls b/src/classes/FTETrackerHelper.cls index e5108dd4..203a3555 100644 --- a/src/classes/FTETrackerHelper.cls +++ b/src/classes/FTETrackerHelper.cls @@ -11,14 +11,13 @@ public class FTETrackerHelper { public static JobWrapper loadWorkCardJobStatus() { // We want block FTE Tracker until all Work Cards will be generated from time cards JobWrapper workCardJobStatus = new JobWrapper(false); - ApexClass[] batchClassArray = [SELECT Id, Name FROM ApexClass WHERE Name='FTEGenerateEmployeesWorkCardBatch' OR Name = 'FTEHoursUploadBatch']; + ApexClass[] batchClassArray = [SELECT Id, Name FROM ApexClass WHERE Name = 'FTEGenerateEmployeesWorkCardBatch' OR Name = 'FTETimeAllocator' OR Name = 'FTEUpdateTagsBatch']; AsyncApexJob[] batchClassJobList = [SELECT Id, ApexClassID, JobItemsProcessed, TotalJobItems, CreatedDate FROM AsyncApexJob WHERE ApexClassID IN: batchClassArray AND Status IN ('Holding', 'Queued', 'Preparing', 'Processing') ORDER BY createdDate DESC LIMIT 1]; if(batchClassJobList != null && batchClassJobList.size() > 0) { workCardJobStatus.isRunning = true; - workCardJobStatus.jobName = batchClassArray[0].Id == batchClassJobList[0].ApexClassID ? (batchClassArray[0].Name == 'FTEHoursUploadBatch' ? 'CSV Upload Batch' : 'FTE Working Card Batch' ) - : (batchClassArray[1].Name == 'FTEHoursUploadBatch' ? 'CSV Upload Batch' : 'FTE Working Card Batch' ); + workCardJobStatus.jobName = 'FTE Time Allocator'; workCardJobStatus.jobItemsProcessed = batchClassJobList[0].JobItemsProcessed; workCardJobStatus.totalJobItems = batchClassJobList[0].TotalJobItems; } else { @@ -61,4 +60,43 @@ public class FTETrackerHelper { tData.add(new SelectOption(String.valueOf(currentYear - 1), String.valueOf(currentYear - 1))); return tData; } + + public static String getFieldName(Integer month) { + return 'Month_' + month + '__c'; + } + + public static String getFieldTemplateFutureName(Integer month) { + return 'Month_Future_' + month + '__c'; + } + + public static String getFieldTemplateBlockedName(Integer month) { + return 'Month_Blocked_' + month + '__c'; + } + + public static String getFieldUpdatedName(Integer month) { + return 'Month_Updated_' + month + '__c'; + } + + public static void markTemplates(List contracts) { + List templates = [SELECT Id, Month_Updated_1__c, Month_Updated_2__c, Month_Updated_3__c, Month_Updated_4__c, Month_Updated_5__c, + Month_Updated_6__c, Month_Updated_7__c, Month_Updated_8__c, Month_Updated_9__c, Month_Updated_10__c, Month_Updated_11__c, Month_Updated_12__c + FROM FTE_Data_Record__c WHERE Contract__c IN: contracts]; + if (templates.size() > 0) { + for (FTE_Data_Record__c template : templates) { + template.Month_Updated_1__c = true; + template.Month_Updated_2__c = true; + template.Month_Updated_3__c = true; + template.Month_Updated_4__c = true; + template.Month_Updated_5__c = true; + template.Month_Updated_6__c = true; + template.Month_Updated_7__c = true; + template.Month_Updated_8__c = true; + template.Month_Updated_9__c = true; + template.Month_Updated_10__c = true; + template.Month_Updated_11__c = true; + template.Month_Updated_12__c = true; + } + update templates; + } + } } \ No newline at end of file diff --git a/src/classes/FTETrackerTest.cls b/src/classes/FTETrackerTest.cls index 161f9367..5111894c 100644 --- a/src/classes/FTETrackerTest.cls +++ b/src/classes/FTETrackerTest.cls @@ -133,170 +133,120 @@ public class FTETrackerTest { insert timeCards; } + + + + /** + * Work Cards tests + */ @isTest public static void shouldGenerateWorkCards() { + FTE_Work_Card__c oldWorkCard = new FTE_Work_Card__c(Employee__c = [SELECT Id FROM SFDC_Employee__c LIMIT 1].Id, Year__c = Date.today().year(), Month_1__c = 0, + Month_2__c = 0, Month_3__c = 0, Month_4__c = 0, Month_5__c = 0, Month_6__c = 0, + Month_7__c = 0, Month_8__c = 0, Month_9__c = 0, Month_10__c = 0, Month_11__c = 0, + Month_12__c = 0, Total__c = 0, Total_Hours__c = 0); // should be deleted + insert oldWorkCard; + Test.startTest(); - Database.executeBatch(new FTEGenerateEmployeesWorkCardBatch(Date.today().year())); + Database.executeBatch(new FTEGenerateEmployeesWorkCardBatch()); Test.stopTest(); List employees = [SELECT Id, Name FROM SFDC_Employee__c WHERE Employee_Status__c = 'Active' ORDER BY Name]; System.assertEquals(3, employees.size()); List workCards = [SELECT Id, Employee__c, Employee__r.Name, Month_1__c, Month_2__c, Month_3__c, Month_4__c, Month_5__c, Month_6__c, Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, Month_12__c, - Total__c, Total_Hours__c, Year__c FROM FTE_Work_Card__c ORDER BY Employee__r.Name]; + Total__c, Total_Hours__c, Year__c FROM FTE_Work_Card__c WHERE Year__c =: Date.today().year() ORDER BY Employee__r.Name]; System.assertEquals(3, workCards.size()); System.assertEquals(92.1, workCards.get(0).Total_Hours__c); System.assertEquals(11.5, workCards.get(0).Total__c); + System.assertEquals(0, [SELECT Id FROM FTE_Work_Card__c WHERE Id =: oldWorkCard.Id].size()); } @isTest - public static void triggerShouldGenerateWorkCards() { + public static void shouldGenerateWorkCardsByWorkCardId() { + Id employeeId = [SELECT Id FROM SFDC_Employee__c WHERE Employee_Status__c = 'Active' ORDER BY Name LIMIT 1].Id; + FTE_Work_Card__c oldWorkCard = new FTE_Work_Card__c(Employee__c = employeeId, Year__c = Date.today().year(), Month_1__c = 0, + Month_2__c = 0, Month_3__c = 0, Month_4__c = 0, Month_5__c = 0, Month_6__c = 0, + Month_7__c = 0, Month_8__c = 0, Month_9__c = 0, Month_10__c = 0, Month_11__c = 0, + Month_12__c = 0, Total__c = 0, Total_Hours__c = 0); // should be deleted + insert oldWorkCard; + Test.startTest(); - DContract__c contractToUpdate1 = [SELECT Id, FTE_Tracker__c FROM DContract__c WHERE Name = 'Unassigned Contract 1' LIMIT 1]; - contractToUpdate1.FTE_Tracker__c = 'Yes'; - DContract__c contractToUpdate2 = [SELECT Id, FTE_Tracker__c FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1]; - contractToUpdate2.FTE_Tracker__c = 'No'; - List contractsToUpdate = new List(); - contractsToUpdate.add(contractToUpdate1); - contractsToUpdate.add(contractToUpdate2); - update contractsToUpdate; + Database.executeBatch(new FTEGenerateEmployeesWorkCardBatch(new Set { oldWorkCard.Id })); Test.stopTest(); - List employees = [SELECT Id, Name FROM SFDC_Employee__c WHERE Employee_Status__c = 'Active' ORDER BY Name]; System.assertEquals(3, employees.size()); List workCards = [SELECT Id, Employee__c, Employee__r.Name, Month_1__c, Month_2__c, Month_3__c, Month_4__c, Month_5__c, Month_6__c, Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, Month_12__c, Total__c, Total_Hours__c, Year__c FROM FTE_Work_Card__c WHERE Year__c =: Date.today().year() ORDER BY Employee__r.Name]; - System.assertEquals(3, workCards.size()); - System.assertEquals(85.8, workCards.get(0).Total_Hours__c); // -25,6 + 19,3 - System.assertEquals(10.75, workCards.get(0).Total__c); - } - - @isTest - public static void shouldMoveHoursToUnassigned() { - Date currentDate = Date.today(); - addTimeCard([SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id, - [SELECT Id FROM SFDC_Employee__c WHERE Name = 'Other Employee'].Id, - Date.newInstance(currentDate.year(), currentDate.month(), 5), 3.3); - SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee']; - PageReference pageRef = Page.FTE_Employee_View; - pageRef.getParameters().put('employeeId', String.valueOf(employee.Id)); - Test.setCurrentPage(pageRef); - - Test.startTest(); - FTEEmployeeController controller = new FTEEmployeeController(); - controller.initFteEmployeeView(); - controller.employeeMonth = currentDate.month() - 1; - controller.contractId = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 2' LIMIT 1].Id; - controller.loadEmployeeUnassMonth(); - controller.fteDays = '3'; - controller.moveTimeToUnassigned(); - controller.initFteEmployeeView(); - Test.stopTest(); - - System.assertEquals(70.9, controller.fteTimeManager.unassigned.hoursArray[currentDate.month() - 1]); - System.assertEquals(8.75, controller.fteTimeManager.unassigned.daysArray[currentDate.month() - 1]); - System.assertEquals(68.1, controller.totalAssignedDays.hoursArray[currentDate.month() - 1]); - System.assertEquals(8.5, controller.totalAssignedDays.daysArray[currentDate.month() - 1]); + System.assertEquals(1, workCards.size()); + System.assertEquals(92.1, workCards.get(0).Total_Hours__c); + System.assertEquals(11.5, workCards.get(0).Total__c); } @isTest - public static void shouldAddErrorWhenMovingHoursToUnassigned() { - Date currentDate = Date.today(); - SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee']; - PageReference pageRef = Page.FTE_Employee_View; - pageRef.getParameters().put('employeeId', String.valueOf(employee.Id)); - Test.setCurrentPage(pageRef); - - Test.startTest(); - FTEEmployeeController controller = new FTEEmployeeController(); - controller.initFteEmployeeView(); - controller.employeeMonth = currentDate.month() - 1; - controller.contractId = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 2' LIMIT 1].Id; - controller.loadEmployeeUnassMonth(); - controller.fteDays = '13'; - controller.moveTimeToUnassigned(); - - List msgs = ApexPages.getMessages(); - Boolean b = false; - System.debug('msgs : ' + msgs); - for(Apexpages.Message msg:msgs){ - if (msg.getDetail().contains('Too much hours to assign / hours cannot be negative')) b = true; - } - Test.stopTest(); - - System.assert(b); - } + public static void shouldGenerateWorkCardsWIthTemplateData() { + List employees = [SELECT Id, Name FROM SFDC_Employee__c WHERE Employee_Status__c = 'Active' ORDER BY Name]; - @isTest - public static void shouldMoveHoursFromUnassigned() { - Date currentDate = Date.today(); - SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee']; - PageReference pageRef = Page.FTE_Employee_View; - pageRef.getParameters().put('employeeId', String.valueOf(employee.Id)); - Test.setCurrentPage(pageRef); + DContract__c fteContract1 = [SELECT Id, FTE_Tracker__c FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1]; + Dcontract__c fteContract2 = addContract('FTE Contract Fake 1', 'Yes'); + Dcontract__c fteContract3 = addContract('FTE Contract Fake 2', 'No'); + + FTE_Data_Record__c record1 = new FTE_Data_Record__c(Employee__c = employees.get(0).Id, Contract__c = fteContract2.Id, Year__c = Date.today().year()); + FTE_Data_Record__c record2 = new FTE_Data_Record__c(Employee__c = employees.get(0).Id, Contract__c = fteContract3.Id, Year__c = Date.today().year()); // this should be skipped + FTE_Data_Record__c record3 = new FTE_Data_Record__c(Employee__c = employees.get(0).Id, Contract__c = fteContract1.Id, Year__c = Date.today().year()); + SObject sObj1 = (SObject) record1; + SObject sObj2 = (SObject) record2; + SObject sObj3 = (SObject) record3; + sObj1.put(FTETrackerHelper.getFieldName(Date.today().month()), 4); + sObj2.put(FTETrackerHelper.getFieldName(Date.today().month()), 8); + sObj3.put(FTETrackerHelper.getFieldName(Date.today().month()), 6); + insert sObj1; + insert sObj2; + insert sObj3; Test.startTest(); - FTEEmployeeController controller = new FTEEmployeeController(); - controller.initFteEmployeeView(); - controller.employeeMonth = currentDate.month() - 1; - controller.loadEmployeeMonth(); - controller.fteDays = '2.5'; - controller.selectedFteContract = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; - controller.moveTimeFromUnassigned(); - controller.initFteEmployeeView(); + Database.executeBatch(new FTEGenerateEmployeesWorkCardBatch()); Test.stopTest(); - System.assertEquals(26.9, controller.fteTimeManager.unassigned.hoursArray[currentDate.month() - 1]); - System.assertEquals(3.25, controller.fteTimeManager.unassigned.daysArray[currentDate.month() - 1]); - System.assertEquals(112.1, controller.totalAssignedDays.hoursArray[currentDate.month() - 1]); - System.assertEquals(14, controller.totalAssignedDays.daysArray[currentDate.month() - 1]); + System.assertEquals(3, employees.size()); + List workCards = [SELECT Id, Employee__c, Employee__r.Name, Month_1__c, Month_2__c, Month_3__c, + Month_4__c, Month_5__c, Month_6__c, Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, Month_12__c, + Total__c, Total_Hours__c, Year__c FROM FTE_Work_Card__c WHERE Year__c =: Date.today().year() ORDER BY Employee__r.Name]; + System.assertEquals(3, workCards.size()); + System.assertEquals(146.5, workCards.get(0).Total_Hours__c); + System.assertEquals(18.25, workCards.get(0).Total__c); } @isTest - public static void shouldAddErrorWhenMovingHoursFromUnassigned() { - Date currentDate = Date.today(); - SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee']; - PageReference pageRef = Page.FTE_Employee_View; - pageRef.getParameters().put('employeeId', String.valueOf(employee.Id)); - Test.setCurrentPage(pageRef); - + public static void triggerShouldGenerateWorkCards() { Test.startTest(); - FTEEmployeeController controller = new FTEEmployeeController(); - controller.initFteEmployeeView(); - controller.employeeMonth = currentDate.month() - 1; - controller.loadEmployeeMonth(); - controller.fteDays = '6'; - controller.moveTimeFromUnassigned(); - - List msgs = ApexPages.getMessages(); - Boolean b = false; - for(Apexpages.Message msg:msgs){ - if (msg.getDetail().contains('Too much hours to assign / hours cannot be negative')) b = true; - } + DContract__c contractToUpdate1 = [SELECT Id, FTE_Tracker__c FROM DContract__c WHERE Name = 'Unassigned Contract 1' LIMIT 1]; + contractToUpdate1.FTE_Tracker__c = 'Yes'; + DContract__c contractToUpdate2 = [SELECT Id, FTE_Tracker__c FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1]; + contractToUpdate2.FTE_Tracker__c = 'No'; + List contractsToUpdate = new List(); + contractsToUpdate.add(contractToUpdate1); + contractsToUpdate.add(contractToUpdate2); + update contractsToUpdate; + Database.executeBatch(new FTEGenerateEmployeesWorkCardBatch()); Test.stopTest(); - System.assert(b); + List employees = [SELECT Id, Name FROM SFDC_Employee__c WHERE Employee_Status__c = 'Active' ORDER BY Name]; + System.assertEquals(3, employees.size()); + List workCards = [SELECT Id, Employee__c, Employee__r.Name, Month_1__c, Month_2__c, Month_3__c, + Month_4__c, Month_5__c, Month_6__c, Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, Month_12__c, + Total__c, Total_Hours__c, Year__c FROM FTE_Work_Card__c WHERE Year__c =: Date.today().year() ORDER BY Employee__r.Name]; + System.assertEquals(3, workCards.size()); + System.assertEquals(85.8, workCards.get(0).Total_Hours__c); // -25,6 + 19,3 + System.assertEquals(10.75, workCards.get(0).Total__c); } - @isTest - public static void shouldGenerateEmployeeHours() { - Date currentDate = Date.today(); - SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee']; - PageReference pageRef = Page.FTE_Employee_View; - pageRef.getParameters().put('employeeId', String.valueOf(employee.Id)); - Test.setCurrentPage(pageRef); - Test.startTest(); - FTEEmployeeController controller = new FTEEmployeeController(); - controller.initFteEmployeeView(); - Test.stopTest(); - System.assertEquals(46.9, controller.fteTimeManager.unassigned.hoursArray[currentDate.month() - 1]); - System.assertEquals(5.75, controller.fteTimeManager.unassigned.daysArray[currentDate.month() - 1]); - System.assertEquals(92.1, controller.totalAssignedDays.hoursArray[currentDate.month() - 1]); - System.assertEquals(11.5, controller.totalAssignedDays.daysArray[currentDate.month() - 1]); - } + /** + * Tags tests + */ @isTest public static void triggerShouldAddRemovedTags() { Id cont1 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; @@ -392,597 +342,224 @@ public class FTETrackerTest { System.assertEquals(contUn2, tc2b.FTE_Contract__c); } -/** - @isTest - public static void batchShouldFillNegativeFTETags1() { - SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'Other Employee']; - SFDC_Employee__c employee2 = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'Yyy Employee']; - Id cont1 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; - Id cont3 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 3' LIMIT 1].Id; - Id cont4 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 4' LIMIT 1].Id; - Id contUn1 = [SELECT Id FROM DContract__c WHERE Name = 'Unassigned Contract 1' LIMIT 1].Id; - Id contUn2 = [SELECT Id FROM DContract__c WHERE Name = 'Unassigned Contract 2' LIMIT 1].Id; - - Test.startTest(); - - List toDel = new List(); - List toUpd = new List(); - - Time_Card__c tc1 = [SELECT Id, Total__c FROM Time_Card__c WHERE Employee__c =: employee.Id AND Client__c =: cont4 LIMIT 1]; - Time_Card__c tc2 = [SELECT Id, Total__c FROM Time_Card__c WHERE Employee__c =: employee.Id AND Client__c =: cont1 AND Total__c = 6 LIMIT 1]; - toDel.add(tc1); - toDel.add(tc2); - - Time_Card__c tc3 = [SELECT Id, Total__c FROM Time_Card__c WHERE Employee__c =: employee.Id AND Client__c =: cont1 AND Total__c = 4.3 LIMIT 1]; - Time_Card__c tc4 = [SELECT Id, Total__c FROM Time_Card__c WHERE Employee__c =: employee.Id AND Client__c =: cont1 AND Total__c = 3.3 LIMIT 1]; - tc3.Total__c = 1.3; - tc4.Total__c = 2.3; - - toDel.addAll([SELECT Id, Total__c FROM Time_Card__c WHERE Employee__c =: employee2.Id AND Client__c =: cont4]); - Time_Card__c tc5 = [SELECT Id, Total__c FROM Time_Card__c WHERE Employee__c =: employee2.Id AND Client__c =: cont1 AND Total__c = 4 LIMIT 1]; - Time_Card__c tc6 = [SELECT Id, Total__c FROM Time_Card__c WHERE Employee__c =: employee2.Id AND Client__c =: cont1 AND Total__c = 5 LIMIT 1]; - tc5.Total__c = 1; - tc6.Total__c = 1; - toUpd.add(tc3); - toUpd.add(tc4); - toUpd.add(tc5); - toUpd.add(tc6); - delete toDel; - update toUpd; - Database.executeBatch(new FTEUpdateTagsBatch(true)); + /** + * FTE Triggers tests + */ + @isTest + public static void testContractTrigger() { + SFDC_Employee__c empl1 = addEmployee('FTE test1'); + SFDC_Employee__c empl2 = addEmployee('FTE test2'); + DContract__c dContract1 = addContract('Trigger contract 1', 'No'); + DContract__c dContract2 = addContract('Trigger contract 2', 'No'); + DContract__c dContract3 = addContract('Trigger contract 2', 'No'); + + insert new List { + new FTE_Data_Record__c(Contract__c = dContract1.Id, Employee__c = empl1.Id), + new FTE_Data_Record__c(Contract__c = dContract2.Id, Employee__c = empl1.Id), + new FTE_Data_Record__c(Contract__c = dContract3.Id, Employee__c = empl1.Id), + new FTE_Data_Record__c(Contract__c = dContract1.Id, Employee__c = empl2.Id) + }; + Test.startTest(); + dContract1.FTE_Tracker__c = 'Yes'; + dContract2.FTE_Tracker__c = 'Yes'; + dContract3.FTE_Tracker__c = 'Yes'; + FTETrackerHelper.markTemplates(new List { dContract1, dContract2, dContract3 }); Test.stopTest(); - List results = sumHours([SELECT Id, Total__c, FTE_Hours__c, FTE_Contract__c FROM Time_Card__c WHERE Client__c =: cont1 AND Employee__r.Name = 'Other Employee']); - System.assertEquals(18.6, results.get(0)); - System.assertEquals(5, results.get(1)); - - Time_Card__c testTimeCard = [SELECT Id, FTE_Only__c, FTE_Contract__c, Total__c, FTE_Hours__c, Client__c FROM Time_Card__c WHERE - Client__r.Name = 'FTE Contract 4' AND Employee__r.Name = 'Other Employee' LIMIT 1]; - System.assertEquals(cont4, testTimeCard.Client__c); - System.assertEquals(true, testTimeCard.FTE_only__c); - System.assertEquals(0, testTimeCard.FTE_Hours__c); - System.assertEquals(null, testTimeCard.FTE_Contract__c); - - results = sumHours([SELECT Id, Total__c, FTE_Hours__c, FTE_Contract__c FROM Time_Card__c WHERE Client__c =: cont1 AND Employee__r.Name = 'Yyy Employee']); - System.assertEquals(12.1, results.get(0)); - System.assertEquals(8, results.get(1)); - - testTimeCard = [SELECT Id, FTE_Only__c, FTE_Contract__c, Total__c, FTE_Hours__c, Client__c FROM Time_Card__c WHERE - Client__r.Name = 'FTE Contract 4' AND Employee__r.Name = 'Yyy Employee' LIMIT 1]; - System.assertEquals(cont4, testTimeCard.Client__c); - System.assertEquals(true, testTimeCard.FTE_only__c); - System.assertEquals(0, testTimeCard.Total__c); - System.assertEquals(2, testTimeCard.FTE_Hours__c); - System.assertEquals(cont3, testTimeCard.FTE_Contract__c); + List tamplates = [SELECT Id, Month_Updated_1__c, Month_Updated_2__c, Month_Updated_3__c, Month_Updated_4__c, Month_Updated_5__c, + Month_Updated_6__c, Month_Updated_7__c, Month_Updated_8__c, Month_Updated_9__c, Month_Updated_10__c, Month_Updated_11__c, Month_Updated_12__c + FROM FTE_Data_Record__c]; + System.assertEquals(4, tamplates.size()); + assertTemplateUpdated(tamplates.get(0)); + assertTemplateUpdated(tamplates.get(1)); + assertTemplateUpdated(tamplates.get(2)); + assertTemplateUpdated(tamplates.get(3)); } @isTest - public static void batchShouldFillNegativeFTETags2() { - SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'Other Employee']; - SFDC_Employee__c employee2 = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'Yyy Employee']; - Id cont1 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; - Id cont2 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 2' LIMIT 1].Id; - Id cont3 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 3' LIMIT 1].Id; - Id cont4 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 4' LIMIT 1].Id; - Id contUn1 = [SELECT Id FROM DContract__c WHERE Name = 'Unassigned Contract 1' LIMIT 1].Id; - Id contUn2 = [SELECT Id FROM DContract__c WHERE Name = 'Unassigned Contract 2' LIMIT 1].Id; + public static void testTimeLoggedTrigger() { + SFDC_Employee__c empl1 = addEmployee('FTE test1'); + SFDC_Employee__c empl2 = addEmployee('FTE test2'); + DContract__c dContract1 = addContract('Trigger contract 1', 'Yes'); + DContract__c dContract2 = addContract('Trigger contract 2', 'Yes'); + DContract__c dContract3 = addContract('Trigger contract 2', 'Yes'); + Integer currentYear = Date.today().year(); + insert new List { + new FTE_Data_Record__c(Year__c = currentYear, Contract__c = dContract1.Id, Employee__c = empl1.Id), + new FTE_Data_Record__c(Year__c = currentYear, Contract__c = dContract2.Id, Employee__c = empl1.Id), + new FTE_Data_Record__c(Year__c = currentYear, Contract__c = dContract3.Id, Employee__c = empl1.Id), + new FTE_Data_Record__c(Year__c = currentYear, Contract__c = dContract1.Id, Employee__c = empl2.Id) + }; Test.startTest(); + List testTimeCards = new List { + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 3, 1), Employee__c = empl1.Id, Client__c = dContract1.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 3, 21), Employee__c = empl1.Id, Client__c = dContract1.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 3, 3), Employee__c = empl1.Id, Client__c = dContract1.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 1, 1), Employee__c = empl1.Id, Client__c = dContract1.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 1, 5), Employee__c = empl1.Id, Client__c = dContract1.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 1, 6), Employee__c = empl1.Id, Client__c = dContract1.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 9, 7), Employee__c = empl1.Id, Client__c = dContract1.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 12, 5), Employee__c = empl1.Id, Client__c = dContract2.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 12, 6), Employee__c = empl1.Id, Client__c = dContract2.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 12, 7), Employee__c = empl1.Id, Client__c = dContract2.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 11, 5), Employee__c = empl1.Id, Client__c = dContract2.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 10, 6), Employee__c = empl1.Id, Client__c = dContract2.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 9, 7), Employee__c = empl1.Id, Client__c = dContract2.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 10, 5), Employee__c = empl1.Id, Client__c = dContract3.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 7, 6), Employee__c = empl1.Id, Client__c = dContract3.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 6, 7), Employee__c = empl1.Id, Client__c = dContract3.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 6, 5), Employee__c = empl1.Id, Client__c = dContract3.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 6, 6), Employee__c = empl1.Id, Client__c = dContract3.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 5, 7), Employee__c = empl1.Id, Client__c = dContract3.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 3, 5), Employee__c = empl1.Id, Client__c = dContract3.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 4, 6), Employee__c = empl1.Id, Client__c = dContract3.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 8, 7), Employee__c = empl2.Id, Client__c = dContract1.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 8, 5), Employee__c = empl2.Id, Client__c = dContract1.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 8, 6), Employee__c = empl2.Id, Client__c = dContract1.Id), + new Time_Card__c(Total__c = 2, Date__c = Date.newInstance(currentYear, 8, 7), Employee__c = empl2.Id, Client__c = dContract1.Id) + }; + insert testTimeCards; + FTETriggerHelper.processTemplates(testTimeCards); + Test.stopTest(); - List toDel = new List(); - List toUpd = new List(); - - Time_Card__c tc1 = [SELECT Id, Total__c FROM Time_Card__c WHERE Employee__c =: employee.Id AND Client__c =: cont4 LIMIT 1]; - Time_Card__c tc2 = [SELECT Id, Total__c FROM Time_Card__c WHERE Employee__c =: employee.Id AND Client__c =: cont1 AND Total__c = 6 LIMIT 1]; - Time_Card__c tc3 = [SELECT Id, Total__c FROM Time_Card__c WHERE Employee__c =: employee.Id AND Client__c =: cont1 AND Total__c = 8 LIMIT 1]; - Time_Card__c tc4 = [SELECT Id, Total__c FROM Time_Card__c WHERE Employee__c =: employee.Id AND Client__c =: cont1 AND Total__c = 7 LIMIT 1]; - Time_Card__c tc5 = [SELECT Id, Total__c FROM Time_Card__c WHERE Employee__c =: employee.Id AND Client__c =: cont1 AND Total__c = 4.3 LIMIT 1]; - toDel.add(tc1); - toDel.add(tc2); - toDel.add(tc3); - toDel.add(tc4); - toDel.add(tc5); - - Time_Card__c tc6 = [SELECT Id, Total__c FROM Time_Card__c WHERE Employee__c =: employee2.Id AND Client__c =: cont1 AND Total__c = 4 LIMIT 1]; - Time_Card__c tc7 = [SELECT Id, Total__c FROM Time_Card__c WHERE Employee__c =: employee2.Id AND Client__c =: cont1 AND Total__c = 5 LIMIT 1]; - Time_Card__c tc8 = [SELECT Id, Total__c FROM Time_Card__c WHERE Employee__c =: employee2.Id AND Client__c =: cont1 AND Total__c = 4.6 LIMIT 1]; - Time_Card__c tc9 = [SELECT Id, Total__c FROM Time_Card__c WHERE Employee__c =: employee2.Id AND Client__c =: cont1 AND Total__c = 2.5 LIMIT 1]; - tc6.Total__c = 0.5; - tc7.Total__c = 0.5; - tc8.Total__c = 0.5; - toDel.add(tc9); - toUpd.add(tc6); - toUpd.add(tc7); - toUpd.add(tc8); - - Time_Card__c tc10 = [SELECT Id, Total__c FROM Time_Card__c WHERE Employee__c =: employee2.Id AND Client__c =: cont2 AND Total__c = 7 LIMIT 1]; - Time_Card__c tc11 = [SELECT Id, Total__c FROM Time_Card__c WHERE Employee__c =: employee2.Id AND Client__c =: cont2 AND Total__c = 9 LIMIT 1]; - tc10.Total__c = 1; - tc11.Total__c = 7; - toUpd.add(tc10); - toUpd.add(tc11); - - Time_Card__c tc12 = [SELECT Id, Total__c FROM Time_Card__c WHERE Employee__c =: employee2.Id AND Client__c =: cont3 AND Total__c = 4 LIMIT 1]; - toDel.add(tc12); - - toDel.addAll([SELECT Id FROM Time_Card__c WHERE Client__c =: contUn2 AND Employee__r.Name = 'Yyy Employee']); - - delete toDel; - update toUpd; - Database.executeBatch(new FTEUpdateTagsBatch(true)); + List tamplates = [SELECT Id, Month_Updated_1__c, Month_Updated_2__c, Month_Updated_3__c, Month_Updated_4__c, Month_Updated_5__c, + Month_Updated_6__c, Month_Updated_7__c, Month_Updated_8__c, Month_Updated_9__c, Month_Updated_10__c, Month_Updated_11__c, Month_Updated_12__c + FROM FTE_Data_Record__c]; + System.assertEquals(4, tamplates.size()); + + FTE_Data_Record__c testTEmplate = [SELECT Id, Month_Updated_1__c, Month_Updated_2__c, Month_Updated_3__c, Month_Updated_4__c, Month_Updated_5__c, + Month_Updated_6__c, Month_Updated_7__c, Month_Updated_8__c, Month_Updated_9__c, Month_Updated_10__c, Month_Updated_11__c, Month_Updated_12__c + FROM FTE_Data_Record__c WHERE Contract__c =: dContract1.Id AND Employee__c =: empl1.Id LIMIT 1]; + assertTemplateUpdated(testTEmplate, true, false, true, false, false, false, false, false, true, false, false, false); + + testTEmplate = [SELECT Id, Month_Updated_1__c, Month_Updated_2__c, Month_Updated_3__c, Month_Updated_4__c, Month_Updated_5__c, + Month_Updated_6__c, Month_Updated_7__c, Month_Updated_8__c, Month_Updated_9__c, Month_Updated_10__c, Month_Updated_11__c, Month_Updated_12__c + FROM FTE_Data_Record__c WHERE Contract__c =: dContract2.Id AND Employee__c =: empl1.Id LIMIT 1]; + assertTemplateUpdated(testTEmplate, false, false, false, false, false, false, false, false, true, true, true, true); + + testTEmplate = [SELECT Id, Month_Updated_1__c, Month_Updated_2__c, Month_Updated_3__c, Month_Updated_4__c, Month_Updated_5__c, + Month_Updated_6__c, Month_Updated_7__c, Month_Updated_8__c, Month_Updated_9__c, Month_Updated_10__c, Month_Updated_11__c, Month_Updated_12__c + FROM FTE_Data_Record__c WHERE Contract__c =: dContract3.Id AND Employee__c =: empl1.Id LIMIT 1]; + assertTemplateUpdated(testTEmplate, false, false, true, true, true, true, true, false, false, true, false, false); + + testTEmplate = [SELECT Id, Month_Updated_1__c, Month_Updated_2__c, Month_Updated_3__c, Month_Updated_4__c, Month_Updated_5__c, + Month_Updated_6__c, Month_Updated_7__c, Month_Updated_8__c, Month_Updated_9__c, Month_Updated_10__c, Month_Updated_11__c, Month_Updated_12__c + FROM FTE_Data_Record__c WHERE Contract__c =: dContract1.Id AND Employee__c =: empl2.Id LIMIT 1]; + assertTemplateUpdated(testTEmplate, false, false, false, false, false, false, false, true, false, false, false, false); + } - Test.stopTest(); - List results = sumHours([SELECT Id, Total__c, FTE_Hours__c, FTE_Contract__c FROM Time_Card__c WHERE Client__c =: cont1 AND Employee__r.Name = 'Other Employee']); - System.assertEquals(3.3, results.get(0)); - System.assertEquals(3.3, results.get(1)); - Time_Card__c tc2b = [SELECT Id, FTE_Only__c, FTE_Contract__c, Total__c, FTE_Hours__c, Client__c FROM Time_Card__c WHERE - Client__r.Name = 'FTE Contract 4' AND Employee__r.Name = 'Other Employee' LIMIT 1]; - System.assertEquals(cont4, tc2b.Client__c); - System.assertEquals(true, tc2b.FTE_only__c); - System.assertEquals(0, tc2b.FTE_Hours__c); - System.assertEquals(null, tc2b.FTE_Contract__c); - results = sumHours([SELECT Id, Total__c, FTE_Hours__c, FTE_Contract__c FROM Time_Card__c WHERE Client__c =: cont1 AND Employee__r.Name = 'Yyy Employee']); - System.assertEquals(4.5, results.get(0)); - System.assertEquals(4.5, results.get(1)); + /** + * FTE Data Manager tests + */ + @isTest + public static void testTimeManagerEmpl1() { + SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee' LIMIT 1]; + Id contract1Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; + Id contract2Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 2' LIMIT 1].Id; + Id contract3Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 3' LIMIT 1].Id; + Id contract4Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 4' LIMIT 1].Id; + + Test.startTest(); + FTEDataManager timeManager = new FTEDataManager(Date.today().year(), employee.Id); + timeManager.loadEmployeeTime(); + Integer month = Date.today().month(); - results = sumHours([SELECT Id, Total__c, FTE_Hours__c, FTE_Contract__c FROM Time_Card__c WHERE Client__c =: cont2 AND Employee__r.Name = 'Yyy Employee']); - System.assertEquals(8, results.get(0)); - System.assertEquals(7, results.get(1)); + System.assertEquals(25.6, timeManager.assignedMap.get(contract1Id).hoursArray[month - 1]); + System.assertEquals(25.6, timeManager.assignedMap.get(contract2Id).hoursArray[month - 1]); + System.assertEquals(10.3, timeManager.assignedMap.get(contract3Id).hoursArray[month - 1]); + System.assertEquals(30.6, timeManager.assignedMap.get(contract4Id).hoursArray[month - 1]); + System.assertEquals(19.3 + 27.6, timeManager.unassigned.hoursArray[month - 1]); - results = sumHours([SELECT Id, Total__c, FTE_Hours__c, FTE_Contract__c FROM Time_Card__c WHERE Client__c =: cont3 AND Employee__r.Name = 'Yyy Employee']); - System.assertEquals(3, results.get(0)); - System.assertEquals(5, results.get(1)); + System.assertEquals(0, [SELECT Id FROM Time_Card__c WHERE Employee__c =: employee.Id AND FTE_Contract__r.FTE_Tracker__c = 'No'].size()); + System.assertEquals(0, [SELECT Id FROM Time_Card__c WHERE Employee__c =: employee.Id AND FTE_Contract__r.FTE_Tracker__c = 'Yes'].size()); - results = sumHours([SELECT Id, Total__c, FTE_Hours__c, FTE_Contract__c FROM Time_Card__c WHERE Client__c =: contUn2 AND Employee__r.Name = 'Yyy Employee']); - System.assertEquals(0, results.get(0)); - System.assertEquals(0, results.get(1)); + timeManager.removeTime(contract1Id, 24, Date.today().month()); + System.assertEquals(1, [SELECT Id FROM Time_Card__c WHERE Client__c =: contract1Id AND Employee__c =: employee.Id AND FTE_Contract__r.FTE_Tracker__c = 'No'].size()); - results = sumHours([SELECT Id, Total__c, FTE_Hours__c, FTE_Contract__c FROM Time_Card__c WHERE Client__c =: cont4 AND Employee__r.Name = 'Yyy Employee']); - System.assertEquals(8, results.get(0)); - System.assertEquals(3, results.get(1)); - } -*/ + timeManager.addTime(contract3Id, 8, Date.today().month()); + System.assertEquals(1, [SELECT Id FROM Time_Card__c WHERE FTE_Contract__c =: contract3Id AND Employee__c =: employee.Id AND FTE_Contract__r.FTE_Tracker__c = 'Yes'].size()); + timeManager.addTime(contract3Id, 2, Date.today().month()); + System.assertEquals(1, [SELECT Id FROM Time_Card__c WHERE FTE_Contract__c =: contract3Id AND Employee__c =: employee.Id AND FTE_Contract__r.FTE_Tracker__c = 'Yes'].size()); - @isTest - public static void shouldGenerateCSVDataWithoutTags() { - SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee']; - Integer emplMonth = Date.today().month(); - Integer fteYear = Date.today().year(); - FTETimeCardGenerator generator = new FTETimeCardGenerator(fteYear, emplMonth, employee.Id); - List employeeMonthProjects = generator.generateMonthTimeCards(); - System.assertEquals(5, employeeMonthProjects.size()); - - // Overhead - System.assertEquals('Overhead', employeeMonthProjects.get(4).name); - - // Overhead - Unassigned Contract 1 - System.assertEquals(5, employeeMonthProjects.get(4).hours[20]); - System.assertEquals(6, employeeMonthProjects.get(4).hours[21]); - System.assertEquals(1, employeeMonthProjects.get(4).hours[22]); - System.assertEquals(4, employeeMonthProjects.get(4).hours[23]); - System.assertEquals(3.3, employeeMonthProjects.get(4).hours[24]); - - // Overhead - Unassigned Contract 2 - System.assertEquals(3, employeeMonthProjects.get(4).hours[0]); - System.assertEquals(8, employeeMonthProjects.get(4).hours[1]); - System.assertEquals(9, employeeMonthProjects.get(4).hours[2]); - System.assertEquals(4.3, employeeMonthProjects.get(4).hours[3]); - System.assertEquals(3.3, employeeMonthProjects.get(4).hours[4]); - System.assertEquals(27.6 + 19.3, employeeMonthProjects.get(4).totalHours); - - // FTE Contract 1 - System.assertEquals(5, employeeMonthProjects.get(0).hours[0]); - System.assertEquals(6, employeeMonthProjects.get(0).hours[1]); - System.assertEquals(7, employeeMonthProjects.get(0).hours[2]); - System.assertEquals(4.3, employeeMonthProjects.get(0).hours[3]); - System.assertEquals(3.3, employeeMonthProjects.get(0).hours[4]); - System.assertEquals(25.6, employeeMonthProjects.get(0).totalHours); - - // FTE Contract 2 - System.assertEquals(5, employeeMonthProjects.get(1).hours[5]); - System.assertEquals(6, employeeMonthProjects.get(1).hours[6]); - System.assertEquals(7, employeeMonthProjects.get(1).hours[7]); - System.assertEquals(4.3, employeeMonthProjects.get(1).hours[8]); - System.assertEquals(3.3, employeeMonthProjects.get(1).hours[9]); - System.assertEquals(25.6, employeeMonthProjects.get(1).totalHours); - - // FTE Contract 3 - System.assertEquals(2, employeeMonthProjects.get(2).hours[10]); - System.assertEquals(2, employeeMonthProjects.get(2).hours[11]); - System.assertEquals(2, employeeMonthProjects.get(2).hours[12]); - System.assertEquals(1, employeeMonthProjects.get(2).hours[13]); - System.assertEquals(3.3, employeeMonthProjects.get(2).hours[14]); - System.assertEquals(10.3, employeeMonthProjects.get(2).totalHours); - - // FTE Contract 4 - System.assertEquals(5, employeeMonthProjects.get(3).hours[15]); - System.assertEquals(9, employeeMonthProjects.get(3).hours[16]); - System.assertEquals(9, employeeMonthProjects.get(3).hours[17]); - System.assertEquals(4.3, employeeMonthProjects.get(3).hours[18]); - System.assertEquals(3.3, employeeMonthProjects.get(3).hours[19]); - System.assertEquals(30.6, employeeMonthProjects.get(3).totalHours); + timeManager.removeTime(contract3Id, 5, Date.today().month()); + System.assertEquals(1, [SELECT Id FROM Time_Card__c WHERE FTE_Contract__c =: contract3Id AND Employee__c =: employee.Id AND FTE_Contract__r.FTE_Tracker__c = 'Yes'].size()); + System.assertEquals(1, [SELECT Id FROM Time_Card__c WHERE FTE_Contract__c =: contract3Id AND Employee__c =: employee.Id AND FTE_Contract__r.FTE_Tracker__c = 'Yes' + AND FTE_Hours__c = 5].size()); + Test.stopTest(); } @isTest - public static void shouldGenerateCSVDataWithTagsV1() { - SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee']; - Integer emplMonth = Date.today().month(); - Integer fteYear = Date.today().year(); - FTETimeCardGenerator generator = new FTETimeCardGenerator(fteYear, emplMonth, employee.Id); - - Id cont1 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; - Id cont2 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 2' LIMIT 1].Id; - Id cont3 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 3' LIMIT 1].Id; - Id cont4 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 4' LIMIT 1].Id; - Id contUn1 = [SELECT Id FROM DContract__c WHERE Name = 'Unassigned Contract 1' LIMIT 1].Id; - Id contUn2 = [SELECT Id FROM DContract__c WHERE Name = 'Unassigned Contract 2' LIMIT 1].Id; - - List tcToUpdate = new List(); - Time_Card__c tc1 = [SELECT Id, FTE_Contract__c, FTE_Hours__c FROM Time_Card__c WHERE - Client__c =: cont1 AND DAY_IN_MONTH(Date__c) = 3 LIMIT 1]; - tc1.FTE_Hours__c = 8; - tc1.FTE_Contract__c = cont2; - tcToUpdate.add(tc1); - - Time_Card__c tc2 = [SELECT Id, FTE_Contract__c, FTE_Hours__c FROM Time_Card__c WHERE - Client__c =: cont1 AND DAY_IN_MONTH(Date__c) = 2 LIMIT 1]; - tc2.FTE_Hours__c = 4; - tc2.FTE_Contract__c = contUn2; - tcToUpdate.add(tc2); - - Time_Card__c tc3 = [SELECT Id, FTE_Contract__c, FTE_Hours__c FROM Time_Card__c WHERE - Client__c =: contUn1 AND DAY_IN_MONTH(Date__c) = 22 LIMIT 1]; - tc3.FTE_Hours__c = 13.5; - tc3.FTE_Contract__c = cont4; - tcToUpdate.add(tc3); - - update tcToUpdate; - - Test.setCreatedDate(cont1, DateTime.newInstance(Date.today().year() - 1, 1, 1)); - Test.setCreatedDate(cont2, DateTime.newInstance(Date.today().year() - 1, 2, 1)); - Test.setCreatedDate(cont3, DateTime.newInstance(Date.today().year() - 1, 3, 1)); - Test.setCreatedDate(cont4, DateTime.newInstance(Date.today().year() - 1, 4, 1)); - Test.setCreatedDate(contUn1, DateTime.newInstance(Date.today().year() - 1, 5, 1)); - Test.setCreatedDate(contUn2, DateTime.newInstance(Date.today().year() - 1, 6, 1)); + public static void testTimeManagerEmpl2() { + SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'Other Employee' LIMIT 1]; + Id contract1Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; + Id contract2Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 2' LIMIT 1].Id; + Id contract3Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 3' LIMIT 1].Id; + Id contract4Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 4' LIMIT 1].Id; Test.startTest(); - List employeeMonthProjects = generator.generateMonthTimeCards(); - System.assertEquals(5, employeeMonthProjects.size()); - Test.stopTest(); + FTEDataManager timeManager = new FTEDataManager(Date.today().year(), employee.Id); + timeManager.loadEmployeeTime(); + Integer month = Date.today().month(); - // Overhead - System.assertEquals('Overhead', employeeMonthProjects.get(4).name); - - // Overhead - Unassigned Contract 1 - System.assertEquals(0, employeeMonthProjects.get(4).hours[20]); - System.assertEquals(0, employeeMonthProjects.get(4).hours[21]); - System.assertEquals(0, employeeMonthProjects.get(4).hours[22]); - System.assertEquals(2.5, employeeMonthProjects.get(4).hours[23]); - System.assertEquals(3.3, employeeMonthProjects.get(4).hours[24]); - - // Overhead - Unassigned Contract 2 - System.assertEquals(3, employeeMonthProjects.get(4).hours[0]); - System.assertEquals(11, employeeMonthProjects.get(4).hours[1]); - System.assertEquals(10, employeeMonthProjects.get(4).hours[2]); - System.assertEquals(4.3, employeeMonthProjects.get(4).hours[3]); - System.assertEquals(3.3, employeeMonthProjects.get(4).hours[4]); - System.assertEquals(5.8 + 31.6, employeeMonthProjects.get(4).totalHours); - - // FTE Contract 1 - System.assertEquals(0, employeeMonthProjects.get(0).hours[0]); - System.assertEquals(0, employeeMonthProjects.get(0).hours[1]); - System.assertEquals(6, employeeMonthProjects.get(0).hours[2]); - System.assertEquals(4.3, employeeMonthProjects.get(0).hours[3]); - System.assertEquals(3.3, employeeMonthProjects.get(0).hours[4]); - System.assertEquals(13.6, employeeMonthProjects.get(0).totalHours); - - // FTE Contract 2 - System.assertEquals(5, employeeMonthProjects.get(1).hours[0]); - System.assertEquals(3, employeeMonthProjects.get(1).hours[1]); - System.assertEquals(5, employeeMonthProjects.get(1).hours[5]); - System.assertEquals(6, employeeMonthProjects.get(1).hours[6]); - System.assertEquals(7, employeeMonthProjects.get(1).hours[7]); - System.assertEquals(4.3, employeeMonthProjects.get(1).hours[8]); - System.assertEquals(3.3, employeeMonthProjects.get(1).hours[9]); - System.assertEquals(33.6, employeeMonthProjects.get(1).totalHours); - - // FTE Contract 3 - System.assertEquals(2, employeeMonthProjects.get(2).hours[10]); - System.assertEquals(2, employeeMonthProjects.get(2).hours[11]); - System.assertEquals(2, employeeMonthProjects.get(2).hours[12]); - System.assertEquals(1, employeeMonthProjects.get(2).hours[13]); - System.assertEquals(3.3, employeeMonthProjects.get(2).hours[14]); - System.assertEquals(10.3, employeeMonthProjects.get(2).totalHours); - - // FTE Contract 4 - System.assertEquals(5, employeeMonthProjects.get(3).hours[15]); - System.assertEquals(9, employeeMonthProjects.get(3).hours[16]); - System.assertEquals(9, employeeMonthProjects.get(3).hours[17]); - System.assertEquals(4.3, employeeMonthProjects.get(3).hours[18]); - System.assertEquals(3.3, employeeMonthProjects.get(3).hours[19]); - System.assertEquals(5, employeeMonthProjects.get(3).hours[20]); - System.assertEquals(6, employeeMonthProjects.get(3).hours[21]); - System.assertEquals(1, employeeMonthProjects.get(3).hours[22]); - System.assertEquals(1.5, employeeMonthProjects.get(3).hours[23]); - System.assertEquals(44.1, employeeMonthProjects.get(3).totalHours); + System.assertEquals(28.6 - 5, timeManager.assignedMap.get(contract1Id).hoursArray[month - 1]); + System.assertEquals(null, timeManager.assignedMap.get(contract2Id)); + System.assertEquals(null, timeManager.assignedMap.get(contract3Id)); + System.assertEquals(5 - 2, timeManager.assignedMap.get(contract4Id).hoursArray[month - 1]); + System.assertEquals(19.3 + 5 + 2, timeManager.unassigned.hoursArray[month - 1]); + Test.stopTest(); } @isTest - public static void shouldGenerateCSVDataWithTagsV2() { - SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee']; - Integer emplMonth = Date.today().month(); - Integer fteYear = Date.today().year(); - FTETimeCardGenerator generator = new FTETimeCardGenerator(fteYear, emplMonth, employee.Id); - - Id cont1 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; - Id cont2 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 2' LIMIT 1].Id; - Id cont3 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 3' LIMIT 1].Id; - Id cont4 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 4' LIMIT 1].Id; - Id contUn1 = [SELECT Id FROM DContract__c WHERE Name = 'Unassigned Contract 1' LIMIT 1].Id; - Id contUn2 = [SELECT Id FROM DContract__c WHERE Name = 'Unassigned Contract 2' LIMIT 1].Id; - - List tcToUpdate = new List(); - Time_Card__c tc1 = [SELECT Id, FTE_Contract__c, FTE_Hours__c FROM Time_Card__c WHERE - Client__c =: cont2 AND DAY_IN_MONTH(Date__c) = 6 LIMIT 1]; - tc1.FTE_Hours__c = 30; - tc1.FTE_Contract__c = cont1; - tcToUpdate.add(tc1); - - Time_Card__c tc2 = [SELECT Id, FTE_Contract__c, FTE_Hours__c FROM Time_Card__c WHERE - Client__c =: cont3 AND DAY_IN_MONTH(Date__c) = 11 LIMIT 1]; - tc2.FTE_Hours__c = 8; - tc2.FTE_Contract__c = cont2; - tcToUpdate.add(tc2); - - Time_Card__c tc3 = [SELECT Id, FTE_Contract__c, FTE_Hours__c FROM Time_Card__c WHERE - Client__c =: cont1 AND DAY_IN_MONTH(Date__c) = 1 LIMIT 1]; - tc3.FTE_Hours__c = 12; - tc3.FTE_Contract__c = cont3; - tcToUpdate.add(tc3); - - update tcToUpdate; - - Test.setCreatedDate(cont1, DateTime.newInstance(Date.today().year() - 1, 1, 1)); - Test.setCreatedDate(cont2, DateTime.newInstance(Date.today().year() - 1, 2, 1)); - Test.setCreatedDate(cont3, DateTime.newInstance(Date.today().year() - 1, 3, 1)); - Test.setCreatedDate(cont4, DateTime.newInstance(Date.today().year() - 1, 4, 1)); - Test.setCreatedDate(contUn1, DateTime.newInstance(Date.today().year() - 1, 5, 1)); - Test.setCreatedDate(contUn2, DateTime.newInstance(Date.today().year() - 1, 6, 1)); + public static void testTimeManagerEmpl3() { + SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'Yyy Employee' LIMIT 1]; + Id contract1Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; + Id contract2Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 2' LIMIT 1].Id; + Id contract3Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 3' LIMIT 1].Id; + Id contract4Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 4' LIMIT 1].Id; Test.startTest(); - List employeeMonthProjects = generator.generateMonthTimeCards(); - System.assertEquals(5, employeeMonthProjects.size()); - Test.stopTest(); + FTEDataManager timeManager = new FTEDataManager(Date.today().year(), employee.Id); + timeManager.loadEmployeeTime(); + Integer month = Date.today().month(); - // Overhead - System.assertEquals('Overhead', employeeMonthProjects.get(4).name); - - // Overhead - Unassigned Contract 1 - System.assertEquals(5, employeeMonthProjects.get(4).hours[20]); - System.assertEquals(6, employeeMonthProjects.get(4).hours[21]); - System.assertEquals(1, employeeMonthProjects.get(4).hours[22]); - System.assertEquals(4, employeeMonthProjects.get(4).hours[23]); - System.assertEquals(3.3, employeeMonthProjects.get(4).hours[24]); - - // Overhead - Unassigned Contract 2 - System.assertEquals(3, employeeMonthProjects.get(4).hours[0]); - System.assertEquals(8, employeeMonthProjects.get(4).hours[1]); - System.assertEquals(9, employeeMonthProjects.get(4).hours[2]); - System.assertEquals(4.3, employeeMonthProjects.get(4).hours[3]); - System.assertEquals(3.3, employeeMonthProjects.get(4).hours[4]); - System.assertEquals(19.3 + 27.6, employeeMonthProjects.get(4).totalHours); - - // FTE Contract 1 - System.assertEquals(0, employeeMonthProjects.get(0).hours[0]); - System.assertEquals(0, employeeMonthProjects.get(0).hours[1]); - System.assertEquals(6, employeeMonthProjects.get(0).hours[2]); - System.assertEquals(4.3, employeeMonthProjects.get(0).hours[3]); - System.assertEquals(3.3, employeeMonthProjects.get(0).hours[4]); - System.assertEquals(5, employeeMonthProjects.get(0).hours[5]); - System.assertEquals(6, employeeMonthProjects.get(0).hours[6]); - System.assertEquals(7, employeeMonthProjects.get(0).hours[7]); - System.assertEquals(4.3, employeeMonthProjects.get(0).hours[8]); - System.assertEquals(3.3, employeeMonthProjects.get(0).hours[9]); - System.assertEquals(2, employeeMonthProjects.get(0).hours[10]); - System.assertEquals(2, employeeMonthProjects.get(0).hours[11]); - System.assertEquals(0.4, employeeMonthProjects.get(0).hours[12]); - System.assertEquals(43.6, employeeMonthProjects.get(0).totalHours); - - // FTE Contract 2 - System.assertEquals(0, employeeMonthProjects.get(1).hours[5]); - System.assertEquals(0, employeeMonthProjects.get(1).hours[6]); - System.assertEquals(0, employeeMonthProjects.get(1).hours[7]); - System.assertEquals(0, employeeMonthProjects.get(1).hours[8]); - System.assertEquals(0, employeeMonthProjects.get(1).hours[9]); - System.assertEquals(0, employeeMonthProjects.get(1).hours[10]); - System.assertEquals(0, employeeMonthProjects.get(1).hours[11]); - System.assertEquals(1.6, employeeMonthProjects.get(1).hours[12]); - System.assertEquals(1, employeeMonthProjects.get(1).hours[13]); - System.assertEquals(1, employeeMonthProjects.get(1).hours[14]); - System.assertEquals(3.6, employeeMonthProjects.get(1).totalHours); - - // FTE Contract 3 - System.assertEquals(5, employeeMonthProjects.get(2).hours[0]); - System.assertEquals(6, employeeMonthProjects.get(2).hours[1]); - System.assertEquals(1, employeeMonthProjects.get(2).hours[2]); - System.assertEquals(0, employeeMonthProjects.get(2).hours[10]); - System.assertEquals(0, employeeMonthProjects.get(2).hours[11]); - System.assertEquals(0, employeeMonthProjects.get(2).hours[12]); - System.assertEquals(0, employeeMonthProjects.get(2).hours[13]); - System.assertEquals(2.3, employeeMonthProjects.get(2).hours[14]); - System.assertEquals(14.3, employeeMonthProjects.get(2).totalHours); - - // FTE Contract 4 - System.assertEquals(5, employeeMonthProjects.get(3).hours[15]); - System.assertEquals(9, employeeMonthProjects.get(3).hours[16]); - System.assertEquals(9, employeeMonthProjects.get(3).hours[17]); - System.assertEquals(4.3, employeeMonthProjects.get(3).hours[18]); - System.assertEquals(3.3, employeeMonthProjects.get(3).hours[19]); - System.assertEquals(30.6, employeeMonthProjects.get(3).totalHours); + System.assertEquals(19.1 - 8, timeManager.assignedMap.get(contract1Id).hoursArray[month - 1]); + System.assertEquals(16 - 7 + 5, timeManager.assignedMap.get(contract2Id).hoursArray[month - 1]); + System.assertEquals(7 - 5 + 3 + 16, timeManager.assignedMap.get(contract3Id).hoursArray[month - 1]); + System.assertEquals(8 - 3 + 2, timeManager.assignedMap.get(contract4Id).hoursArray[month - 1]); + System.assertEquals(3 + 22 + 8 + 7 - 16 - 2, timeManager.unassigned.hoursArray[month - 1]); + Test.stopTest(); } - @isTest - public static void shouldGenerateCSVDataWithTagsV3() { - SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'Other Employee']; - Integer emplMonth = Date.today().month(); - Integer fteYear = Date.today().year(); - FTETimeCardGenerator generator = new FTETimeCardGenerator(fteYear, emplMonth, employee.Id); - Id cont1 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; - Id cont2 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 2' LIMIT 1].Id; - Id cont3 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 3' LIMIT 1].Id; - Id cont4 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 4' LIMIT 1].Id; - Id contUn1 = [SELECT Id FROM DContract__c WHERE Name = 'Unassigned Contract 1' LIMIT 1].Id; - Id contUn2 = [SELECT Id FROM DContract__c WHERE Name = 'Unassigned Contract 2' LIMIT 1].Id; - Test.setCreatedDate(cont1, DateTime.newInstance(Date.today().year() - 1, 1, 1)); - Test.setCreatedDate(cont2, DateTime.newInstance(Date.today().year() - 1, 2, 1)); - Test.setCreatedDate(cont3, DateTime.newInstance(Date.today().year() - 1, 3, 1)); - Test.setCreatedDate(cont4, DateTime.newInstance(Date.today().year() - 1, 4, 1)); - Test.setCreatedDate(contUn1, DateTime.newInstance(Date.today().year() - 1, 5, 1)); - Test.setCreatedDate(contUn2, DateTime.newInstance(Date.today().year() - 1, 6, 1)); - Test.startTest(); - List employeeMonthProjects = generator.generateMonthTimeCards(); - System.assertEquals(3, employeeMonthProjects.size()); - Test.stopTest(); + /** + * Time Allocation tests + */ - // Overhead - System.assertEquals('Overhead', employeeMonthProjects.get(2).name); - - // Overhead - Unassigned Contract 1 - System.assertEquals(5, employeeMonthProjects.get(2).hours[20]); - System.assertEquals(6, employeeMonthProjects.get(2).hours[21]); - System.assertEquals(1, employeeMonthProjects.get(2).hours[22]); - System.assertEquals(4, employeeMonthProjects.get(2).hours[23]); - System.assertEquals(3.3, employeeMonthProjects.get(2).hours[24]); - - // Overhead - Unassigned Contract 2 - System.assertEquals(2, employeeMonthProjects.get(2).hours[15]); - System.assertEquals(24.3 + 2, employeeMonthProjects.get(2).totalHours); - - // FTE Contract 1 - System.assertEquals(3, employeeMonthProjects.get(0).hours[0]); - System.assertEquals(6, employeeMonthProjects.get(0).hours[1]); - System.assertEquals(7, employeeMonthProjects.get(0).hours[2]); - System.assertEquals(4.3, employeeMonthProjects.get(0).hours[3]); - System.assertEquals(3.3, employeeMonthProjects.get(0).hours[4]); - System.assertEquals(23.6, employeeMonthProjects.get(0).totalHours); - - // FTE Contract 4 - System.assertEquals(3, employeeMonthProjects.get(1).hours[15]); - System.assertEquals(3, employeeMonthProjects.get(1).totalHours); - } - @isTest - public static void shouldGenerateCSVDataWithTagsV4() { - SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'Yyy Employee']; - Integer emplMonth = Date.today().month(); - Integer fteYear = Date.today().year(); - FTETimeCardGenerator generator = new FTETimeCardGenerator(fteYear, emplMonth, employee.Id); - Id cont1 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; - Id cont2 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 2' LIMIT 1].Id; - Id cont3 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 3' LIMIT 1].Id; - Id cont4 = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 4' LIMIT 1].Id; - Id contUn1 = [SELECT Id FROM DContract__c WHERE Name = 'Unassigned Contract 1' LIMIT 1].Id; - Id contUn2 = [SELECT Id FROM DContract__c WHERE Name = 'Unassigned Contract 2' LIMIT 1].Id; - List tcToUpdate = new List(); - Time_Card__c tc1 = [SELECT Id, FTE_Contract__c, FTE_Hours__c FROM Time_Card__c WHERE - Client__c =: cont2 AND DAY_IN_MONTH(Date__c) = 6 LIMIT 1]; - tc1.FTE_Hours__c = 30; - tc1.FTE_Contract__c = cont1; - tcToUpdate.add(tc1); - - Time_Card__c tc2 = [SELECT Id, FTE_Contract__c, FTE_Hours__c FROM Time_Card__c WHERE - Client__c =: cont3 AND DAY_IN_MONTH(Date__c) = 11 LIMIT 1]; - tc2.FTE_Hours__c = 8; - tc2.FTE_Contract__c = cont2; - tcToUpdate.add(tc2); - - Time_Card__c tc3 = [SELECT Id, FTE_Contract__c, FTE_Hours__c FROM Time_Card__c WHERE - Client__c =: cont1 AND DAY_IN_MONTH(Date__c) = 1 LIMIT 1]; - tc3.FTE_Hours__c = 12; - tc3.FTE_Contract__c = cont3; - tcToUpdate.add(tc3); - - update tcToUpdate; - - Test.setCreatedDate(cont1, DateTime.newInstance(Date.today().year() - 1, 1, 1)); - Test.setCreatedDate(cont2, DateTime.newInstance(Date.today().year() - 1, 2, 1)); - Test.setCreatedDate(cont3, DateTime.newInstance(Date.today().year() - 1, 3, 1)); - Test.setCreatedDate(cont4, DateTime.newInstance(Date.today().year() - 1, 4, 1)); - Test.setCreatedDate(contUn1, DateTime.newInstance(Date.today().year() - 1, 5, 1)); - Test.setCreatedDate(contUn2, DateTime.newInstance(Date.today().year() - 1, 6, 1)); + /** + * Time Cards generation tests + */ - Test.startTest(); - List employeeMonthProjects = generator.generateMonthTimeCards(); - System.assertEquals(5, employeeMonthProjects.size()); - Test.stopTest(); - // Overhead - System.assertEquals('Overhead', employeeMonthProjects.get(4).name); - - // Overhead - Unassigned Contract 1 - System.assertEquals(3, employeeMonthProjects.get(4).hours[0]); - System.assertEquals(4, employeeMonthProjects.get(4).hours[1]); - System.assertEquals(1, employeeMonthProjects.get(4).hours[2]); - System.assertEquals(7, employeeMonthProjects.get(4).hours[5]); - System.assertEquals(3, employeeMonthProjects.get(4).hours[20]); - - // Overhead - Unassigned Contract 2 - System.assertEquals(0, employeeMonthProjects.get(4).hours[21]); - System.assertEquals(0, employeeMonthProjects.get(4).hours[22]); - System.assertEquals(4, employeeMonthProjects.get(4).hours[23]); - System.assertEquals(18 + 4, employeeMonthProjects.get(4).totalHours); - - // FTE Contract 1 - System.assertEquals(0, employeeMonthProjects.get(0).hours[0]); - System.assertEquals(0, employeeMonthProjects.get(0).hours[1]); - System.assertEquals(4, employeeMonthProjects.get(0).hours[2]); - System.assertEquals(4.6, employeeMonthProjects.get(0).hours[3]); - System.assertEquals(2.5, employeeMonthProjects.get(0).hours[4]); - System.assertEquals(11.1, employeeMonthProjects.get(0).totalHours); - - // FTE Contract 2 - System.assertEquals(2, employeeMonthProjects.get(1).hours[5]); - System.assertEquals(7, employeeMonthProjects.get(1).hours[7]); - System.assertEquals(4, employeeMonthProjects.get(1).hours[8]); - System.assertEquals(1, employeeMonthProjects.get(1).hours[9]); - System.assertEquals(14, employeeMonthProjects.get(1).totalHours); - - // FTE Contract 3 - System.assertEquals(0, employeeMonthProjects.get(2).hours[8]); - System.assertEquals(2, employeeMonthProjects.get(2).hours[9]); - System.assertEquals(0.5, employeeMonthProjects.get(2).hours[15]); - System.assertEquals(1.5, employeeMonthProjects.get(2).hours[16]); - System.assertEquals(1, employeeMonthProjects.get(2).hours[17]); - System.assertEquals(6, employeeMonthProjects.get(2).hours[20]); - System.assertEquals(5, employeeMonthProjects.get(2).hours[21]); - System.assertEquals(5, employeeMonthProjects.get(2).hours[22]); - System.assertEquals(21, employeeMonthProjects.get(2).totalHours); - - // FTE Contract 4 - System.assertEquals(0, employeeMonthProjects.get(3).hours[15]); - System.assertEquals(0, employeeMonthProjects.get(3).hours[16]); - System.assertEquals(1, employeeMonthProjects.get(3).hours[17]); - System.assertEquals(1, employeeMonthProjects.get(3).hours[18]); - System.assertEquals(2, employeeMonthProjects.get(3).hours[19]); - System.assertEquals(1, employeeMonthProjects.get(3).hours[20]); - System.assertEquals(2, employeeMonthProjects.get(3).hours[22]); - System.assertEquals(7, employeeMonthProjects.get(3).totalHours); - } + + /** + * CSV Parser Tests + */ @isTest - public static void csvParseControllerTest() { + public static void csvParseControllerTestFullFile() { Integer fteYear = Date.today().year(); integer fteMonth = Date.today().month(); String correctData = ',,,,,,\n\r ' @@ -1004,19 +581,32 @@ public class FTETrackerTest { assertFTEDataRecord(csvUpload.records.values(), 'Other Employee', fteYear, 'FTE Contract 1', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); assertFTEDataRecord(csvUpload.records.values(), 'FTE Employee', fteYear, 'FTE Contract 1', 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14); assertFTEDataRecord(csvUpload.records.values(), 'Yyy Employee', fteYear, 'FTE Contract 1', 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + + List dbTemplates = [SELECT Id, Employee__r.Name, Contract__r.Name, Year__c, + Month_1__c, Month_2__c, Month_3__c, Month_4__c, Month_5__c, Month_6__c, + Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, Month_12__c, + Month_Updated_1__c, Month_Updated_2__c, Month_Updated_3__c, Month_Updated_4__c, Month_Updated_5__c, Month_Updated_6__c, + Month_Updated_7__c, Month_Updated_8__c, Month_Updated_9__c, Month_Updated_10__c, Month_Updated_11__c, Month_Updated_12__c + FROM FTE_Data_Record__c + WHERE Year__c =: fteYear ORDER BY Employee__r.Name]; + System.assertEquals(3, dbTemplates.size()); + + assertFTEDBDataRecord(dbTemplates.get(0), 'FTE Employee', fteYear, 'FTE Contract 1', 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14); + assertFTEDBDataRecord(dbTemplates.get(1), 'Other Employee', fteYear, 'FTE Contract 1', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); + assertFTEDBDataRecord(dbTemplates.get(2), 'Yyy Employee', fteYear, 'FTE Contract 1', 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); } @isTest - public static void shouldUploadAndMoveCSVDataSample1() { + public static void csvParseControllerTestPartialFile() { Integer fteYear = Date.today().year(); integer fteMonth = Date.today().month(); String correctData = ',,,,,,\n\r ' - + 'FTE Contract 1 ,01/' + fteYear + ', 02/' + fteYear + ', 03/' + fteYear + ', 04/' + fteYear + ', 05/' + fteYear + ', 06/' + fteYear + ', 07/' + fteYear - + ', 08/' + fteYear + ', 09/' + fteYear + ', 10/' + fteYear + ', 11/' + fteYear + ', 12/' + fteYear + '\n\r' - + buildDataRow('Other Employee', fteMonth, 5.0) - + buildDataRow('FTE Employee', fteMonth, 7.0) - + buildDataRow('Yyy Employee', fteMonth, 4.0); - + + 'FTE Contract 1 ,01/' + fteYear + ', 02/' + fteYear + ', 03/' + fteYear + ', 04/' + fteYear + '\n\r' + + 'Other Employee,1,,,0\n\r' + + 'Other Employee,5,2,,\n\r' + + 'Yyy Employee,4,4,4,0\n\r' + + 'FTE Employee,3,3,,1\n\r' + + 'Yyy Employee,,0,,2\n\r'; FTECsvUploadController csvUpload = new FTECsvUploadController(); Test.startTest(); @@ -1024,44 +614,142 @@ public class FTETrackerTest { csvUpload.fileName = 'Test file name'; csvUpload.parseCsvFile(); - Test.stopTest(); - for (FTE_Data_Record_Status__c rec : [SELECT Status__c, Status_Message__c, Line_Number__c, Line_Number_Text__c FROM FTE_Data_Record_Status__c]) { - System.debug('Status Error Record : ' + rec); - } - System.assertEquals(0, [SELECT count() FROM FTE_Data_Record_Status__c]); - + System.assertEquals(3, csvUpload.records.size()); + assertFTEDataRecord(csvUpload.records.values(), 'Other Employee', fteYear, 'FTE Contract 1', 6, 2, -1, 0, -2, -2, -2, -2, -2, -2, -2, -2); + assertFTEDataRecord(csvUpload.records.values(), 'FTE Employee', fteYear, 'FTE Contract 1', 3, 3, -1, 1, -2, -2, -2, -2, -2, -2, -2, -2); + assertFTEDataRecord(csvUpload.records.values(), 'Yyy Employee', fteYear, 'FTE Contract 1', 4, 4, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2); + + List dbTemplates = [SELECT Id, Employee__r.Name, Contract__r.Name, Year__c, + Month_1__c, Month_2__c, Month_3__c, Month_4__c, Month_5__c, Month_6__c, + Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, Month_12__c, + Month_Updated_1__c, Month_Updated_2__c, Month_Updated_3__c, Month_Updated_4__c, Month_Updated_5__c, Month_Updated_6__c, + Month_Updated_7__c, Month_Updated_8__c, Month_Updated_9__c, Month_Updated_10__c, Month_Updated_11__c, Month_Updated_12__c + FROM FTE_Data_Record__c + WHERE Year__c =: fteYear ORDER BY Employee__r.Name]; + System.assertEquals(3, dbTemplates.size()); + + assertFTEDBDataRecord(dbTemplates.get(0), 'FTE Employee', fteYear, 'FTE Contract 1', 3, 3, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1); + assertFTEDBDataRecord(dbTemplates.get(1), 'Other Employee', fteYear, 'FTE Contract 1', 6, 2, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1); + assertFTEDBDataRecord(dbTemplates.get(2), 'Yyy Employee', fteYear, 'FTE Contract 1', 4,4, 4, 2, -1, -1, -1, -1, -1, -1, -1, -1); + } + + @isTest + public static void csvParseControllerTestMergeTemplate() { + Integer fteYear = Date.today().year(); + integer fteMonth = Date.today().month(); + Id contractId = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; + Id employeeId1 = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee' LIMIT 1].Id; + Id employeeId2 = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'Yyy Employee' LIMIT 1].Id; + insert new List { + new FTE_Data_Record__c(Year__c = fteYear, Employee__c = employeeId1, Contract__c = contractId, Month_1__c = 3, Month_2__c = -1, Month_3__c = -1, Month_4__c = 0), + new FTE_Data_Record__c(Year__c = fteYear, Employee__c = employeeId2, Contract__c = contractId, Month_1__c = 3, Month_2__c = 4, Month_3__c = 0, Month_4__c = 2) + }; + + String correctData = ',,,,,,\n\r ' + + 'FTE Contract 1 ,01/' + fteYear + ', 02/' + fteYear + ', 03/' + fteYear + ', 04/' + fteYear + '\n\r' + + 'Other Employee,1,,,0\n\r' + + 'Other Employee,5,2,,\n\r' + + 'Yyy Employee,4,4,4,0\n\r' + + 'FTE Employee,3,3,,1\n\r' + + 'Yyy Employee,,0,,2\n\r'; + FTECsvUploadController csvUpload = new FTECsvUploadController(); + Test.startTest(); + csvUpload.fileContent = Blob.valueOf(correctData); + csvUpload.fileName = 'Test file name'; + + csvUpload.parseCsvFile(); + Test.stopTest(); + + System.assertEquals(3, csvUpload.records.size()); + assertFTEDataRecord(csvUpload.records.values(), 'Other Employee', fteYear, 'FTE Contract 1', 6, 2, -1, 0, -2, -2, -2, -2, -2, -2, -2, -2); + assertFTEDataRecord(csvUpload.records.values(), 'FTE Employee', fteYear, 'FTE Contract 1', 3, 3, -1, 1, -2, -2, -2, -2, -2, -2, -2, -2); + assertFTEDataRecord(csvUpload.records.values(), 'Yyy Employee', fteYear, 'FTE Contract 1', 4, 4, 4, 2, -2, -2, -2, -2, -2, -2, -2, -2); + + List dbTemplates = [SELECT Id, Employee__r.Name, Contract__r.Name, Year__c, + Month_1__c, Month_2__c, Month_3__c, Month_4__c, Month_5__c, Month_6__c, + Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, Month_12__c, + Month_Updated_1__c, Month_Updated_2__c, Month_Updated_3__c, Month_Updated_4__c, Month_Updated_5__c, Month_Updated_6__c, + Month_Updated_7__c, Month_Updated_8__c, Month_Updated_9__c, Month_Updated_10__c, Month_Updated_11__c, Month_Updated_12__c + FROM FTE_Data_Record__c + WHERE Year__c =: fteYear ORDER BY Employee__r.Name]; + for (FTE_Data_Record__c templ : dbTemplates) { + System.debug('Template data : ' + templ.Employee__r.Name + ' ' + templ.Year__c + ' ' + templ.Contract__r.Name); + } + System.assertEquals(3, dbTemplates.size()); + + assertFTEDBDataRecord(dbTemplates.get(0), 'FTE Employee', fteYear, 'FTE Contract 1', 3, 3, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1); + assertFTEDBDataRecord(dbTemplates.get(1), 'Other Employee', fteYear, 'FTE Contract 1', 6, 2, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1); + assertFTEDBDataRecord(dbTemplates.get(2), 'Yyy Employee', fteYear, 'FTE Contract 1', 4, 4, 4, 2, -1, -1, -1, -1, -1, -1, -1, -1); + assertTemplateUpdated(dbTemplates.get(0), false, true, false, true, false, false, false, false, false, false, false, false); + assertTemplateUpdated(dbTemplates.get(1), true, true, false, true, false, false, false, false, false, false, false, false); + assertTemplateUpdated(dbTemplates.get(2), true, false, true, false, false, false, false, false, false, false, false, false); + } + + @isTest + public static void shouldUploadAndMoveCSVDataSample1() { + Integer fteYear = Date.today().year(); + integer fteMonth = Date.today().month(); + String correctData = ',,,,,,\n\r ' + + 'FTE Contract 1 ,01/' + fteYear + ', 02/' + fteYear + ', 03/' + fteYear + ', 04/' + fteYear + ', 05/' + fteYear + ', 06/' + fteYear + ', 07/' + fteYear + + ', 08/' + fteYear + ', 09/' + fteYear + ', 10/' + fteYear + ', 11/' + fteYear + ', 12/' + fteYear + '\n\r' + + buildDataRow('Other Employee', fteMonth, 5.0) + + buildDataRow('FTE Employee', fteMonth, 7.0) + + buildDataRow('Yyy Employee', fteMonth, 4.0); + + FTECsvUploadController csvUpload = new FTECsvUploadController(); + + Test.startTest(); + csvUpload.fileContent = Blob.valueOf(correctData); + csvUpload.fileName = 'Test file name'; + + csvUpload.parseCsvFile(); + Database.executeBatch(new FTETimeAllocator(true)); + Test.stopTest(); + + // FTE Employee SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee']; Id contractId = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1'].Id; - FTETimeManager timeManager = new FTETimeManager(employee, fteYear); - timeManager.loadEmployeeTime(); + FTEDataManager timeManager = new FTEDataManager(fteYear, employee.Id); + timeManager.loadEmployeeTime(); + timeManager.loadTemplateTime(); System.assertEquals(56, timeManager.assignedMap.get(contractId).hoursArray[fteMonth - 1]); - timeManager.assignedMap.get(contractId).calculateDays(); + timeManager.assignedMap.get(contractId).calculateDaysAndTotal(); System.assertEquals(7, timeManager.assignedMap.get(contractId).daysArray[fteMonth - 1]); + System.assertEquals(7, timeManager.assignedMap.get(contractId).templateArray[fteMonth - 1]); + assertTemplatesValue(-1, new Set { fteMonth }, timeManager.assignedMap.get(contractId)); + // FTE Employee employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'Other Employee']; - timeManager = new FTETimeManager(employee, fteYear); + timeManager = new FTEDataManager(fteYear, employee.Id); timeManager.loadEmployeeTime(); + timeManager.loadTemplateTime(); System.assertEquals(40, timeManager.assignedMap.get(contractId).hoursArray[fteMonth - 1]); - timeManager.assignedMap.get(contractId).calculateDays(); + timeManager.assignedMap.get(contractId).calculateDaysAndTotal(); System.assertEquals(5, timeManager.assignedMap.get(contractId).daysArray[fteMonth - 1]); + System.assertEquals(5, timeManager.assignedMap.get(contractId).templateArray[fteMonth - 1]); + assertTemplatesValue(-1, new Set { fteMonth }, timeManager.assignedMap.get(contractId)); + // FTE Employee employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'Yyy Employee']; - timeManager = new FTETimeManager(employee, fteYear); + timeManager = new FTEDataManager(fteYear, employee.Id); timeManager.loadEmployeeTime(); + timeManager.loadTemplateTime(); System.assertEquals(32, timeManager.assignedMap.get(contractId).hoursArray[fteMonth - 1]); - timeManager.assignedMap.get(contractId).calculateDays(); + timeManager.assignedMap.get(contractId).calculateDaysAndTotal(); System.assertEquals(4, timeManager.assignedMap.get(contractId).daysArray[fteMonth - 1]); + System.assertEquals(4, timeManager.assignedMap.get(contractId).templateArray[fteMonth - 1]); + assertTemplatesValue(-1, new Set { fteMonth }, timeManager.assignedMap.get(contractId)); } @isTest public static void shouldUploadAndMoveCSVDataSample2() { Integer fteYear = Date.today().year(); - integer fteMonth = Date.today().month(); + Integer fteMonth = Date.today().month(); String correctData = ',,,,,,\n\r ' + 'FTE Contract 1 ,01/' + fteYear + ', 02/' + fteYear + ', 03/' + fteYear + ', 04/' + fteYear + ', 05/' + fteYear + ', 06/' + fteYear + ', 07/' + fteYear + ', 08/' + fteYear + ', 09/' + fteYear + ', 10/' + fteYear + ', 11/' + fteYear + ', 12/' + fteYear + '\n\r' @@ -1076,131 +764,52 @@ public class FTETrackerTest { csvUpload.fileName = 'Test file name'; csvUpload.parseCsvFile(); + Database.executeBatch(new FTETimeAllocator(true)); Test.stopTest(); - for (FTE_Data_Record_Status__c rec : [SELECT Status__c, Status_Message__c, Line_Number__c, Line_Number_Text__c FROM FTE_Data_Record_Status__c]) { - System.debug('Status Error Record : ' + rec); - } - System.assertEquals(0, [SELECT count() FROM FTE_Data_Record_Status__c]); - SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee']; Id contractId = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1'].Id; - FTETimeManager timeManager = new FTETimeManager(employee, fteYear); + FTEDataManager timeManager = new FTEDataManager(fteYear, employee.Id); timeManager.loadEmployeeTime(); + timeManager.loadTemplateTime(); System.assertEquals(8, timeManager.assignedMap.get(contractId).hoursArray[fteMonth - 1]); - timeManager.assignedMap.get(contractId).calculateDays(); + timeManager.assignedMap.get(contractId).calculateDaysAndTotal(); System.assertEquals(1, timeManager.assignedMap.get(contractId).daysArray[fteMonth - 1]); System.assertEquals(64.5, timeManager.unassigned.hoursArray[fteMonth - 1]); - timeManager.unassigned.calculateDays(); + timeManager.unassigned.calculateDaysAndTotal(); System.assertEquals(8, timeManager.unassigned.daysArray[fteMonth - 1]); + assertTemplatesValue(-1, new Set { fteMonth }, timeManager.assignedMap.get(contractId)); employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'Other Employee']; - timeManager = new FTETimeManager(employee, fteYear); + timeManager = new FTEDataManager(fteYear, employee.Id); timeManager.loadEmployeeTime(); + timeManager.loadTemplateTime(); System.assertEquals(8, timeManager.assignedMap.get(contractId).hoursArray[fteMonth - 1]); - timeManager.assignedMap.get(contractId).calculateDays(); + timeManager.assignedMap.get(contractId).calculateDaysAndTotal(); System.assertEquals(1, timeManager.assignedMap.get(contractId).daysArray[fteMonth - 1]); System.assertEquals(41.9, timeManager.unassigned.hoursArray[fteMonth - 1]); - timeManager.unassigned.calculateDays(); + timeManager.unassigned.calculateDaysAndTotal(); System.assertEquals(5.25, timeManager.unassigned.daysArray[fteMonth - 1]); + assertTemplatesValue(-1, new Set { fteMonth }, timeManager.assignedMap.get(contractId)); employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'Yyy Employee']; - timeManager = new FTETimeManager(employee, fteYear); + timeManager = new FTEDataManager(fteYear, employee.Id); timeManager.loadEmployeeTime(); + timeManager.loadTemplateTime(); System.assertEquals(8, timeManager.assignedMap.get(contractId).hoursArray[fteMonth - 1]); - timeManager.assignedMap.get(contractId).calculateDays(); + timeManager.assignedMap.get(contractId).calculateDaysAndTotal(); System.assertEquals(1, timeManager.assignedMap.get(contractId).daysArray[fteMonth - 1]); System.assertEquals(25.1, timeManager.unassigned.hoursArray[fteMonth - 1]); - timeManager.unassigned.calculateDays(); + timeManager.unassigned.calculateDaysAndTotal(); System.assertEquals(3.25, timeManager.unassigned.daysArray[fteMonth - 1]); + assertTemplatesValue(-1, new Set { fteMonth }, timeManager.assignedMap.get(contractId)); } - @isTest - public static void shouldRetunrYearList() { - List years = FTETrackerHelper.getYearsData(); - System.assertEquals(4, years.size()); - Integer currentYear = Date.today().year(); - System.assertEquals(String.valueOf(currentYear + 2), years.get(0).getValue()); - System.assertEquals(String.valueOf(currentYear + 1), years.get(1).getValue()); - System.assertEquals(String.valueOf(currentYear), years.get(2).getValue()); - System.assertEquals(String.valueOf(currentYear - 1), years.get(3).getValue()); - } - @isTest - public static void testTimeManagerEmpl1() { - SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee' LIMIT 1]; - Id contract1Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; - Id contract2Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 2' LIMIT 1].Id; - Id contract3Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 3' LIMIT 1].Id; - Id contract4Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 4' LIMIT 1].Id; - Test.startTest(); - FTETimeManager timeManager = new FTETimeManager(employee, Date.today().year()); - timeManager.loadEmployeeTime(); - System.assertEquals(25.6, timeManager.assignedMap.get(contract1Id).hoursArray[12]); - System.assertEquals(25.6, timeManager.assignedMap.get(contract2Id).hoursArray[12]); - System.assertEquals(10.3, timeManager.assignedMap.get(contract3Id).hoursArray[12]); - System.assertEquals(30.6, timeManager.assignedMap.get(contract4Id).hoursArray[12]); - System.assertEquals(19.3 + 27.6, timeManager.unassigned.hoursArray[12]); - - System.assertEquals(0, [SELECT Id FROM Time_Card__c WHERE Employee__c =: employee.Id AND FTE_Contract__r.FTE_Tracker__c = 'No'].size()); - System.assertEquals(0, [SELECT Id FROM Time_Card__c WHERE Employee__c =: employee.Id AND FTE_Contract__r.FTE_Tracker__c = 'Yes'].size()); - - timeManager.moveTimeToUnassigned(24, Date.today().month(), contract1Id); - System.assertEquals(1, [SELECT Id FROM Time_Card__c WHERE Client__c =: contract1Id AND Employee__c =: employee.Id AND FTE_Contract__r.FTE_Tracker__c = 'No'].size()); - - timeManager.moveTimeToAssigned(8, Date.today().month(), contract3Id); - System.assertEquals(1, [SELECT Id FROM Time_Card__c WHERE FTE_Contract__c =: contract3Id AND Employee__c =: employee.Id AND FTE_Contract__r.FTE_Tracker__c = 'Yes'].size()); - timeManager.moveTimeToAssigned(2, Date.today().month(), contract3Id); - System.assertEquals(1, [SELECT Id FROM Time_Card__c WHERE FTE_Contract__c =: contract3Id AND Employee__c =: employee.Id AND FTE_Contract__r.FTE_Tracker__c = 'Yes'].size()); - - timeManager.moveTimeToUnassigned(5, Date.today().month(), contract3Id); - System.assertEquals(1, [SELECT Id FROM Time_Card__c WHERE FTE_Contract__c =: contract3Id AND Employee__c =: employee.Id AND FTE_Contract__r.FTE_Tracker__c = 'Yes'].size()); - System.assertEquals(1, [SELECT Id FROM Time_Card__c WHERE FTE_Contract__c =: contract3Id AND Employee__c =: employee.Id AND FTE_Contract__r.FTE_Tracker__c = 'Yes' - AND FTE_Hours__c = 5].size()); - Test.stopTest(); - } - - @isTest - public static void testTimeManagerEmpl2() { - SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'Other Employee' LIMIT 1]; - Id contract1Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; - Id contract2Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 2' LIMIT 1].Id; - Id contract3Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 3' LIMIT 1].Id; - Id contract4Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 4' LIMIT 1].Id; - - Test.startTest(); - FTETimeManager timeManager = new FTETimeManager(employee, Date.today().year()); - timeManager.loadEmployeeTime(); - System.assertEquals(28.6 - 5, timeManager.assignedMap.get(contract1Id).hoursArray[12]); - System.assertEquals(null, timeManager.assignedMap.get(contract2Id)); - System.assertEquals(null, timeManager.assignedMap.get(contract3Id)); - System.assertEquals(5 - 2, timeManager.assignedMap.get(contract4Id).hoursArray[12]); - System.assertEquals(19.3 + 5 + 2, timeManager.unassigned.hoursArray[12]); - Test.stopTest(); - } - - @isTest - public static void testTimeManagerEmpl3() { - SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'Yyy Employee' LIMIT 1]; - Id contract1Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; - Id contract2Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 2' LIMIT 1].Id; - Id contract3Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 3' LIMIT 1].Id; - Id contract4Id = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 4' LIMIT 1].Id; - - Test.startTest(); - FTETimeManager timeManager = new FTETimeManager(employee, Date.today().year()); - timeManager.loadEmployeeTime(); - System.assertEquals(19.1 - 8, timeManager.assignedMap.get(contract1Id).hoursArray[12]); - System.assertEquals(16 - 7 + 5, timeManager.assignedMap.get(contract2Id).hoursArray[12]); - System.assertEquals(7 - 5 + 3 + 16, timeManager.assignedMap.get(contract3Id).hoursArray[12]); - System.assertEquals(8 - 3 + 2, timeManager.assignedMap.get(contract4Id).hoursArray[12]); - System.assertEquals(3 + 22 + 8 + 7 - 16 - 2, timeManager.unassigned.hoursArray[12]); - Test.stopTest(); - } /** * Controller tests @@ -1210,8 +819,9 @@ public class FTETrackerTest { Integer currYear = Date.today().year(); List workCards = new List(); for (SFDC_Employee__c empl : [SELECT Id FROM SFDC_Employee__c]) { - workCards.add(new FTE_Work_Card__c(Employee__c = empl.Id, Month_1__c = 1, Month_2__c = 2, Month_3__c = 3, Month_4__c = 4, Month_5__c = 5, Month_6__c = 6, Month_7__c = 7, Month_8__c = 8, - Month_9__c = 9, Month_10__c = 10, Month_11__c = 11, Month_12__c = 12, Total__c = 78, Total_Hours__c = 78 * 8, Year__c = currYear)); + workCards.add(new FTE_Work_Card__c(Employee__c = empl.Id, Month_1__c = 1, Month_2__c = 2, Month_3__c = 3, Month_4__c = 22, Month_5__c = 5, Month_6__c = 6, Month_7__c = 7, Month_8__c = 8, + Month_9__c = 9, Month_10__c = 10, Month_11__c = 11, Month_12__c = 12, Total__c = 78, Total_Hours__c = 78 * 8, Year__c = currYear, + Month_Future_9__c = true, Month_Blocked_4__c = true, Month_Future_5__c = true, Month_Blocked_5__c = true)); } insert workCards; @@ -1283,65 +893,6 @@ public class FTETrackerTest { Test.stopTest(); } - @isTest - public static void testFileCtrl() { - String empId = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee' LIMIT 1].Id; - PageReference pageRef = Page.FTE_Time_Card_View; - pageRef.getParameters().put('employeeId', EncodingUtil.urlDecode(empId, 'UTF-8')); - pageRef.getParameters().put('fteYear', EncodingUtil.urlDecode(String.valueOf(Date.today().year()), 'UTF-8')); - pageRef.getParameters().put('month', EncodingUtil.urlDecode(String.valueOf(Date.today().month()), 'UTF-8')); - Test.setCurrentPage(pageRef); - - Test.startTest(); - FTEFileController fileCtrl = new FTEFileController(); - fileCtrl.loadExportTimeCards(); - System.assertEquals(Date.daysInMonth(Date.today().year(), Date.today().month()), fileCtrl.rowList.size()); - System.assertEquals(5, fileCtrl.employeeMonthProjects.size()); // 4 FTE contracts and 1 overhead sum - System.assertEquals('FTE Contract 1', fileCtrl.employeeMonthProjects.get(0).name); - System.assertEquals(25.6, fileCtrl.employeeMonthProjects.get(0).totalHours); - System.assertEquals('FTE Contract 2', fileCtrl.employeeMonthProjects.get(1).name); - System.assertEquals(25.6, fileCtrl.employeeMonthProjects.get(1).totalHours); - System.assertEquals('FTE Contract 3', fileCtrl.employeeMonthProjects.get(2).name); - System.assertEquals(10.3, fileCtrl.employeeMonthProjects.get(2).totalHours); - System.assertEquals('FTE Contract 4', fileCtrl.employeeMonthProjects.get(3).name); - System.assertEquals(30.6, fileCtrl.employeeMonthProjects.get(3).totalHours); - System.assertEquals('Overhead', fileCtrl.employeeMonthProjects.get(4).name); - System.assertEquals(19.3 + 27.6, fileCtrl.employeeMonthProjects.get(4).totalHours); - Test.stopTest(); - } - - @isTest - public static void testFileCtrlWithDownloadAndWithTags() { - String empId = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'Yyy Employee' LIMIT 1].Id; - PageReference pageRef = Page.FTE_Download_File; - pageRef.getParameters().put('employeeId', EncodingUtil.urlDecode(empId, 'UTF-8')); - pageRef.getParameters().put('fteYear', EncodingUtil.urlDecode(String.valueOf(Date.today().year()), 'UTF-8')); - pageRef.getParameters().put('month', EncodingUtil.urlDecode(String.valueOf(Date.today().month()), 'UTF-8')); - Test.setCurrentPage(pageRef); - - Test.startTest(); - FTEFileController fileCtrl = new FTEFileController(); - System.assertNotEquals(null, fileCtrl.csvFile); - System.assert(String.isNotBlank(fileCtrl.csvFile)); - System.assertEquals('Yyy_Employee_' + (DateTime.newInstance(Date.today().year(), Date.today().month(), 1).format('MMMM')) - + '_' + Date.today().year() + '.csv', fileCtrl.fileName); - - fileCtrl.loadExportTimeCards(); - System.assertEquals(Date.daysInMonth(Date.today().year(), Date.today().month()), fileCtrl.rowList.size()); - System.assertEquals(5, fileCtrl.employeeMonthProjects.size()); // 4 FTE contracts and 1 overhead sum - System.assertEquals('FTE Contract 1', fileCtrl.employeeMonthProjects.get(0).name); - System.assertEquals(19.1 - 8, fileCtrl.employeeMonthProjects.get(0).totalHours); - System.assertEquals('FTE Contract 2', fileCtrl.employeeMonthProjects.get(1).name); - System.assertEquals(16 - 7 + 5, fileCtrl.employeeMonthProjects.get(1).totalHours); - System.assertEquals('FTE Contract 3', fileCtrl.employeeMonthProjects.get(2).name); - System.assertEquals(7 - 5 + 3 + 16, fileCtrl.employeeMonthProjects.get(2).totalHours); - System.assertEquals('FTE Contract 4', fileCtrl.employeeMonthProjects.get(3).name); - System.assertEquals(8 - 3 + 2 , fileCtrl.employeeMonthProjects.get(3).totalHours); - System.assertEquals('Overhead', fileCtrl.employeeMonthProjects.get(4).name); - System.assertEquals(3 + 22 + 8 + 7 - 16 - 2, fileCtrl.employeeMonthProjects.get(4).totalHours); - Test.stopTest(); - } - @isTest public static void testEmployeeCtrl() { String empId = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee' LIMIT 1].Id; @@ -1380,6 +931,461 @@ public class FTETrackerTest { Test.stopTest(); } + @isTest + public static void shouldGenerateEmployeeHoursEmplCtrl() { + Date currentDate = Date.today(); + SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee']; + PageReference pageRef = Page.FTE_Employee_View; + pageRef.getParameters().put('employeeId', String.valueOf(employee.Id)); + Test.setCurrentPage(pageRef); + + Test.startTest(); + FTEEmployeeController controller = new FTEEmployeeController(); + controller.initFteEmployeeView(); + Test.stopTest(); + + System.assertEquals(46.9, controller.fteTimeManager.unassigned.hoursArray[currentDate.month() - 1]); + System.assertEquals(5.75, controller.fteTimeManager.unassigned.daysArray[currentDate.month() - 1]); + System.assertEquals(92.1, controller.totalAssignedDays.hoursArray[currentDate.month() - 1]); + System.assertEquals(11.5, controller.totalAssignedDays.daysArray[currentDate.month() - 1]); + } + + @isTest + public static void shouldMoveHoursToUnassignedEmplCtrl() { + Date currentDate = Date.today(); + addTimeCard([SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id, + [SELECT Id FROM SFDC_Employee__c WHERE Name = 'Other Employee'].Id, + Date.newInstance(currentDate.year(), currentDate.month(), 5), 3.3); + SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee']; + PageReference pageRef = Page.FTE_Employee_View; + pageRef.getParameters().put('employeeId', String.valueOf(employee.Id)); + Test.setCurrentPage(pageRef); + + Test.startTest(); + FTEEmployeeController controller = new FTEEmployeeController(); + controller.initFteEmployeeView(); + controller.employeeMonth = currentDate.month(); + controller.contractId = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 2' LIMIT 1].Id; + controller.fteDays = '3'; + + controller.unassignTime(); + controller.initFteEmployeeView(); + Test.stopTest(); + + System.assertEquals(70.9, controller.fteTimeManager.unassigned.hoursArray[currentDate.month() - 1]); + System.assertEquals(8.75, controller.fteTimeManager.unassigned.daysArray[currentDate.month() - 1]); + System.assertEquals(68.1, controller.totalAssignedDays.hoursArray[currentDate.month() - 1]); + System.assertEquals(8.5, controller.totalAssignedDays.daysArray[currentDate.month() - 1]); + } + + @isTest + public static void shouldMoveHoursFromUnassignedEmplCtrl() { + Date currentDate = Date.today(); + SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee']; + PageReference pageRef = Page.FTE_Employee_View; + pageRef.getParameters().put('employeeId', String.valueOf(employee.Id)); + Test.setCurrentPage(pageRef); + + Test.startTest(); + FTEEmployeeController controller = new FTEEmployeeController(); + controller.initFteEmployeeView(); + controller.employeeMonth = currentDate.month(); + controller.fteDays = '2.5'; + controller.selectedFteContract = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; + + controller.assignTime(); + controller.initFteEmployeeView(); + Test.stopTest(); + + System.assertEquals(26.9, controller.fteTimeManager.unassigned.hoursArray[currentDate.month() - 1]); + System.assertEquals(3.25, controller.fteTimeManager.unassigned.daysArray[currentDate.month() - 1]); + System.assertEquals(112.1, controller.totalAssignedDays.hoursArray[currentDate.month() - 1]); + System.assertEquals(14, controller.totalAssignedDays.daysArray[currentDate.month() - 1]); + } + + @isTest + public static void shouldSetBlockedTemplateEmplCtrl() { + Date currentDate = Date.today(); + SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee']; + PageReference pageRef = Page.FTE_Employee_View; + pageRef.getParameters().put('employeeId', String.valueOf(employee.Id)); + Test.setCurrentPage(pageRef); + + Test.startTest(); + FTEEmployeeController controller = new FTEEmployeeController(); + controller.initFteEmployeeView(); + controller.employeeMonth = currentDate.month(); + controller.fteDays = '6.00'; + controller.contractId = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; + + controller.setThreshold(); + controller.initFteEmployeeView(); + Test.stopTest(); + + System.assertEquals(48, controller.fteTimeManager.assignedMap.get(controller.contractId).hoursArray[currentDate.month() - 1]); + System.assertEquals(24.5, controller.fteTimeManager.unassigned.hoursArray[currentDate.month() - 1]); + System.assertEquals(114.5, controller.totalAssignedDays.hoursArray[currentDate.month() - 1]); + System.assertEquals(14.25, controller.totalAssignedDays.daysArray[currentDate.month() - 1]); + System.assertEquals(6, controller.fteTimeManager.assignedMap.get(controller.contractId).templateArray[currentDate.month() - 1]); + System.assertEquals('fteCell blocked', controller.fteTimeManager.assignedMap.get(controller.contractId).cssStyle[currentDate.month() - 1]); + assertTemplatesValue(-1, new Set { currentDate.month() }, controller.fteTimeManager.assignedMap.get(controller.contractId)); + + List futureTemplates = [SELECT Contract__c, Contract__r.Name, Employee__c, Month_1__c, Month_2__c, Month_3__c, Month_4__c, + Month_5__c, Month_6__c, Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, Month_12__c + FROM FTE_Data_Record__c]; + System.assertEquals(1, futureTemplates.size()); + } + + @isTest + public static void shouldSetFutureTemplateEmplCtrl() { + Date currentDate = Date.today(); + SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee']; + PageReference pageRef = Page.FTE_Employee_View; + pageRef.getParameters().put('employeeId', String.valueOf(employee.Id)); + Test.setCurrentPage(pageRef); + + Test.startTest(); + FTEEmployeeController controller = new FTEEmployeeController(); + controller.initFteEmployeeView(); + controller.employeeMonth = currentDate.month(); + controller.fteDays = '12.00'; + controller.contractId = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; + + controller.setThreshold(); + controller.initFteEmployeeView(); + Test.stopTest(); + + System.assertEquals(72.5, controller.fteTimeManager.assignedMap.get(controller.contractId).hoursArray[currentDate.month() - 1]); // no 96 hours contains orginal time for contracts + System.assertEquals(12, controller.fteTimeManager.assignedMap.get(controller.contractId).daysArray[currentDate.month() - 1]); // no 96 hours contains orginal time for contracts + System.assertEquals(0, controller.fteTimeManager.unassigned.hoursArray[currentDate.month() - 1]); + // in merged records like totals and in hours we have merged data with templates, + // we don't do this in other hours array like unassigned assignedMap and unassignedMap because we are using them for calculations when moving time + System.assertEquals(162.5, controller.totalAssignedDays.hoursArray[currentDate.month() - 1]); + System.assertEquals(20.25, controller.totalAssignedDays.daysArray[currentDate.month() - 1]); + System.assertEquals(12, controller.fteTimeManager.assignedMap.get(controller.contractId).templateArray[currentDate.month() - 1]); + System.assertEquals('fteCell future', controller.fteTimeManager.assignedMap.get(controller.contractId).cssStyle[currentDate.month() - 1]); + assertTemplatesValue(-1, new Set { currentDate.month() }, controller.fteTimeManager.assignedMap.get(controller.contractId)); + + List futureTemplates = [SELECT Contract__c, Contract__r.Name, Employee__c, Month_1__c, Month_2__c, Month_3__c, Month_4__c, + Month_5__c, Month_6__c, Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, Month_12__c + FROM FTE_Data_Record__c]; + System.assertEquals(1, futureTemplates.size()); + } + + @isTest + public static void shouldUpdateTemplateEmplCtrl() { + Date currentDate = Date.today(); + SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee']; + Id testContract = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; + FTE_Data_Record__c newRecord = new FTE_Data_Record__c(Employee__c = employee.Id, Year__c = currentDate.year(), Contract__c = testContract); + SObject sObjRec = (SObject) newRecord; + sObjRec.put(FTETrackerHelper.getFieldName(currentDate.month()), 6); + insert newRecord; + + PageReference pageRef = Page.FTE_Employee_View; + pageRef.getParameters().put('employeeId', String.valueOf(employee.Id)); + Test.setCurrentPage(pageRef); + + Test.startTest(); + FTEEmployeeController controller = new FTEEmployeeController(); + controller.initFteEmployeeView(); + controller.employeeMonth = currentDate.month(); + controller.fteDays = '12.00'; + controller.contractId = testContract; + + controller.setThreshold(); + controller.initFteEmployeeView(); + Test.stopTest(); + + System.assertEquals(72.5, controller.fteTimeManager.assignedMap.get(controller.contractId).hoursArray[currentDate.month() - 1]); // no 96 hours contains orginal time for contracts + System.assertEquals(12, controller.fteTimeManager.assignedMap.get(controller.contractId).daysArray[currentDate.month() - 1]); // no 96 hours contains orginal time for contracts + System.assertEquals(0, controller.fteTimeManager.unassigned.hoursArray[currentDate.month() - 1]); + // in merged records like totals and in hours we have merged data with templates, + // we don't do this in other hours array like unassigned assignedMap and unassignedMap because we are using them for calculations when moving time + System.assertEquals(162.5, controller.totalAssignedDays.hoursArray[currentDate.month() - 1]); + System.assertEquals(20.25, controller.totalAssignedDays.daysArray[currentDate.month() - 1]); + System.assertEquals(12, controller.fteTimeManager.assignedMap.get(controller.contractId).templateArray[currentDate.month() - 1]); + System.assertEquals('fteCell future', controller.fteTimeManager.assignedMap.get(controller.contractId).cssStyle[currentDate.month() - 1]); + assertTemplatesValue(-1, new Set { currentDate.month() }, controller.fteTimeManager.assignedMap.get(controller.contractId)); + + List futureTemplates = [SELECT Id, Contract__c, Contract__r.Name, Employee__c, Month_1__c, Month_2__c, Month_3__c, Month_4__c, + Month_5__c, Month_6__c, Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, Month_12__c + FROM FTE_Data_Record__c]; + System.assertEquals(1, futureTemplates.size()); + System.assertEquals(newRecord.Id, futureTemplates.get(0).Id); + } + + @isTest + public static void shouldSetZeroInTemplateEmplCtrl() { + Date currentDate = Date.today(); + SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee']; + PageReference pageRef = Page.FTE_Employee_View; + pageRef.getParameters().put('employeeId', String.valueOf(employee.Id)); + Test.setCurrentPage(pageRef); + + Test.startTest(); + FTEEmployeeController controller = new FTEEmployeeController(); + controller.initFteEmployeeView(); + controller.employeeMonth = currentDate.month(); + controller.fteDays = '0.00'; + controller.contractId = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; + + controller.setThreshold(); + controller.initFteEmployeeView(); + Test.stopTest(); + + System.assertEquals(0, controller.fteTimeManager.assignedMap.get(controller.contractId).hoursArray[currentDate.month() - 1]); + System.assertEquals(72.5, controller.fteTimeManager.unassigned.hoursArray[currentDate.month() - 1]); + System.assertEquals(66.5, controller.totalAssignedDays.hoursArray[currentDate.month() - 1]); + System.assertEquals(8.25, controller.totalAssignedDays.daysArray[currentDate.month() - 1]); + System.assertEquals(0, controller.fteTimeManager.assignedMap.get(controller.contractId).templateArray[currentDate.month() - 1]); + System.assertEquals('fteCell blocked', controller.fteTimeManager.assignedMap.get(controller.contractId).cssStyle[currentDate.month() - 1]); + assertTemplatesValue(-1, new Set { currentDate.month() }, controller.fteTimeManager.assignedMap.get(controller.contractId)); + + List futureTemplates = [SELECT Contract__c, Contract__r.Name, Employee__c, Month_1__c, Month_2__c, Month_3__c, Month_4__c, + Month_5__c, Month_6__c, Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, Month_12__c + FROM FTE_Data_Record__c]; + System.assertEquals(1, futureTemplates.size()); + } + + @isTest + public static void shouldResetTemplateEmplCtrl() { + Date currentDate = Date.today(); + SFDC_Employee__c employee = [SELECT Id FROM SFDC_Employee__c WHERE Name = 'FTE Employee']; + Id testContract = [SELECT Id FROM DContract__c WHERE Name = 'FTE Contract 1' LIMIT 1].Id; + FTE_Data_Record__c newRecord = new FTE_Data_Record__c(Employee__c = employee.Id, Year__c = currentDate.year(), Contract__c = testContract); + SObject sObjRec = (SObject) newRecord; + sObjRec.put(FTETrackerHelper.getFieldName(currentDate.month()), 6); + insert newRecord; + + PageReference pageRef = Page.FTE_Employee_View; + pageRef.getParameters().put('employeeId', String.valueOf(employee.Id)); + Test.setCurrentPage(pageRef); + + Test.startTest(); + FTEEmployeeController controller = new FTEEmployeeController(); + controller.initFteEmployeeView(); + controller.employeeMonth = currentDate.month(); + controller.fteDays = ''; + controller.contractId = testContract; + + controller.setThreshold(); + controller.initFteEmployeeView(); + Test.stopTest(); + + List futureTemplates = [SELECT Id, Contract__c, Contract__r.Name, Employee__c, Month_1__c, Month_2__c, Month_3__c, Month_4__c, + Month_5__c, Month_6__c, Month_7__c, Month_8__c, Month_9__c, Month_10__c, Month_11__c, Month_12__c + FROM FTE_Data_Record__c]; + System.assertEquals(1, futureTemplates.size()); + System.assertEquals(newRecord.Id, futureTemplates.get(0).Id); + System.assertEquals(-1, (Decimal) ((SObject) futureTemplates.get(0)).get(FTETrackerHelper.getFieldName(currentDate.month()))); + } + + + + + /** + * Utils tests + */ + @isTest + public static void shouldRetunrYearList() { + List years = FTETrackerHelper.getYearsData(); + System.assertEquals(4, years.size()); + Integer currentYear = Date.today().year(); + System.assertEquals(String.valueOf(currentYear + 2), years.get(0).getValue()); + System.assertEquals(String.valueOf(currentYear + 1), years.get(1).getValue()); + System.assertEquals(String.valueOf(currentYear), years.get(2).getValue()); + System.assertEquals(String.valueOf(currentYear - 1), years.get(3).getValue()); + } + + @isTest + public static void shouldBuildCorrectFieldNames() { + System.assertEquals('Month_Updated_4__c', FTETrackerHelper.getFieldUpdatedName(4)); + System.assertEquals('Month_Updated_11__c', FTETrackerHelper.getFieldUpdatedName(11)); + System.assertEquals('Month_Blocked_4__c', FTETrackerHelper.getFieldTemplateBlockedName(4)); + System.assertEquals('Month_Blocked_7__c', FTETrackerHelper.getFieldTemplateBlockedName(7)); + System.assertEquals('Month_Future_9__c', FTETrackerHelper.getFieldTemplateFutureName(9)); + System.assertEquals('Month_Future_7__c', FTETrackerHelper.getFieldTemplateFutureName(7)); + System.assertEquals('Month_6__c', FTETrackerHelper.getFieldName(6)); + System.assertEquals('Month_10__c', FTETrackerHelper.getFieldName(10)); + } + + @isTest + public static void shouldRoundHoursToDays() { + System.assertEquals(0.25, FTETrackerHelper.roundtoDays(1)); + System.assertEquals(0.25, FTETrackerHelper.roundtoDays(2)); + System.assertEquals(0.5, FTETrackerHelper.roundtoDays(3)); + System.assertEquals(0.5, FTETrackerHelper.roundtoDays(4)); + System.assertEquals(0.75, FTETrackerHelper.roundtoDays(5)); + System.assertEquals(0.75, FTETrackerHelper.roundtoDays(6)); + System.assertEquals(1, FTETrackerHelper.roundtoDays(7)); + System.assertEquals(1, FTETrackerHelper.roundtoDays(8)); + System.assertEquals(1.25, FTETrackerHelper.roundtoDays(9)); + System.assertEquals(1.25, FTETrackerHelper.roundtoDays(10)); + System.assertEquals(1.5, FTETrackerHelper.roundtoDays(11)); + System.assertEquals(1.5, FTETrackerHelper.roundtoDays(12)); + System.assertEquals(1.75, FTETrackerHelper.roundtoDays(13)); + System.assertEquals(1.75, FTETrackerHelper.roundtoDays(14)); + System.assertEquals(0.25, FTETrackerHelper.roundtoDays(1.5)); + System.assertEquals(0.25, FTETrackerHelper.roundtoDays(2.5)); + System.assertEquals(0.5, FTETrackerHelper.roundtoDays(3.5)); + System.assertEquals(0.5, FTETrackerHelper.roundtoDays(4.5)); + System.assertEquals(0.75, FTETrackerHelper.roundtoDays(5.5)); + System.assertEquals(0.75, FTETrackerHelper.roundtoDays(6.5)); + } + + @isTest + public static void testEmployeeDataWrappers() { + List employees = [SELECT Id, Name FROM SFDC_Employee__c WHERE Employee_Status__c = 'Active' ORDER BY Name]; + Id fteEmployee = employees.get(0).Id; + Id otherEmployee = employees.get(1).Id; + Id yyyEmployee = employees.get(2).Id; + + Integer currentYear = Date.today().year(); + Integer pYear = currentYear - 1; + Integer nYear = currentYear + 1; + + Set emplWrappers = new Set(); + emplWrappers.add(new FTEEmployeeWrapper(fteEmployee, currentYear)); + emplWrappers.add(new FTEEmployeeWrapper(otherEmployee, currentYear)); + emplWrappers.add(new FTEEmployeeWrapper(fteEmployee, pYear)); + emplWrappers.add(new FTEEmployeeWrapper(fteEmployee, pYear)); + emplWrappers.add(new FTEEmployeeWrapper(otherEmployee, currentYear)); + emplWrappers.add(new FTEEmployeeWrapper(fteEmployee, nYear)); + emplWrappers.add(new FTEEmployeeWrapper(fteEmployee, currentYear)); + emplWrappers.add(new FTEEmployeeWrapper(fteEmployee, nYear)); + + System.assertEquals(4, emplWrappers.size()); + + Set emplMonthWrappers = new Set(); + emplMonthWrappers.add(new FTEEmployeeMonthWrapper(fteEmployee, 1, currentYear)); + emplMonthWrappers.add(new FTEEmployeeMonthWrapper(otherEmployee, 1, currentYear)); + emplMonthWrappers.add(new FTEEmployeeMonthWrapper(fteEmployee, 1, pYear)); + emplMonthWrappers.add(new FTEEmployeeMonthWrapper(fteEmployee, 1, pYear)); + emplMonthWrappers.add(new FTEEmployeeMonthWrapper(otherEmployee, 1, currentYear)); + emplMonthWrappers.add(new FTEEmployeeMonthWrapper(fteEmployee, 1, nYear)); + emplMonthWrappers.add(new FTEEmployeeMonthWrapper(fteEmployee, 1, currentYear)); + emplMonthWrappers.add(new FTEEmployeeMonthWrapper(fteEmployee, 1, nYear)); + emplMonthWrappers.add(new FTEEmployeeMonthWrapper(fteEmployee, 7, nYear)); + emplMonthWrappers.add(new FTEEmployeeMonthWrapper(otherEmployee, 2, nYear)); + emplMonthWrappers.add(new FTEEmployeeMonthWrapper(fteEmployee, 3, nYear)); + + System.assertEquals(7, emplMonthWrappers.size()); + List sortedList = new List(); + sortedList.addAll(emplMonthWrappers); + sortedList.sort(); + + System.assertEquals(7, sortedList.size()); + System.assertEquals(sortedList.get(0).getEmployeeId(), sortedList.get(1).getEmployeeId()); + System.assertEquals(sortedList.get(5).getEmployeeId(), sortedList.get(6).getEmployeeId()); + } + + @isTest + public static void testEmployeeTimeDays() { + FTEEmployeeTime emplTime = new FTEEmployeeTime(null, null); + for (Integer i = 0; i < 12; i++) { + emplTime.hoursArray[i] = (i + 1) * 2; + } + emplTime.templateArray[4] = 2; + emplTime.templateArray[5] = 3; + emplTime.calculateDaysAndTotal(); + + System.assert(!emplTime.merged); + System.assertEquals(0.25, emplTime.daysArray[0]); + System.assertEquals(0.5, emplTime.daysArray[1]); + System.assertEquals(0.75, emplTime.daysArray[2]); + System.assertEquals(1, emplTime.daysArray[3]); + System.assertEquals(2, emplTime.daysArray[4]); + System.assertEquals(3, emplTime.daysArray[5]); + } + + @isTest + public static void testEmployeeTimeMerge() { + FTEEmployeeTime emplTime1 = new FTEEmployeeTime(null, null); + FTEEmployeeTime emplTime2 = new FTEEmployeeTime(null, null); + FTEEmployeeTime emplTime3 = new FTEEmployeeTime(null, null); + for (Integer i = 0; i < 12; i++) { + emplTime1.hoursArray[i] = i + 1; + emplTime2.hoursArray[i] = i + 3; + emplTime3.hoursArray[i] = i + 2; + } + + emplTime1.templateArray[4] = 2; + emplTime3.templateArray[4] = 3; + emplTime3.templateArray[1] = 4; + + FTEEmployeeTime mergedData = new FTEEmployeeTime(null, null); + mergedData.mergeEmployeeTime(emplTime1); + System.assert(mergedData.merged); + System.assertEquals(1, mergedData.hoursArray[0]); + System.assertEquals(2, mergedData.hoursArray[1]); + System.assertEquals(3, mergedData.hoursArray[2]); + System.assertEquals(4, mergedData.hoursArray[3]); + System.assertEquals(16, mergedData.hoursArray[4]); + System.assertEquals(-1, mergedData.templateArray[0]); + System.assertEquals(-1, mergedData.templateArray[1]); + System.assertEquals(-1, mergedData.templateArray[2]); + System.assertEquals(-1, mergedData.templateArray[3]); + System.assertEquals(16, mergedData.templateArray[4]); + + mergedData.mergeEmployeeTime(emplTime2); + System.assertEquals(1 + 3, mergedData.hoursArray[0]); + System.assertEquals(2 + 4, mergedData.hoursArray[1]); + System.assertEquals(3 + 5, mergedData.hoursArray[2]); + System.assertEquals(4 + 6, mergedData.hoursArray[3]); + System.assertEquals(16 + 7, mergedData.hoursArray[4]); + System.assertEquals(-1, mergedData.templateArray[0]); + System.assertEquals(-1, mergedData.templateArray[1]); + System.assertEquals(-1, mergedData.templateArray[2]); + System.assertEquals(-1, mergedData.templateArray[3]); + System.assertEquals(16 + 7, mergedData.templateArray[4]); + + mergedData.mergeEmployeeTime(emplTime3); + System.assertEquals(1 + 3 + 2, mergedData.hoursArray[0]); + System.assertEquals(2 + 4 + 32, mergedData.hoursArray[1]); + System.assertEquals(3 + 5 + 4, mergedData.hoursArray[2]); + System.assertEquals(4 + 6 + 5, mergedData.hoursArray[3]); + System.assertEquals(16 + 7 + 24, mergedData.hoursArray[4]); + System.assertEquals(-1, mergedData.templateArray[0]); + System.assertEquals(2 + 4 + 32, mergedData.templateArray[1]); + System.assertEquals(-1, mergedData.templateArray[2]); + System.assertEquals(-1, mergedData.templateArray[3]); + System.assertEquals(16 + 7 + 24, mergedData.templateArray[4]); + + mergedData.calculateDaysAndTotal(); + System.assertEquals(0.75, mergedData.daysArray[0]); + System.assertEquals(4.75, mergedData.daysArray[1]); + System.assertEquals(1.5, mergedData.daysArray[2]); + System.assertEquals(2, mergedData.daysArray[3]); + System.assertEquals(6, mergedData.daysArray[4]); + } + + + + + /** + * Tests helper methods + */ + private static void assertTemplateUpdated(FTE_Data_Record__c template) { + assertTemplateUpdated(template, true, true, true, true, true, true, true, true, true, true, true, true); + } + + private static void assertTemplateUpdated(FTE_Data_Record__c template, Boolean m1, Boolean m2, Boolean m3, Boolean m4, Boolean m5, + Boolean m6, Boolean m7, Boolean m8, Boolean m9, Boolean m10, Boolean m11, Boolean m12) { + System.assertEquals(m1, template.Month_Updated_1__c); + System.assertEquals(m2, template.Month_Updated_2__c); + System.assertEquals(m3, template.Month_Updated_3__c); + System.assertEquals(m4, template.Month_Updated_4__c); + System.assertEquals(m5, template.Month_Updated_5__c); + System.assertEquals(m6, template.Month_Updated_6__c); + System.assertEquals(m7, template.Month_Updated_7__c); + System.assertEquals(m8, template.Month_Updated_8__c); + System.assertEquals(m9, template.Month_Updated_9__c); + System.assertEquals(m10, template.Month_Updated_10__c); + System.assertEquals(m11, template.Month_Updated_11__c); + System.assertEquals(m12, template.Month_Updated_12__c); + } + private static void assertFTEDataRecord(List elements, String emplName, Integer fteYear, String contractName, Decimal m1, Decimal m2, Decimal m3, Decimal m4, Decimal m5, Decimal m6, Decimal m7, Decimal m8, Decimal m9, Decimal m10, Decimal m11, Decimal m12) { @@ -1410,11 +1416,39 @@ public class FTETrackerTest { System.assertEquals(m12, rec.getMonthTime(12)); } + private static void assertFTEDBDataRecord(FTE_Data_Record__c rec, String emplName, Integer fteYear, String contractName, + Decimal m1, Decimal m2, Decimal m3, Decimal m4, Decimal m5, Decimal m6, + Decimal m7, Decimal m8, Decimal m9, Decimal m10, Decimal m11, Decimal m12) { + System.assertEquals(fteYear, rec.Year__c); + System.assertEquals(emplName, rec.Employee__r.Name); + System.assertEquals(contractName, rec.Contract__r.Name); + System.assertEquals(m1, rec.Month_1__c); + System.assertEquals(m2, rec.Month_2__c); + System.assertEquals(m3, rec.Month_3__c); + System.assertEquals(m4, rec.Month_4__c); + System.assertEquals(m5, rec.Month_5__c); + System.assertEquals(m6, rec.Month_6__c); + System.assertEquals(m7, rec.Month_7__c); + System.assertEquals(m8, rec.Month_8__c); + System.assertEquals(m9, rec.Month_9__c); + System.assertEquals(m10, rec.Month_10__c); + System.assertEquals(m11, rec.Month_11__c); + System.assertEquals(m12, rec.Month_12__c); + } + + private static void assertTemplatesValue(Decimal expectedValue, Set monthsToSkip, FTEEmployeeTime emplTime) { + for (Integer month = 1; month <= 12; month++) { + if (!monthsToSkip.contains(month)) { + System.assertEquals(expectedValue, emplTime.templateArray[month -1]); + } + } + } + private static String buildDataRow(String employeeName, Integer month, Decimal value) { String hoursRow = ''; for (Integer i = 1; i <= 12; i++) { if (i != month) { - hoursRow += ',' + ' 0 '; + hoursRow += ',' + ' '; } else { hoursRow += ',' + value; } diff --git a/src/classes/FTETriggerHelper.cls b/src/classes/FTETriggerHelper.cls new file mode 100644 index 00000000..56d1fd4a --- /dev/null +++ b/src/classes/FTETriggerHelper.cls @@ -0,0 +1,69 @@ +/** + * Helper class to cache FTE Templates and update month flags. + */ +public class FTETriggerHelper { + + public static void processTemplates(List timeCards) { + // we need use maps because in trigger we also calculate time card salary, we don't want exceed limits like 2000 charachters per SOQL query, 200 queries and others + // It is complicated but we want make synchronization error prone + Integer yearMin = Date.today().year(); + Integer yearMax = yearMin; + Set employeeSet = new Set (); + + for (Time_Card__c tc : timeCards) { + employeeSet.add(tc.Employee__c); + Integer tcYear = tc.Date__c.year(); + if (tcYear > yearMax) { + yearMax = tcYear; + } else if (tcYear < yearMin) { + yearMin = tcYear; + } + } + + Map> templatesMapping = new Map>(); + List toUpdate = new List(); + Set fteContracts = new Set(); + for (FTE_Data_Record__c emplTemplate : [SELECT Id, Year__c, Employee__c, Contract__c, Month_Updated_1__c, Month_Updated_2__c, Month_Updated_3__c, Month_Updated_4__c, Month_Updated_5__c, + Month_Updated_6__c, Month_Updated_7__c, Month_Updated_8__c, Month_Updated_9__c, Month_Updated_10__c, Month_Updated_11__c, Month_Updated_12__c + FROM FTE_Data_Record__c WHERE Contract__r.FTE_Tracker__c = 'Yes' AND Year__c >=: yearMin AND Year__c <=: yearMax ORDER BY Year__c DESC]) { + if (templatesMapping.containsKey(emplTemplate.Employee__c)) { + templatesMapping.get(emplTemplate.Employee__c).add(emplTemplate); + } else { + templatesMapping.put(emplTemplate.Employee__c, new List { emplTemplate }); + } + fteContracts.add(emplTemplate.Contract__c); + toUpdate.add(emplTemplate); + } + + for (Time_Card__c tc : timeCards) { + if (templatesMapping.containsKey(tc.Employee__c)) { // employee has templates + Boolean updated = false; + FTE_Data_Record__c templateTmp = null; + List templates = templatesMapping.get(tc.Employee__c); + if (fteContracts.contains(tc.Client__c)) { // contract is templated fte + for (FTE_Data_Record__c template : templates) { + if (template.Contract__c == tc.Client__c && tc.Date__c.year() == template.Year__c) { + markMonthToUpdate(template, tc.Date__c.month()); + updated = true; + } else if (templateTmp == null && tc.Date__c.year() == template.Year__c) { + templateTmp = template; + } + } + } + + if (updated == false && templateTmp != null) { // we want mark month when unassigned time was logged, we want trigger template for allocator + markMonthToUpdate(templateTmp, tc.Date__c.month()); + } + } + } + + if (toUpdate.size() > 0) { + update toUpdate; + } + } + + private static void markMonthToUpdate(FTE_Data_Record__c template, Integer month) { + Sobject sobj = (SObject) template; + sobj.put(FTETrackerHelper.getFieldUpdatedName(month), true); + } +} \ No newline at end of file diff --git a/src/classes/FTETriggerHelper.cls-meta.xml b/src/classes/FTETriggerHelper.cls-meta.xml new file mode 100644 index 00000000..cbddff8c --- /dev/null +++ b/src/classes/FTETriggerHelper.cls-meta.xml @@ -0,0 +1,5 @@ + + + 38.0 + Active + diff --git a/src/classes/FTEUpdateTagsBatch.cls b/src/classes/FTEUpdateTagsBatch.cls index cbc68efe..924dc305 100644 --- a/src/classes/FTEUpdateTagsBatch.cls +++ b/src/classes/FTEUpdateTagsBatch.cls @@ -51,7 +51,7 @@ public without sharing class FTEUpdateTagsBatch implements Database.Batchable= 0) { // we don't want add (-1) just skip it if employee data was duplicated in uploaded CSV + if (this.timeTable[month - 1] == -1) { + value += 1; + } this.timeTable[month - 1] = this.timeTable[month - 1] + value; } } @@ -48,11 +51,25 @@ public class FTEUploadData { return this.fteYear; } - public FTE_Data_Record__c buildDBRec() { - return new FTE_Data_Record__c(Month_1__c = this.timeTable[0], Month_2__c = this.timeTable[1], Month_3__c = this.timeTable[2], - Month_4__c = this.timeTable[3], Month_5__c = this.timeTable[4], Month_6__c = this.timeTable[5], - Month_7__c = this.timeTable[6],Month_8__c = this.timeTable[7], Month_9__c = this.timeTable[8], - Month_10__c = this.timeTable[9], Month_11__c = this.timeTable[10], Month_12__c = this.timeTable[11], - Year__c = this.fteYear, Contract__c = this.contractId, Employee__c = this.employeeId, Line_Number__c = 1); + public FTE_Data_Record__c mergeData(FTE_Data_Record__c rec) { + if (rec == null) { + rec = new FTE_Data_Record__c(Year__c = this.fteYear, Contract__c = this.contractId, Employee__c = this.employeeId); + } + + SObject recSObj = (SObject) rec; + for (Integer month = 1; month <= 12; month++) { + Decimal oldValue = null; + if (rec.Id != null) { + oldValue = (Decimal) recSObj.get(FTETrackerHelper.getFieldName(month)); + } + System.debug('Month merge : old : ' + oldValue + ' new ' + this.timeTable[month - 1]); + if (this.timeTable[month - 1] > -2 && ((oldValue == null && this.timeTable[month - 1] != -1) || (oldValue != null && oldValue != this.timeTable[month - 1]))) { // -2 means that nothing was uploaded for that month + System.debug('Month merge set true'); + recSObj.put(FTETrackerHelper.getFieldName(month), this.timeTable[month - 1]); + recSObj.put(FTETrackerHelper.getFieldUpdatedName(month), true); + } + } + + return (FTE_Data_Record__c) recSObj; } } \ No newline at end of file diff --git a/src/classes/TimeCardCaseUpdateBatch.cls b/src/classes/TimeCardCaseUpdateBatch.cls index 993cd6d0..56fa48bb 100644 --- a/src/classes/TimeCardCaseUpdateBatch.cls +++ b/src/classes/TimeCardCaseUpdateBatch.cls @@ -36,9 +36,10 @@ public class TimeCardCaseUpdateBatch implements Database.Batchable, String dbCaseTitle = fbCase.caseId + ': ' + fbCase.title; Integer clientFBId = Integer.valueOf(fbCase.client); - List timeCardsToUpdate = [SELECT Id, Area__c, Case__c, Project__c, Client__c FROM Time_Card__c WHERE Case_Number__c =: fbCase.caseId AND FTE_only__c = false - AND (Area__c !=: fbCase.area OR Case__c !=: dbCaseTitle OR Project__c !=: fbCase.project - OR Client__r.FB_Id__c !=: clientFBId)]; + List timeCardsToUpdate = [SELECT Id, Area__c, Case__c, Project__c, Client__c + FROM Time_Card__c WHERE Case_Number__c =: fbCase.caseId AND FTE_only__c = false + AND (Area__c !=: fbCase.area OR Case__c !=: dbCaseTitle OR Project__c !=: fbCase.project OR Client__r.FB_Id__c !=: clientFBId) + ORDER BY Employee__c]; List contracts = [SELECT Id, Name FROM DContract__c WHERE FB_Id__c =: clientFBId]; diff --git a/src/classes/TimeCardTriggerController.cls b/src/classes/TimeCardTriggerController.cls index 1fdd0f74..5cf0ade5 100644 --- a/src/classes/TimeCardTriggerController.cls +++ b/src/classes/TimeCardTriggerController.cls @@ -28,6 +28,8 @@ public class TimeCardTriggerController { if (tcToUpdate.size() > 0) { update tcToUpdate; } + + FTETriggerHelper.processTemplates(newTimeCards); } public static void handleAfterUpdate(List updatedTimeCards, Map beforeUpdateTimeCards) { @@ -37,6 +39,7 @@ public class TimeCardTriggerController { List tags = new List(); List timeCardsToUpdate = new List(); + List fteTimeCards = new List(); Set contractsIds = new Set(); for (Time_Card__c tc : updatedTimeCards) { @@ -46,6 +49,8 @@ public class TimeCardTriggerController { contractsIds.add(oldTC.Client__c); contractsIds.add(tc.Client__c); + fteTimeCards.add(tc); + Time_Card__c tcToUpdate = null; if (tc.FTE_Contract__c != null) { @@ -67,7 +72,7 @@ public class TimeCardTriggerController { if (tags.size() > 0) { insert tags; } - if (timeCardsToUpdate.size() > 0) { + if (timeCardsToUpdate.size() > 0) { // new contract we must recalculate time card billing rate Map billingRateMap = new Map(); TimeCardCalculatorHelper timeCardHelper = new TimeCardCalculatorHelper(); for (DContract__c client : [SELECT Id, Project_Billing_Rate__c FROM DContract__c WHERE Id IN: contractsIds]) { @@ -85,6 +90,10 @@ public class TimeCardTriggerController { if (contractsIds.size() > 0) { TimeCardCalculatorUtils.markContractsToRefresh(contractsIds); } + + if (fteTimeCards.size() > 0) { + FTETriggerHelper.processTemplates(fteTimeCards); + } } public static void handleAfterDelete(List deletedTimeCards) { @@ -105,5 +114,7 @@ public class TimeCardTriggerController { insert tags; } TimeCardCalculatorUtils.markContractsToRefresh(contractsIds); + + FTETriggerHelper.processTemplates(deletedTimeCards); } } \ No newline at end of file diff --git a/src/pages/FTE_CSV_Upload.page b/src/pages/FTE_CSV_Upload.page index 07ff1121..5638cfdf 100644 --- a/src/pages/FTE_CSV_Upload.page +++ b/src/pages/FTE_CSV_Upload.page @@ -46,35 +46,6 @@ -
- - - - - - - - - - - - -
Page: - - -    - - - - Records per page:   - - - - - - -
-
diff --git a/src/pages/FTE_Employee_List_View.page b/src/pages/FTE_Employee_List_View.page index dc5d485d..6427feba 100644 --- a/src/pages/FTE_Employee_List_View.page +++ b/src/pages/FTE_Employee_List_View.page @@ -3,11 +3,23 @@ .fteProjectCell { cursor: pointer; } + .fteCell { + cursor: pointer; + } + .highlight td { + background: #5fa6d4 !important; + } .fteProjectCell:hover { - background: #1797C0 !important; + background: #5fa6d4 !important; } .overbilled { - color: red !important; + color: #e50000 !important; + } + .future { + background: #87bcdf; + } + .blocked { + background: #ccdae5; } .fteTable { margin-top: 10px; @@ -21,6 +33,22 @@ margin-right: 10px; height: 22px !important; } + .tLegend { + display: inline-block; + } + .tLegendElement { + display: flex; + margin-bottom: 5px; + } + .tLegendColor { + width: 90px; + height: 19px; + padding: 0px; + margin: 0px; + } + .boldText { + font-weight: bold; + } @@ -72,19 +100,19 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + @@ -119,6 +147,12 @@ +
+
+
Table legend :
+
  - future time allocation
+
  - blocked time
+
diff --git a/src/pages/FTE_Employee_View.page b/src/pages/FTE_Employee_View.page index b9c9ce15..14fe24f4 100644 --- a/src/pages/FTE_Employee_View.page +++ b/src/pages/FTE_Employee_View.page @@ -4,16 +4,22 @@ cursor: pointer; } .fteCell:hover { - background: #1797C0 !important; + background: #5fa6d4 !important; } .fteProjectCell { cursor: pointer; } .fteProjectCell:hover { - background: #1797C0 !important; + background: #5fa6d4 !important; } .overbilled { - color: red !important; + color: #e50000 !important; + } + .future { + background: #87bcdf !important; + } + .blocked { + background: #ccdae5 !important; } .topTotal { border-top-width: 3px !important; @@ -33,6 +39,19 @@ padding-left:5px; margin-top: 10px; } + .tLegend { + display: inline-block; + } + .tLegendElement { + display: flex; + margin-bottom: 5px; + } + .tLegendColor { + width: 90px; + height: 19px; + padding: 0px; + margin: 0px; + } .boldText { font-weight: bold; } @@ -43,6 +62,7 @@ line-height: 1.5em; padding: 10px 5px 30px 5px !important; min-width: 300px; + max-height: 400px; } .hoursModal label, input, span, h1, select { display:block; @@ -79,24 +99,54 @@ - + - + + + + + + FTE Tracker is currently calculating Empolyee Work Cards {!workCardJobStatus.jobItemsProcessed}/{!workCardJobStatus.totalJobItems} +
+
+ - - -
-
- -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -