function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Jordan KindlerJordan Kindler 

System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, cd_OpportunityLineItemTrigger: execution of AfterInsert caused by: System.NullPointerException: Attempt to de-reference a null object

I get the above error when deploying a trigger and its associated test class in production. I believe it has to do with either my creating a record that already exists via another trigger, or something that has been left null(?). Any and all help is much appreciated! Posting my trigger and test class below:

Trigger:
trigger closedTrigger on Opportunity (after update) {
    
    //create a list of related accounts and account Ids
    list<Id> acctIds = new list<Id>();
    list<Account> accts = new list<Account>();
    
    //get the accounts and oplineitems associated with the opportunity 
    for (opportunity o:trigger.new) {
        acctIds.add(o.accountId);    
    }
    
    //create a list of Opportunity Line Items 
   list<Id> prodOpIds = new list<Id>();
    
    Map<Id, Set<String>> mapProducts = new Map<Id, Set<String>>();
        for (opportunity op:trigger.new) {
            prodOpIds.add(op.Id);
            mapProducts.put(op.id, new Set<String>());
        }
    
    for (OpportunityLineItem z: [SELECT Id, Product2.Name, OpportunityId FROM OpportunityLineItem WHERE OpportunityId IN: prodOpIds]) {
        mapProducts.get(z.OpportunityId).add(z.Product2.Name);
    }
    
    //now we can loop over the associated account(s) and update the information with which we're concerned
    for (account a: [SELECT Id, Curriculum_Product__c, Past_Room_Scheduling_Product__c, Room_Scheduling_Product__c, 
                                                       Past_Curriculum_Product__c, Past_Event_Scheduling_Product__c, 
                                                       Event_Scheduler_Product__c,  Class_Schedule_Planning_Product__c, 
                                                       Past_Class_Scheduling_Product__c, Past_Catalog_Product__c, 
                                                       Catalog_Product__c, Account_Lifecycle_Status__c 
                     FROM account WHERE Id IN: acctIds]) {
        for (opportunity op:trigger.new) {
        Set<String> setProducts = mapProducts.get(op.Id);
            if (op.stageName=='Closed Won' && trigger.oldmap.get(op.Id).StageName != 'Closed Won') {
                //set status to Customer
                a.Account_Lifecycle_Status__c = 'Customer';
                //class 
                if(setProducts.contains('Class Scheduler') && a.Class_Schedule_Planning_Product__c != 'Coursedog')  {
                    a.Past_Class_Scheduling_Product__c = a.Class_Schedule_Planning_Product__c;
                    a.Class_Schedule_Planning_Product__c = 'Coursedog';                 
                } 
                //catalog
                if(setProducts.contains('Catalog Management') && a.Catalog_Product__c != 'Coursedog')  {
                    a.Past_Catalog_Product__c = a.Catalog_Product__c;
                    a.Catalog_Product__c = 'Coursedog';
                }
                //events
                if(setProducts.contains('Event Scheduler') && a.Event_Scheduler_Product__c != 'Coursedog')  {
                    a.Past_Event_Scheduling_Product__c = a.Event_Scheduler_Product__c;
                    a.Event_Scheduler_Product__c = 'Coursedog';
                }  
                //curriculum
                if(setProducts.contains('Curriculum Management') && a.Curriculum_Product__c != 'Coursedog')  {
                    a.Past_Curriculum_Product__c = a.Curriculum_Product__c;
                    a.Curriculum_Product__c = 'Coursedog';
                }
            accts.add(a);  
               
            }
            if (op.stageName=='Closed Lost' && trigger.oldmap.get(op.Id).StageName != 'Closed Lost') {
                a.Account_Lifecycle_Status__c = 'Recycled';
            accts.add(a);
            }
        }
    
    }
    update accts; 
}
Test class:
@istest
public class testClassForTrigger{
    @istest
    public static void triggerTest(){
        account acc = new account();
        acc.name='test'; //when you create an account you need a name 
        acc.Class_Schedule_Planning_Product__c = 'Astra Scheduler';
        acc.Curriculum_Product__c = 'Courseleaf CIM';
        acc.Catalog_Product__c = 'Courseleaf CAT';
        acc.Event_Scheduler_Product__c = 'EMS';
        insert acc; //now we have an ID
        
        Pricebook2 stdpb = new Pricebook2(Id = Test.getStandardPricebookId());
        update stdpb;

        Product2 p = new Product2(Name = 'Catalog Management', CanUseRevenueSchedule = true, IsActive = true);
        insert p;
        
        Product2 p2 = new Product2(Name = 'Curriculum Management', CanUseRevenueSchedule = true, IsActive = true);
        insert p2;
        
        Product2 p3 = new Product2(Name = 'Class Scheduler', CanUseRevenueSchedule = true, IsActive = true);
        insert p3;
        
        Product2 p4 = new Product2(Name = 'Event Scheduler', CanUseRevenueSchedule = true, IsActive = true);
        insert p4;

        PricebookEntry pbe = new PricebookEntry(Product2Id = p.Id, Pricebook2Id = stdpb.Id, IsActive = true, UnitPrice = 0);
        insert pbe;
        
        PricebookEntry pbe2 = new PricebookEntry(Product2Id = p2.Id, Pricebook2Id = stdpb.Id, IsActive = true, UnitPrice = 0);
        insert pbe2;
        
        PricebookEntry pbe3 = new PricebookEntry(Product2Id = p3.Id, Pricebook2Id = stdpb.Id, IsActive = true, UnitPrice = 0);
        insert pbe3;
        
        PricebookEntry pbe4 = new PricebookEntry(Product2Id = p4.Id, Pricebook2Id = stdpb.Id, IsActive = true, UnitPrice = 0);
        insert pbe4;
        
        opportunity opp = new opportunity();
        opp.name='test opp';
        opp.accountId = acc.Id; 
        opp.closedate = date.today().adddays(5);
        opp.stagename='Interest'; //when you create an op you need a stage, acocunt, name, and close date
        
        test.startTest();
        insert opp;
        
        
        OpportunityLineItem oli = new OpportunityLineItem(OpportunityId = opp.Id, PricebookEntryId = pbe.Id, Quantity = 1, UnitPrice = 50);
        insert oli;
        
        OpportunityLineItem oli2 = new OpportunityLineItem(OpportunityId = opp.Id, PricebookEntryId = pbe2.Id, Quantity = 1, UnitPrice = 50);
        insert oli2;
        
        OpportunityLineItem oli3 = new OpportunityLineItem(OpportunityId = opp.Id, PricebookEntryId = pbe3.Id, Quantity = 1, UnitPrice = 50);
        insert oli3;
        
        OpportunityLineItem oli4 = new OpportunityLineItem(OpportunityId = opp.Id, PricebookEntryId = pbe4.Id, Quantity = 1, UnitPrice = 50);
        insert oli4;
        
        opp.closedate = date.today();
        opp.stageName = 'Closed Won';
        update opp; 
        account actTest = [SELECT Id, Account_Lifecycle_Status__c, Class_Schedule_Planning_Product__c, Past_Class_Scheduling_Product__c, 
                                                                   Curriculum_Product__c, Past_Curriculum_Product__c,
                                                                   Catalog_Product__c, Past_Catalog_Product__c,
                                                                   Event_Scheduler_Product__c, Past_Event_Scheduling_Product__c
                                                                   FROM Account WHERE ID = :acc.Id LIMIT 1];
        update actTest; 
        system.assertequals('Customer', actTest.Account_Lifecycle_Status__c,'Opportunity update did not set account status properly');
        system.assertequals('Coursedog', actTest.Curriculum_Product__c, 'Opportunity did not set curriculum product properly');
        system.assertequals('Courseleaf CIM', actTest.Past_Curriculum_Product__c, 'Opportunity did not set curriculum product properly');
        system.assertequals('Coursedog', actTest.Class_Schedule_Planning_Product__c, 'Opportunity did not set scheduling product properly');
        system.assertequals('Astra Scheduler', actTest.Past_Class_Scheduling_Product__c, 'Opportunity did not set scheduling product properly');
        system.assertequals('Coursedog', actTest.Event_Scheduler_Product__c, 'Opportunity did not set event product properly');
        system.assertequals('EMS', actTest.Past_Event_Scheduling_Product__c, 'Opportunity did not set event product properly');
        system.assertequals('Coursedog', actTest.Catalog_Product__c, 'Opportunity did not set catlog product properly');
        system.assertequals('Courseleaf CAT', actTest.Past_Catalog_Product__c, 'Opportunity did not set catalog product properly');

        test.stopTest();
        
       
    }
}

 
Best Answer chosen by Jordan Kindler
RituSharmaRituSharma
In line no. 59 of cd_OpportunityLineItemTriggerHandlerv2 class, logic is adding 0 days to the Contract_Start_Date__c date field. You need to set the value of this field for the opportunity that you are creating in the test class(line no. 47) to fix the error. 

Alternatively, you may update cd_OpportunityLineItemTriggerHandlerv2 class to check value of Contract_Start_Date__c field. If it's null then bypass the addDays logic.

All Answers

RituSharmaRituSharma
System is throwing error for cd_OpportunityLineItemTrigger for AfterInsert scenario. So share the code of that trigger.
Jordan KindlerJordan Kindler
Full error message: System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, cd_OpportunityLineItemTrigger: execution of AfterInsert caused by: System.NullPointerException: Attempt to de-reference a null object Class.cd_OpportunityLineItemTriggerHandlerv2.syncSchedules: line 59, column 1 Class.cd_OpportunityLineItemTriggerHandlerv2.process: line 8, column 1 Trigger.cd_OpportunityLineItemTrigger: line 4, column 1: []
Stack Trace: Class.testClassForTrigger.triggerTest: line 51, column 1

Trigger 1: 

trigger cd_OpportunityTrigger on Opportunity (after update) {

    cd_OpportunityTriggerHandlerv2 th = new cd_OpportunityTriggerHandlerv2();
    th.process(Trigger.new, Trigger.oldMap);
}


Triggger that that one references^:
 
public class cd_OpportunityLineItemTriggerHandlerv2 {

    public void process(List<OpportunityLineItem> recs, Map<Id, OpportunityLineItem> oldRecs){

        switch on Trigger.operationType {

            when AFTER_INSERT, AFTER_UPDATE {
                syncSchedules(recs, oldRecs);
            }
        }
    }

    @TestVisible
    private void syncSchedules(List<OpportunityLineItem> recs, Map<Id, OpportunityLineItem> oldRecs){

        if(cd_TriggerControl.isFlagSet('SyncsDone')){
            System.debug('syncSchedules is already in this transaction');
            return;
        }

        if (!cd_TriggerControl.areTestsRunning() && !cd_TriggerControl.isFeatureEnabled('Sync Opp Product Schedules')){
            System.debug('syncSchedules is not enabled');
            return;
        }

        if (recs != null && !recs.isEmpty()){

            Set<Id> oliIdsToCheck = new Set<Id>();
            Map<Id, Boolean> prodIdsForScheds = new Map<Id, Boolean>();
            Map<Id, Date> oppIdToCloseDate = new Map<Id, Date>();

            for (OpportunityLineItem oli : recs){

                if (oldRecs == null
                        || (oli.UnitPrice != oldRecs.get(oli.Id).UnitPrice)
                        || (oli.Quantity != oldRecs.get(oli.Id).Quantity)){

                    System.debug('Qty or UnitPrice changed on OLI: ' + oli.Id);
                    oliIdsToCheck.add(oli.Id);
                    prodIdsForScheds.put(oli.Product2Id, false);
                    oppIdToCloseDate.put(oli.OpportunityId, null);
                }
            }

            System.debug('Have this many OLIs to delete: ' + oliIdsToCheck.size());

            if (!oliIdsToCheck.isEmpty()) {

                System.debug('Find which prods allow Revenue Scheds');
                for (Product2 p : [SELECT Id, CanUseRevenueSchedule
                                    FROM Product2
                                    WHERE Id IN :prodIdsForScheds.keySet()]) {
                    prodIdsForScheds.put(p.Id, p.CanUseRevenueSchedule);
                }

                for (Opportunity opp : [SELECT Id, Contract_Start_Date__c
                                    FROM Opportunity
                                    WHERE Id IN :oppIdToCloseDate.keySet()]) {
                    oppIdToCloseDate.put(opp.Id, opp.Contract_Start_Date__c.addDays(0));
                }

                List<OpportunityLineItemSchedule> schedsToDelete = new List<OpportunityLineItemSchedule>([SELECT Id
                                                                                                            FROM OpportunityLineItemSchedule
                                                                                                            WHERE OpportunityLineItemId IN :oliIdsToCheck]);

                System.debug('Have this many Scheds to delete: ' + schedsToDelete.size());

                System.debug('Prepare new Scheds to be created');
                List<OpportunityLineItemSchedule> schedsToInsert = new List<OpportunityLineItemSchedule>();

                for (OpportunityLineItem oli : recs) {

                    if (oliIdsToCheck.contains(oli.Id)){
                        System.debug('Creating scheds for OLI: ' + oli.Id);

                        for (Integer i = 0; i < oli.Quantity; i++){
                            schedsToInsert.add(new OpportunityLineItemSchedule(
                                    OpportunityLineItemId = oli.Id,
                                    Revenue = oli.UnitPrice,
                                    Type = 'Revenue',
                                    ScheduleDate = (oli.ServiceDate != null ? oli.ServiceDate : oppIdToCloseDate.get(oli.OpportunityId)).addYears(i)));
                        }
                    }
                }

                if (!schedsToDelete.isEmpty()) {
                    delete schedsToDelete;
                }

                System.debug('Have this many Scheds to insert: ' + schedsToInsert.size());
                if (!schedsToInsert.isEmpty()) {
                    insert schedsToInsert;
                }
            }
        }
    }
}

 
RituSharmaRituSharma
In line no. 59 of cd_OpportunityLineItemTriggerHandlerv2 class, logic is adding 0 days to the Contract_Start_Date__c date field. You need to set the value of this field for the opportunity that you are creating in the test class(line no. 47) to fix the error. 

Alternatively, you may update cd_OpportunityLineItemTriggerHandlerv2 class to check value of Contract_Start_Date__c field. If it's null then bypass the addDays logic.
This was selected as the best answer
Jordan KindlerJordan Kindler
THANK YOU!!!!