Skip to content

Instantly share code, notes, and snippets.

@JeroenSfdc
Last active January 21, 2022 18:43
Show Gist options
  • Save JeroenSfdc/eed4390f0874dbe812568e63dbf2faee to your computer and use it in GitHub Desktop.
Save JeroenSfdc/eed4390f0874dbe812568e63dbf2faee to your computer and use it in GitHub Desktop.
/**
* 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