Last active
January 21, 2022 18:43
-
-
Save JeroenSfdc/eed4390f0874dbe812568e63dbf2faee to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Created by MO20244784 on 20/01/2022. | |
*/ | |
public with sharing class PerformanceTriggerHelper { | |
// The method name can be just matchBooking() | |
// That is in hindsight a better name, because the intent is to ideally identify/match a Booking | |
// Method should allow for partial success with regards to DML, any exceptions should be logged to DebugLog | |
// Beware: inserts/updates of EDC are triggered by API, so we should not return exceptions to the API | |
// --> that would make no sense, since through API a 'valid' performance should be inserteable/upserteable. | |
// See also comment in the bottom w/r logic to identify a booking. | |
public static void setCleaningLocationMatchingStatus(List<Performance__c> newPerformanceList) { | |
for (Performance__c performance : newPerformanceList) { | |
workerIds.add(performance.WorkerId__c); | |
workDateList.add(performance.WorkDate__c); | |
personAccountIds.add(performance.CustomerContractId__c); | |
} | |
Set<Id> workerIds = new Set<Id>(); | |
Set<Date> workDateList = new Set<Date>(); | |
Set<Id> personAccountIds = new Set<Id>(); | |
List<Booking__c> updateBookingInfo = new List<Booking__c>(); | |
Id locationId = null; | |
Integer locationCount = 0; | |
for (Performance__c performance : newPerformanceList) { | |
workerIds.add(performance.WorkerId__c); | |
workDateList.add(performance.WorkDate__c); | |
personAccountIds.add(performance.CustomerContractId__c); | |
} | |
List<Booking__c> bookingLst = getBookings(workDateList, workerIds); | |
List<Account> cleaningLocationLst = getCleaningLocations(personAccountIds); | |
for (Performance__c performance : newPerformanceList) { | |
List<Booking__c> matchedBookingLst = new List<Booking__c>(); | |
// Always use the Constants class. | |
if (performance.RecordType.DeveloperName == 'EDC') { | |
for (Booking__c booking : bookingLst) { | |
if (performance.WorkerId__c == booking.HouseholdHelp__c && performance.WorkDate__c == booking.Date__c) { | |
matchedBookingLst.add(booking); | |
} | |
} | |
} | |
locationCount = 0; | |
for (Account account : cleaningLocationLst) { | |
if (account.PrimaryContactNew__c == performance.CustomerContractId__c) { | |
locationId = account.Id; | |
locationCount++; | |
} | |
} | |
// Constants! | |
performance.MatchingStatus__c = 'Unmatched'; | |
switch on locationCount { | |
when 0 { | |
performance.MatchingStatus__c = 'Unmatched - No Location'; | |
} | |
when 1 { | |
switch on matchedBookingLst.size() { | |
when 0 { | |
performance.MatchingStatus__c = 'Unmatched - No booking'; | |
} | |
when 1 { | |
performance.Booking__r = matchedBookingLst.get(1); | |
performance.MatchingStatusDate__c = Date.today(); | |
matchedBookingLst.get(1).Performance__r = performance; | |
updateBookingInfo.add(matchedBookingLst.get(1)); | |
performance.MatchingStatus__c = performance.HoursQuantity__c == matchedBookingLst.get(1).Hours__c ? 'Matched' : 'Partially matched - Different Hours'; | |
} | |
when else { | |
performance.MatchingStatus__c = 'Unmatched - Multiple Bookings'; | |
} | |
} | |
} | |
when else { | |
performance.MatchingStatus__c = 'Unmatched - Multiple Locations'; | |
} | |
} | |
} | |
} | |
// Technically this SOQL should be ok. But beware Booking will contains 10s of M records within few years | |
// So DB will filter on HouseHoldHelp__c but that will for the DB not be super efficient. | |
// Asume we receive a 200-record bulkified insert, 200 performances for 200 unique HHHs | |
// The IN :workerIds will be 'expensive' for the database (but as long as it remains within SOQL time-out it's fine) | |
// The DB will technically filter in-memory for IN :workDateList, so final result set should be OK-ish | |
// I'd expect returning a Map<String, Booking__c> where the Key would be something like: | |
// StartDate_HouseholdHelpId (like: 20221231_a2E1x000002BOXyEAO) | |
// You can then quickly see what are the bookings for give HHH / Start Date | |
// Next the Bookings can be checked for location & hours. | |
private static List<Booking__c> getBookings(Set<Date> workDateList, Set<Id> workerIds) { | |
return [ | |
SELECT Id,Name,HouseholdHelp__c,Date__c,Hours__c | |
FROM Booking__c | |
WHERE Date__c IN :workDateList AND HouseholdHelp__c IN :workerIds | |
]; | |
} | |
// You need to take the AccountContact relationship into account, one PA (customer) can be related with >1 Cleaning location | |
// Background: there are often > 1 customer related with a location. That is typically because e.g. wife and husband both own | |
// their own respective Sodexo number. Both can be used by the customer. This is a very typical situation, should not be an issue | |
// since most of the time the customer will be related with just a single cleaning location. | |
// Less frequent: a customer is linked to > 1 cleaning location. In that case, you need to consider both locations as probable | |
// to match a booking. Ideally it identifies a single Booking. But in case based on Start Date / HHH any one of the locations | |
// result in > 1 Booking that is an issue. | |
private static List<Account> getCleaningLocations(Set<Id> personAccountIds) { | |
return [ | |
SELECT Id,Name | |
FROM Account | |
WHERE RecordType.DeveloperName = 'CleaningLocation' AND PrimaryContactNew__c IN :personAccountIds | |
]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment