2

I've created this trigger to create a project upon an opportunity being closed won. In our sandbox the trigger is performing properly. However, in production it is creating two projects for one opportunity. Can someone help me figure out why?

 trigger AddProject on Opportunity (after insert, after update) {    
 if(trigger.isUpdate){
        set<string> setOfFields = new set<string>{
                    'Generate_Projects__c', 'StageName', 'Projects_Created__c'
                };
        boolean change = false;
        for (integer i = 0; i < Trigger.new.size(); i++) {
            for (string field : setOfFields){
                if(trigger.new[i].get(field) != trigger.old[i].get(field)){
                    change = true;
                    break;
                }
            }
            if(change){
                break;
            }
        }
        if(!change){
            return;
        }
    }

    Set<Id> SetOfIds = new Set<Id>();
    Set<Id> SetOfOPLIIds = new Set<Id>();
    list<Project__c> lstProject = new List<Project__c>();
    list<CreditDetail__c> lstCD = new List<CreditDetail__c>();
    list<map<Date,Project__c>> lstmapProjects = new List<map<Date,Project__c>>();
    boolean blnContinue = false; 

    for (Integer i = 0; i < Trigger.new.size(); i++) {   
        if (Trigger.new[i].Generate_Projects__c == true && Trigger.new[i].StageName == '7 - Closed Won' && Trigger.new[i].Projects_Created__c == false){
            blnContinue=true;
        }
        SetOfIds.add(Trigger.new[i].Id);
    }

    if (!blnContinue) {
        return;
    }

    for (Integer i = 0; i < Trigger.new.size(); i++) {
        SetOfIds.add(Trigger.new[i].Id);
    }

    list<Opportunity> OppList = [Select Id,OwnerId, Generate_Projects__c, Beneficiary__c,Contract_New__c, RecordType.name, AccountId, Name, StageName, Projects_Created__c, 
    (Select Id, ProductID__c, Description, Jurisdiction__c,Tax_Years__c, TotalPrice, Product_ID__c, Budget_Month__c, Budget_Year__c, ServiceDate, Quantity From OpportunityLineItems) From Opportunity where id IN :SetOfIds 
    and StageName='7 - Closed Won' and RecordType.name = 'Research & Development'];

    for (Integer i = 0; i < OppList.size(); i++) {
        lstmapProjects.add(new map<Date,Project__c>());
        if (OppList[i].StageName == '7 - Closed Won' && OppList[i].RecordType.name == 'Research & Development' && Opplist[i].Generate_Projects__c == true){

            for (integer j = 0; j < OppList[i].OpportunityLineItems.size(); j++){
                if (lstmapProjects[i].get(OppList[i].OpportunityLineItems[j].ServiceDate) == null) {
                    lstmapProjects[i].put(OppList[i].OpportunityLineItems[j].ServiceDate, 
                    new Project__c (Kickoff_Date__c = OppList[i].OpportunityLineItems[j].ServiceDate,
                                    Project_Stage__c='1 - Awaiting Start - Internal',
                                    Program_Type__c = 'Research & Development',
                                    PlatformContract__c=OppList[i].Contract_New__c,
                                    Delivery_Deadline__c=OppList[i].OpportunityLineItems[j].ServiceDate+90,
                                    Opportunity__c = OppList[i].Id,
                                    Account__c = OppList[i].AccountId,
                                    Name = OppList[i].Name   + string.valueOf(OppList[i].OpportunityLineItems[j].ServiceDate.Year()) + '-'+ string.valueOf(OppList[i].OpportunityLineItems[j].ServiceDate.Year()+1)));
                    lstProject.add(lstmapProjects[i].get(OppList[i].OpportunityLineItems[j].ServiceDate));
                }
            }
        }
    }
    update OppList;
    insert lstProject;

    for (Integer i = 0; i < OppList.size(); i++) {
        if (OppList[i].StageName == '7 - Closed Won' && OppList[i].RecordType.name == 'Research & Development' && Opplist[i].Generate_Projects__c == true) {
            for (Integer j = 0; j < OppList[i].OpportunityLineItems.size(); j++) {
                //system.debug(OppList[i].OpportunityLineItems[j].Event_Quantity__c);

                if(lstmapProjects[i].get(OppList[i].OpportunityLineItems[j].ServiceDate) != null){
                  lstCD.add(new CreditDetail__c( Name =OppList[i].AccountID+'_'+'R&D'+ OppList[i].OpportunityLineItems[j].Jurisdiction__c+'_'+OppList[i].OpportunityLineItems[j].Tax_Years__c,
                                                 Product__c = OppList[i].OpportunityLineItems[j].Product_ID__c,
                                                 Project__c = lstmapProjects[i].get(OppList[i].OpportunityLineItems[j].ServiceDate).Id,
                                                 Beneficiary__c = OppList[i].Beneficiary__c,
                                                RecordTypeId = '01214000001FsPI',
                                                Jurisdiction__c = OppList[i].OpportunityLineItems[j].Jurisdiction__c,
                                                Program__c = 'R&D',
                                                Forecast_Credits_Delivered__c = OppList[i].OpportunityLineItems[j].TotalPrice,
                                                ForecastCreditDeliveredMonth__c = OppList[i].OpportunityLineItems[j].Budget_Month__c,
                                                ForecastCreditsDeliveredYear__c = OppList[i].OpportunityLineItems[j].Budget_Year__c,
                                                Tax_Year__c = OppList[i].OpportunityLineItems[j].Tax_Years__c));
                }

            }
        }
    }
    insert lstCD;
  • 1
    What field update workflow rules do you have active in each environment? – martin Jul 28 '15 at 17:03
  • I have multiple field updates on both opportunity & opp Product. – Andrew Sims Jul 28 '15 at 18:41
  • Are they identical in both environments? My first guess would be that the sandbox doesn't update a field when the opportunity becomes closed won while production does. – martin Jul 29 '15 at 0:54
0

workflow Rules cause triggers to run twice. You might want to modify your trigger to make sure you'll avoid creating duplicates:

trigger X on Opportunity (...) {
    if(staticVariables.triggerIds.containsAll(Trigger.newMap.keySet()) {
        return;
    }
    staticVariables.triggerIds.addAll(Trigger.newMap.keySet());
    // Do the rest of your code here

The variable is a simple normal class:

public class staticVariables {
    public static Set<Id> triggerIds = new Set<Id>();
}
  • I've added the above and created the new staticvariables class. Still getting the duplicate issue. – Andrew Sims Jul 28 '15 at 18:39
  • Hmm. I'm out of ideas. You might need some debug logs. Triggers should only execute twice at most. – sfdcfox Jul 29 '15 at 4:51

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.