This could get a bit sketch if the numbers of records are large, but if they're managable within limits then some aggregate SOQL could be of use here.
For example to get all the counts for the various related records (I assume you're grouping them by some kind of field, like Type__c
:
select count(Id) from Child__c where Parent__c = : someId group by <<field to count>>
This gets more tricky when dealing with multiple parents, but you can group by those too:
select count(Id), Parent__c from Child__c where Parent__c in : <<setOfParents>> group by Parent__c, <<field to count>>
Then it'll just be a case of looping through your results and finding the highest number of children for each parent, something like:
Map<String, Integer> parentToHighest = new Map<String, Integer>();
Map<String, String> parentToValue = new Map<String, String>();
for(AggregateResult ar : [ select count(Id) num, Type__c, Parent__c from Child__c where Parent__c in : trigger.new.KeySet() group by Parent__c, Type__c])
{
Integer num = (Integer)ar.get('num');
String name = (String)ar.get('Parent__c');
String type = (String)ar.get('Type__c');
if(parentToHighest.get(name) == null || parentToHighest.get(name) < num)
{
parentToHighest.put(name, num);
parentToValue.put(name, type);
}
}
Now, if you need it you'll have a map of parent id -> count of highest child, and also a map of parent -> type of child which you can use to populate the appropriate parent field.
You'll need to work out what you want to do when two children types have the same count!
The trigger code is having lot of redundancy, So I modified it.
before posting the modified code few lines of explanation what I changed.
you collected account Ids twice and did the condition check twice where once is more enough. I am also made changes to the test class, where Task data is provided which is not required because the trigger has to create it once the necessary conditions are met.
I am expecting this trigger should work for you, if there is any errors feel free to post as a comment.
trigger OpportunityAfter on Opportunity (after update){
Set AccountIDs = new Set();
for(Opportunity o : trigger.new){
if(opp.StageName == 'Closed - Lost' && opp.Business_Line__c == 'Workforce' &&
opp.Survey_Type__c != 'APulse' && trigger.oldMap.get(opp.Id).StageName != opp.StageName){
AccountIDs.add(o.AccountId);
}
}
Task[] tasksToInsert = new Task[]{};
for (Account acc : [Select Id, Name, OwnerId from Account where Id IN :AccountIds]){
for (Opportunity opp : trigger.new){
if(opp.AccountId == acc.Id){
Task tas = new Task();
tas.WhatId=acc.Id;
tas.OwnerId=opp.OwnerId;
tas.Subject='Follow-up: ' + opp.name + ' - ' + acc.name;
tas.ActivityDate=(opp.CloseDate + 180);
tas.Description='Follow up to see how engagement initiatives are going and if Avatar can help. Refer to lost opportunity: ' + opp.name;
tasksToInsert.add(tas);
}
}
}
if(tasksToInsert != null && !tasksToInsert.isEmpty())
Database.insert(tasksToInsert);
}
@isTest
public class TestClass {
static testMethod void myUnitTest() {
//Set up user
User u1 = [SELECT Id FROM User WHERE Email='abc@sampleemail.com'];
test.startTest();
//Run As U1
System.RunAs(u1){
System.debug('Testing trigger... (single record validation)');
//NEW Account record
Account acc = new account();
acc.Name = 'Test Account';
acc.Industry = 'Healthcare';
insert acc;
//NEW Opportunity record
Opportunity opp = new Opportunity();
opp.Name = 'Test Opportunity';
opp.CloseDate = System.today();
opp.StageName = 'S1 - Investigative';
opp.Type = 'Repeat Business - Wrkforce HC';
opp.AccountId = acc.Id;
opp.Survey_Type__c = 'Product Name';
insert opp;
opp.StageName = 'Closed - Lost';
opp.Reason_Won_Lost__c = 'Relationship';
opp.Business_Line__c = 'Workforce' //added this line to meet the if condition while collecting the set of id in the trigger.
update opp;
test.stopTest();
// Here I am expecting the task has been inserted and doing a query for it and check it in the assert statement.
Task testTask=[Select Id, WhatId from Task where WhatId=:acc.Id];
//Validate single insert
System.assertEquals(acc.Id, testTask.WhatId);
}
}
}
Best Answer
It's probably better to iterate through the custom settings instead of the account fields, as there are probably less of them thus saving you iterations and making it more efficient.
Try something like this: