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
Don PierceDon Pierce 

Trigger error when attempting to delete a quote item

The error returned upon a delete of a Quote Line Item is:

There were custom validation error(s) encountered while saving the affected record(s). The first validation error encountered was "Apex trigger QuoteLineItemTrigger caused an unexpected exception, contact your administrator: QuoteLineItemTrigger: execution of AfterDelete caused by: System.NullPointerException: Attempt to de-reference a null object: Trigger.QuoteLineItemTrigger: line 12, column 1". 

This is the code, I tried after delete and before delete. It works fine for after insert and after update.

trigger QuoteLineItemTrigger on QuoteLineItem (after insert, after update, after delete){  
    
    // prevent recursion
    if (!QuoteLineItemUtility.TriggerIsRunning){
        QuoteLineItemUtility.TriggerIsRunning = true;

        Set<Id> QuoteIds = new Set<Id>();
 
        List<QuoteLineItem> lineItemsForUpdate = new List<QuoteLineItem>();

        // gather IDs first of quotes
       for (QuoteLineItem ql : trigger.new) {   // line 12
            
                 QuoteIds.add(ql.QuoteId);
        }

        if (!QuoteIds.isEmpty()) {
            // get all line items for all of the above quotes in bulk so that we don't hit governor limits
            Id prevQuoteId;
            Double lastLineNumber;
            // we can query all and these triggered records in an after trigger, nothing missing
            for (QuoteLineItem ql : [Select Id, Item_Numbering__c,QuoteId,SortOrder
                                       From QuoteLineItem 
                                      Where QuoteId in :QuoteIds
//                                   Order By ProductName__c NULLS LAST]) {
//                                   Order By Item_Numbering__c NULLS LAST]) {
                                   Order By SortOrder  ASC NULLS LAST]) {

                // These are coming in already grouped by the same quote
                // and are sorted by the line number within that group
                
                if (prevQuoteId == null || prevQuoteId != ql.QuoteId) {

                    // start fresh because this is the first iteration OR we made it to 
                    // another group of line items
                    prevQuoteId = ql.QuoteId;
                    lastLineNumber = 0.0; //back to default                   
                }

                // Set the new line numbers as needed
//                if(ql.Item_Numbering__c == null || ql.Item_Numbering__c <= lastLineNumber ) {
//               if(ql.Item_Numbering__c == null || ql.Item_Numbering__c == 0) {

                    ql.Item_Numbering__c = lastLineNumber + 1;
                    
                    // Need to create a "new" in memory line item to break reference to the 
                    // trigger reference, otherwise you will get an error like "cannot update in an After trigger"
 //                   lineItemsForUpdate.add(new QuoteLineItem(id = ql.id, Item_Numbering__c = ql.SortOrder));
                    lineItemsForUpdate.add(new QuoteLineItem(id = ql.id, Item_Numbering__c = ql.Item_Numbering__c));
 //               }
                
                lastLineNumber = ql.Item_Numbering__c;

            } // end for

        }

        if (!lineItemsForUpdate.isEmpty())
            update lineItemsForUpdate; // DML only the changed line items

        QuoteLineItemUtility.TriggerIsRunning = false;
    }
}
 
Best Answer chosen by Don Pierce
Glyn Anderson 3Glyn Anderson 3
The delete events don't have a Trigger.new collection, only Trigger.old.  Change line 12 to be:

<pre>
        // gather IDs first of quotes
       for (QuoteLineItem ql : trigger.isDelete ? trigger.old : trigger.new) {   // line 12
            
                 QuoteIds.add(ql.QuoteId);
        }
</pre>

All Answers

Glyn Anderson 3Glyn Anderson 3
The delete events don't have a Trigger.new collection, only Trigger.old.  Change line 12 to be:

<pre>
        // gather IDs first of quotes
       for (QuoteLineItem ql : trigger.isDelete ? trigger.old : trigger.new) {   // line 12
            
                 QuoteIds.add(ql.QuoteId);
        }
</pre>
This was selected as the best answer
Don PierceDon Pierce
Thank you.  Sorry for my inexperience on this.