7

Scenario: I have a trigger that will fire whenever a Primary Campaign Changes on an Opportunity by comparing trigger.old and trigger.new values of CampaingID,

Issue: When I changed the campaign on the opportunity to point to a different campaign, the trigger did not fire when I debugged it I found that trigger.old value and trigger.new value of Campaign are the SAME (I checked the logs there is no recursion problem all classes are called only once).

Any reason why this might be happening?

SideNote : I have WFRs firing on Opportunity as well

trigger MasterOpportunityTrigger on Opportunity(after update) 
{

    if (Trigger.isUpdate) 
    {
        if(triggerHelper.isAfterUpdateFirstRun == true)
            triggerHelper.isAfterUpdateFirstRun = false; 

        //Campaign changed for Opportunity update the old campaign
        CampChangeRollup Camp = new CampChangeRollup(trigger.oldmap,trigger.newmap);
        Camp.FCampRollUp();
        system.debug('*************CampChangeRollup Class Execute After Update');
    }        
}

public class CampChangeRollup 
{
    private Map<Id, Opportunity> oldOpps;
    private Map<Id, Opportunity> newOpps;
    private Map<Id,Opportunity> CampIdOpp = new Map<Id,Opportunity>();
    private list<Opportunity> Opplst = new list<Opportunity>();
    private list<Opportunity> delOpplst = new list<Opportunity>();

    public CampChangeRollup(Map<Id, Opportunity> oldTriggerOpps, Map<Id, Opportunity> newTriggerOpps) 
    {
        if(oldTriggerOpps != Null)
            oldOpps = oldTriggerOpps;
        else
            oldOpps = new Map<Id,Opportunity>();

        if(newTriggerOpps != Null)
            newOpps = newTriggerOpps;    
        else
            newOpps = new Map<Id,Opportunity>();


        for(Opportunity opp : newOpps.values())
        {    
            // Access the "old" record by its ID in Trigger.oldMap
            // Opportunity oldOpp;           
            Id newOppCampId;
            Id oldOppCampId;

            if(!oldOpps.isEmpty())
                oldOppCampId = oldOpps.get(opp.Id).CampaignId;

            if(opp.CampaignId != null)
                newOppCampId = opp.CampaignId;

            system.debug('oldOppCampId'+' '+oldOppCampId+' '+'newOppCampId'+' '+newOppCampId);

            //Only when Campaign is changed 
            if(newOppCampId != oldOppCampId) 
                CampIdOpp.put(oldOppCampId,opp);     
        }
    }

    public void FCampRollUp()
    {
        try
        {
            if(CampIdOpp!= null)
            {
                for(Campaign Camp : [select id from Campaign where id =:CampIdOpp.keyset()])
                {
                    Id OppId = CampIdOpp.get(Camp.id).id;
                    String soql = CloningUtils.getCreatableFieldsSOQL('Opportunity','id = :OppId ');
                    system.debug('returned SOQL'+ soql);            
                    Opportunity O = (Opportunity)Database.query(soql);
                    Opportunity Od = O.clone(false, true);
                    Od.CampaignId = Camp.Id; 
                    Od.Amount = 1;               
                    system.debug('Opportunity tobe deleted'+ Od.id+Od.name+Od.CampaignId);
                    Opplst.add(Od);
                } 

                if(Opplst.size()>0)
                { 
                    insert Opplst;   
                    system.debug('Opplst'+Opplst);
                    system.debug('Dummy Opportunity Inserted for Campaign Changed Opportunity'+ Opplst+Opplst[0].id+Opplst+Opplst[0].CampaignId);                          
                }
            }
        } catch(Exception error){ }
    }
}
  • 2
    Without seeing your code, your problem is difficult to diagnose. Please edit your post to include it. – Adrian Larson May 21 '16 at 14:21
  • Have you tried debugging it by creating a simple after update code just to iterate over the records you changed, to see if the values are still the same? Because if they are not, then the problem is probably in your code. – Renato Oliveira May 22 '16 at 22:58
  • Is the trigger supposed to change the field or the workflow rule? That's very important. – Programmable Medley Jul 14 '16 at 19:51
1

One of the possible scenario here is usage of multiple triggers with DML. Let's look at the example below.

Trigger B:

trigger OpportunityTriggerB on Opportunity (after update) {
    if(Trigger.isUpdate && Trigger.isAfter){
        OpportunityTriggerHandlerB.onAfterUpdate( Trigger.oldMap, Trigger.newMap);
    }
}

With its handler:

public with sharing class OpportunityTriggerHandlerB {
    public static Boolean firstRunAfterUpdate = true;
    private static Integer counter = 0;

    public static void onAfterUpdate(map<Id,Opportunity> oldMap, map<Id,Opportunity> newMap) {
        system.debug('counter: ' + counter++);

        if (firstRunAfterUpdate) {
            firstRunAfterUpdate = false;

            for (Opportunity opp : newMap.values()){
                if (oldMap.get(opp.Id).StageName != opp.StageName) {
                    system.debug('OpportunityTriggerHandler magic');
                } else {
                    system.debug('OpportunityTriggerHandler no magic');
}   }   }   }   }

Due to Stage update, will get following logs:

|DEBUG|counter: 0
|DEBUG|OpportunityTriggerHandler magic

But if we add new Trigger for Opportunity:

trigger OpportunityTriggerC on Opportunity (after update) {
    if(Trigger.isUpdate && Trigger.isAfter){
        OpportunityTriggerHandlerC.onAfterUpdate( Trigger.oldMap, Trigger.newMap);
    }
}

Handler :

public with sharing class OpportunityTriggerHandlerC {
    public static Boolean firstRunAfterUpdate = true;
    private static Integer counter = 0;

    public static void onAfterUpdate(map<Id,Opportunity> oldMap, map<Id,Opportunity> newMap) {

        system.debug('C counter: ' + counter++);
        for (Opportunity opp : newMap.values()){
            system.debug('C old StageName: ' + oldMap.get(opp.Id).StageName + ' new StageName: ' + opp.StageName );
        }

        if (firstRunAfterUpdate) {
            firstRunAfterUpdate = false;

            updateProcedure(newMap.values());
        }
    }

    private static void updateProcedure(list<Opportunity> opps){
        list <Opportunity> oppToUpdate = new list<Opportunity>();
        for(Opportunity opp :opps) {
            oppToUpdate.add(new Opportunity(id = opp.id) );
        }
        system.debug('C OpportunityTriggerHandler update');
        update oppToUpdate;
    }
}

Console log:

|DEBUG|C counter: 0
|DEBUG|C old StageName: Qualification new StageName: Negotiation/Review
|DEBUG|C OpportunityTriggerHandler update
|DEBUG|C counter: 1
|DEBUG|C old StageName: Negotiation/Review new StageName: Negotiation/Review
|DEBUG|counter: 0
|DEBUG|OpportunityTriggerHandler no magic
|DEBUG|counter: 1

As we can see there is no Magic for B Handler. DML we've made in trigger C has created new trigger event, and this event has higher priority that DML from UI. (I suppose Salesforce is using Stack for this.) That's why we have same field values while they're arriving to Trigger B If you disable recursion functionality, you'll see that values from UI arrive to trigger B with counter = 1. Just make sure you have one trigger and as many handlers as you want.

I thought that order is dependent on trigger time creation or its name, but it's not

| improve this answer | |
  • If someone is reading this and given example doesn't work, try to swap handler bodies. – Ilya Lepesh Aug 28 '16 at 0:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.