I'm trying to write a trigger to prevent users from changing an opportunity stage if the following isn't met.
- Opportunity doesn't have a contact with the role Champion.
- Opportunity doesn't have an event with the type New Business Meeting.
- Latest New Business Meeting doesn't have an RSM. I'm having trouble bulkifying the trigger. Here's my code.
Trigger
trigger OpportunityTrigger on Opportunity (before update) {
if (Trigger.isBefore) {
if (Trigger.isUpdate) {
for (Opportunity opp : Trigger.New)
{
List<ID> OppID = New List<ID>();
Opportunity oldOpp = Trigger.oldMap.get(opp.ID);
if(opp.StageName == 'Discovery' && oldOpp.StageName == 'Scope' && opp.Link_to_Value_Pyramid__c != null){
OppID.add(opp.Id);
OpportunityHandler.stage2To3(Trigger.new);
}
if(opp.StageName == 'Discovery' && oldOpp.StageName == 'Scope' && opp.Link_to_Value_Pyramid__c == null){
opp.addError('Unable to save. Please fill in the Link to Value Pyramid field');
}
}
}
}
}
Trigger Handler
public class OpportunityHandler {
public static void stage2To3(List<Opportunity> listOfNewOpportunities){
Set<Id> oppsWithChampions = new Map<Id, SObject>(
[SELECT Opportunity.Id
FROM OpportunityContactRole
WHERE Role='Champion' AND Opportunity.Id IN :listOfNewOpportunities]).keySet();
List<Event> oppsWithEvents =
[SELECT WhatId
FROM Event
WHERE Type = 'New Business Meeting'
AND WhatId IN: oppsWithChampions];
Map<Id, AggregateResult> maxEvents = new Map<Id, AggregateResult>
([SELECT WhatId Id, Max(ActivityDateTime) ActivityDate
FROM Event
WHERE Type = 'New Business Meeting'
AND WhatId IN: oppsWithChampions
GROUP BY WhatId]);
Set<Id> whatIds = new Set<Id>();
for (AggregateResult ar : [SELECT WhatId, Max(ActivityDateTime) ActivityDate
FROM Event
WHERE Type = 'New Business Meeting'
AND WhatId IN: oppsWithChampions
//AND ActivityDate = LAST_N_DAYS:35
GROUP BY WhatId]){
whatIds.add((ID)ar.get('WhatId'));
}
List<Opportunity> oppNotUpdated = [SELECT Id FROM Opportunity
WHERE Id IN : listOfNewOpportunities
AND Id NOT IN : whatIds];
for(Opportunity o:listOfNewOpportunities){
for(Opportunity o:oppNotUpdated){
o.addError('Please fill out the required information before changing the opportunity stage.');
}
}
}
}
I have tried the following code but I get 'Invalid bind expression type of OpportunityContactRole does not match domain of foreign key'. How do I filter the listOfNewOpportunities to only include the ones that do not meet the criteria.