0

I need to update a custom field (Next_Activity_Date__c) on Opportunity with next closest Date from Event or Task which is added to current Opportunity.

Example: When a user has logged a Task/Event, and it's related to Opportunity - then get closest ActivityDate from OpenActivities and set it to Opportunity.Next_Activity_Date__c

This SOQL request can get all OpenActivities from current Oportunity

Opportunity oppActivities = [SELECT (SELECT ActivityDate FROM OpenActivities ORDER BY ActivityDate ASC) FROM Opportunity WHERE id = :oppId];

How to implement this by not writing two similar triggers on Task & Event objects?

trigger EventTrigger on Event (after insert, after update) {
    Opportunity[] oppToUpdate = new Opportunity[]{};

    if(Trigger.isInsert || Trigger.isUpdate) {
        for(Event e : Trigger.new) {
            if(e.WhatId != null && e.WhatId .getSobjectType().getDescribe().getName() == 'Opportunity') {
                Opportunity opp = OpportunityHelper.getOpenActivities(e.WhatId);
                
                if(opp.OpenActivities.size() > 0) {
                    opp.Next_Activity_Date__c = opp.OpenActivities.get(0).ActivityDate;
                } else {
                    opp.Next_Activity_Date__c = null;
                }
                oppToUpdate.add(opp);
            }
        }
    }
    if(oppToUpdate.size() > 0) {
        update oppToUpdate;
    }
}
2
  • Are you asking how to do this without code, or are you asking how to do this without duplicating code?
    – sfdcfox
    Commented Jan 26, 2021 at 19:21
  • If you know how to implement this without code - please, share your solution. And the main question was - 'how to do this without duplicating code' Currently, I have two triggers doing the same thing but on different objects
    – dmtkmrv
    Commented Jan 26, 2021 at 19:54

1 Answer 1

0

As triggers, what you need is a common class to deduplicate your code (the Don't Repeat Yourself principle), something like:

public class OpportunityNextActivityDate {
  public static void execute(sObject[] records) {
    Set<Id> oppIds = new Set<Id>();
    for(sObject record: records) {
      Id whatId = (Id)record.get('WhatId');
      if(whatId?.getSObjectType() == Opportunity.sObjectType) {
        oppIds.add(whatId);
      }
    }
    if(oppIds.isEmpty()) {
      return;
    }
    Opportunity[] opps = [SELECT Next_Activity_Date__c, (SELECT ActivityDate FROM OpenActivities ORDER BY ActivityDate ASC NULLS LAST) FROM Opportunity WHERE Id = :oppIds];
    Opportunity[] updatedOpps = new Opportunity[0];
    for(Opportunity record: opps) {
      if(!record.OpenActivities.isEmpty() && record.Next_Activity_Date__c != record.OpenActivities[0].ActivityDate) {
        updatedOpps.add(new Opportunity(Id=record.Id, Next_Activity_Date__c = record.OpenActivities[0].ActivityDate));
      }
    }
    update updatedOpps;
  }
}

Then, in your triggers, you just call the method:

trigger EventTrigger on Event (after insert, after update) {
  OpportunityNextActivityDate.execute(Trigger.new);
}

trigger EventTrigger on Task (after insert, after update) {
  OpportunityNextActivityDate.execute(Trigger.new);
}

You can also do this with Process Builder, but you'll need two Processes instead of Triggers, and ideally you'd use a flow with basically the same technique as this code: query the opportunity record's open activities, then grab the first date, if applicable, and update the Opportunity records.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .