Skip to content

Commit

Permalink
Merge pull request #176 from SalesforceLabs/feature/location_bugfix
Browse files Browse the repository at this point in the history
Fixes to Location Flows and Automation
  • Loading branch information
GeekStewie authored Oct 2, 2024
2 parents 13ce7d3 + 729ec82 commit 45633f9
Show file tree
Hide file tree
Showing 12 changed files with 423 additions and 985 deletions.
99 changes: 99 additions & 0 deletions force-app/main/default/classes/ASCS_MovementTriggerHandler.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
public with sharing class ASCS_MovementTriggerHandler {
// Method to handle logic after insert

public static void handleInsert(Map<Id, animalshelters__Movement__c> newMap) {

// Check if the allocation toggle is set:
// Return out if allocation enabled is false
// ASCS_Allocation_Toggle__c toggle = ASCS_Allocation_Toggle__c.getOrgDefaults();
// Boolean toggleValue = Boolean.valueOf(toggle.get('ASCS_Allocation_Enabled__c'));
// if(toggleValue == false) return;

// Create a list(Incase more than one movement is created) of Location Ids to pass through to updateMovementCount function
List<String> locationList = new List<String>();

// Loop incase of bulk upload
for (animalshelters__Movement__c movement : newMap.values()) {
// Make sure the new movement value is current
if(movement.animalshelters__Current__c == true && movement.animalshelters__Location__c != null){
// Add to Location List, for proccessing
locationList.add(movement.animalshelters__Location__c);
}
}
updateMovementCount(locationList);
}

// Method to handle logic after update
public static void handleUpdate(Map<Id, animalshelters__Movement__c> newMap, Map<Id, animalshelters__Movement__c> oldMap) {

// Return out if allocation enables is false
// ASCS_Allocation_Toggle__c toggle = ASCS_Allocation_Toggle__c.getOrgDefaults();
// Boolean toggleValue = Boolean.valueOf(toggle.get('ASCS_Allocation_Enabled__c'));
// System.debug('Toggle' + toggleValue);
// if(toggleValue == false) return;

// Create List of Locations
//Create Lost of Location Id Strings
List<String> locationIdStringList = new List<String>();

// Loop incase of bulk movement creation
for (Id movementId : newMap.keySet()) {
animalshelters__Movement__c newMovement = newMap.get(movementId);
animalshelters__Movement__c oldMovement = oldMap.get(movementId);
// Pull current value from new and onld map
Boolean oldCurrentValue = Boolean.valueOf(oldMovement.get('animalshelters__Current__c'));
Boolean newCurrentValue = Boolean.valueOf(newMovement.get('animalshelters__Current__c'));

// Check that the movement current value has been changed
if(oldCurrentValue != newCurrentValue){
// Add to location string list
String newLocation = String.valueOf(newMovement.get('animalshelters__Location__c'));
if(newLocation != null){
locationIdStringList.add(newLocation);
}
}
}
updateMovementCount(locationIdStringList);
}

// Method to pass in locationId List that updates the allocation based on movement count
public static void updateMovementCount(List<String> locationIdStringList) {
Map<String, Integer> movementCount = new Map<String, Integer>();
List<animalshelters__Locations__c> locationList = new List<animalshelters__Locations__c>();

// Perform the aggregate query to get count of movements per location
List<AggregateResult> results = [
SELECT animalshelters__Location__c, COUNT(Id)
FROM animalshelters__Movement__c
WHERE animalshelters__Location__c IN :locationIdStringList AND animalshelters__Current__c = true
GROUP BY animalshelters__Location__c
];

// Loop through the results and populate the map
for (AggregateResult result : results) {
String locationId = (String)result.get('animalshelters__Location__c');
Integer count = (Integer)result.get('expr0');

// Create temp location to update the allocation
animalshelters__Locations__c tempLocation = new animalshelters__Locations__c();
tempLocation.Id = locationId;
tempLocation.animalshelters__Allocation__c = count;
locationList.add(tempLocation);
// Add to map
movementCount.put(locationId, count);
}

// Now handle locations that were not found in the query results
for (String locationId : locationIdStringList) {
// If the locationId is not present in the results, add it with an allocation of 0
if (!movementCount.containsKey(locationId)) {
// Create a temp location with allocation 0
animalshelters__Locations__c tempLocation = new animalshelters__Locations__c();
tempLocation.Id = locationId;
tempLocation.animalshelters__Allocation__c = 0;
locationList.add(tempLocation);
}
}
update locationList;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>61.0</apiVersion>
<status>Active</status>
</ApexClass>
109 changes: 109 additions & 0 deletions force-app/main/default/classes/ASCS_MovementTriggerHandlerTest.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
@isTest
private class ASCS_MovementTriggerHandlerTest {

@TestSetup
static void setupTestData() {
// Fetch all necessary record type Ids in one go
Map<String, Schema.RecordTypeInfo> recordTypeMap = Schema.SObjectType.animalshelters__Locations__c.getRecordTypeInfosByDeveloperName();
String unitRecordTypeId = recordTypeMap.get('Unit').getRecordTypeId();
String blockRecordTypeId = recordTypeMap.get('Block').getRecordTypeId();
String siteRecordTypeId = recordTypeMap.get('Site').getRecordTypeId();

// Create the Site and Block locations
animalshelters__Locations__c locationSite = new animalshelters__Locations__c(
animalshelters__Name__c = 'Test Location Site',
recordTypeId = siteRecordTypeId
);

insert locationSite;

animalshelters__Locations__c locationBlock = new animalshelters__Locations__c(
animalshelters__Name__c = 'Test Location Block',
recordTypeId = blockRecordTypeId,
animalshelters__Parent_Block__c = locationSite.Id
);

insert locationBlock ;

// Create two Unit locations
List<animalshelters__Locations__c> locationList = new List<animalshelters__Locations__c>();
animalshelters__Locations__c location1 = new animalshelters__Locations__c(
animalshelters__Name__c = 'Test Location',
recordTypeId = unitRecordTypeId,
animalshelters__Capacity__c = 5,
animalshelters__Parent_Block__c = locationBlock.Id
);

animalshelters__Locations__c location2 = new animalshelters__Locations__c(
animalshelters__Name__c = 'Test Location 2',
recordTypeId = unitRecordTypeId,
animalshelters__Capacity__c = 5,
animalshelters__Parent_Block__c = locationBlock.Id
);

locationList.add(location1);
locationList.add(location2);

// Insert unit locations
insert locationList;

// Create an Animal record
animalshelters__Animal__c animal = new animalshelters__Animal__c(
animalshelters__Microchip__c = '123456',
animalshelters__Animal_Name__c = 'Test Dog',
//ASCS_Status_Reason__c = 'None',
animalshelters__Date_of_Arrival__c = DateTime.now()
);
insert animal;
}

@IsTest
public static void testMovementTrigger() {
// Retrieve test data created in @TestSetup
animalshelters__Locations__c location1 = [SELECT Id, animalshelters__Allocation__c FROM animalshelters__Locations__c WHERE animalshelters__Name__c = 'Test Location' LIMIT 1];
animalshelters__Locations__c location2 = [SELECT Id, animalshelters__Allocation__c FROM animalshelters__Locations__c WHERE animalshelters__Name__c = 'Test Location 2' LIMIT 1];
animalshelters__Animal__c animal = [SELECT Id FROM animalshelters__Animal__c WHERE animalshelters__Animal_Name__c = 'Test Dog' LIMIT 1];

// Start test block for DML operation simulation
Test.startTest();

// Create the first Movement
animalshelters__Movement__c movement1 = new animalshelters__Movement__c(
animalshelters__Location__c = location1.Id,
animalshelters__Current__c = true,
animalshelters__Animal__c = animal.Id
);
insert movement1;

// Verify the first location's allocation after first movement
animalshelters__Locations__c updatedLocation1 = [SELECT animalshelters__Allocation__c FROM animalshelters__Locations__c WHERE Id = :location1.Id];
System.assertEquals(1, updatedLocation1.animalshelters__Allocation__c);

// Create the second movement, mark the first as inactive
animalshelters__Movement__c movement2 = new animalshelters__Movement__c(
animalshelters__Location__c = location2.Id,
animalshelters__Current__c = true,
animalshelters__Animal__c = animal.Id
);
movement1.animalshelters__Current__c = false;

// Insert new movement and update the first
insert movement2;
update movement1;

// End test block
Test.stopTest();

// Query both locations for allocation check
List<animalshelters__Locations__c> updatedLocations = [SELECT Id, animalshelters__Allocation__c FROM animalshelters__Locations__c WHERE Id IN :new Set<Id>{location1.Id, location2.Id}];

// Verify allocations after the movements
for (animalshelters__Locations__c loc : updatedLocations) {
if (loc.Id == location1.Id) {
System.assertEquals(0, loc.animalshelters__Allocation__c, 'Location 1 should have 0 allocation');
} else if (loc.Id == location2.Id) {
System.assertEquals(1, loc.animalshelters__Allocation__c, 'Location 2 should have 1 allocation');
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>61.0</apiVersion>
<status>Active</status>
</ApexClass>
12 changes: 12 additions & 0 deletions force-app/main/default/classes/MovementTrigger.trigger
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
trigger MovementTrigger on animalshelters__Movement__c (after insert, after update) {

// Called upon Create of new movement
if (Trigger.isInsert) {
ASCS_MovementTriggerHandler.handleInsert(Trigger.newMap);
}

// Update an existing movement
if (Trigger.isUpdate) {
ASCS_MovementTriggerHandler.handleUpdate(Trigger.newMap, Trigger.oldMap);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexTrigger xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>61.0</apiVersion>
<status>Active</status>
</ApexTrigger>
Loading

0 comments on commit 45633f9

Please sign in to comment.