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
Stephanie ArceStephanie Arce 

After Update Trigger Failing

When I try to do a mass update of records, this trigger fails on about half of them on line 56, "argument cannot be null".

When these records are created, Invoice__c isn't populated until later. I have no problem creating the records, it's just when I try to update them to give Invoice__c a value that half fail. Cost__c is a required field and never null.

I've checked through a debug log that I'm not close to any limits. Can anyone help me figure out what's wrong?

Here is the trigger:
trigger Line_Item_Invoice_RollupTrigger on Line_Item__c (after update, after insert, after delete) {
     Map<Id, Double> LineItemTotal = new Map<Id, Double>();
     Map<Id, Double> LineItemTotalAdjusted = new Map<Id, Double>();
     Map<Id, Double> NumberofLineItems = new Map<Id, Double>();
     Double count = 0;
     List<Invoice__c> invoicesToUpdate = new List<Invoice__c>();
     List<Line_Item__c> itemsForInvoice;
     List<Line_Item__c> items;
     if (trigger.isDelete) {
         items = trigger.old;
     }
     else {
         items = trigger.new;
    }
    
    // Go through all line items that the trigger is acting on.
    Set<ID> setInvoiceId = new Set<ID>();
    for (Line_Item__c triggerItem: items) {       

            // Get the invoice's ID for the line item and then
            // ensure its ID exists in the line item / line item adjusted totals
            // maps and their totals default to $0.00.        
        if (!LineItemTotal.containsKey(triggerItem.Invoice__c)) {
            LineItemTotal.put(triggerItem.Invoice__c, 0.0);
        }
        if (!LineItemTotalAdjusted.containsKey(triggerItem.Invoice__c)) {
            LineItemTotalAdjusted.put(triggerItem.Invoice__c, 0.0);
        }
        if (!NumberofLineItems.containsKey(triggerItem.Invoice__c)) {
            NumberofLineItems.put(triggerItem.Invoice__c, 0.0);
        }
        
        
        
        if(triggerItem.Invoice__c != NULL)
            setInvoiceId.add(triggerItem.Invoice__c);
    }
    
    // Sum the total cost of the line items
    // for the current invoice (see invoice above).
    //
    // 1. Get all of the line items for the invoice.
    // 2. For each line item update the mapping for the invoice 
    //    to be (previous total + total cost).    
    List<Line_Item__c> lstInvLineItem_LineItemTotal = new List<Line_Item__c>();
    
    if(setInvoiceId.size()>0){
        lstInvLineItem_LineItemTotal = [SELECT Id, Cost__c, Total_Cost_incl_Adjustment__c, Invoice__c FROM Line_Item__c
                WHERE Invoice__c IN :setInvoiceId];

    }
    // If the list has records, add those IDs and totals to the map.
    if(lstInvLineItem_LineItemTotal.size()>0){
        for(Line_Item__c item:lstInvLineItem_LineItemTotal){ 
            if(item.Invoice__c != NULL && LineItemTotal.containsKey(item.Invoice__c))    {
                LineItemTotal.put(item.Invoice__c, LineItemTotal.get(item.Invoice__c) + item.Cost__c); 
                LineItemTotalAdjusted.put(item.Invoice__c, 
                    LineItemTotalAdjusted.get(item.Invoice__c) + item.Total_Cost_incl_Adjustment__c); 
                NumberofLineItems.put(item.Invoice__c, NumberofLineItems.get(item.Invoice__c)+1);
            }
        }
    }
    
    List<Id> invoices = new List<Id>();
    for (Id previous : LineItemTotal.keyset()) {
        invoices.add(previous);
    }
    for (Id current : LineItemTotal.keyset()) {
        if (!LineItemTotal.containsKey(current)) {
            invoices.add(current);
        }
    }
    // Get a list of all invoices where its Id is in the invoices map.
    List<Invoice__c> lstInvoices = new List<Invoice__c>();
    if(invoices.size()>0){
        lstInvoices = [SELECT Id, Line_Item_Total__c, Line_Item_Total_Adjusted__c, Number_of_Line_Items__c
             FROM Invoice__c WHERE Id IN :invoices];
    }
    // Update the map with line item and line item adjusted totals.
    if(lstInvoices.size()>0){
        for(Invoice__c invoice:lstInvoices){
            if (LineItemTotal.containsKey(invoice.id)) {
                invoice.Line_Item_Total__c = LineItemTotal.get(invoice.id);
            }
            
            if (LineItemTotalAdjusted.containsKey(invoice.id)) {
                invoice.Line_Item_Total_Adjusted__c = LineItemTotalAdjusted.get(invoice.id);
            }
            
            if (NumberofLineItems.containsKey(invoice.id)) {
                invoice.Number_of_Line_Items__c = NumberofLineItems.get(invoice.id);
            }
            
            invoicesToUpdate.add(invoice);
        }
    }
    update invoicesToUpdate;
}

kaustav goswamikaustav goswami
The cost field is a required field from system level or from the page layout? Have you looked at the data extract to make sure tha tall the records have the cost__c field populated? Can you give a debug just before the line and see the values for each iteration?

Another thing i noticed is that in line 68 you are iterating over the key set of a map the checking if the key exists then you do not add anything to the invoices list else you add it. So in this loop the control is never going to go into. You may end up in an unreachable piece of code.

Thanks,
Kaustav
Vatsal KothariVatsal Kothari
Hi Stephanie,

You can refer below updated code:

trigger Line_Item_Invoice_RollupTrigger on Line_Item__c (after update, after insert, after delete) {
     Map<Id, Double> LineItemTotal = new Map<Id, Double>();
     Map<Id, Double> LineItemTotalAdjusted = new Map<Id, Double>();
     Map<Id, Double> NumberofLineItems = new Map<Id, Double>();
     List<Invoice__c> invoicesToUpdate = new List<Invoice__c>();
     List<Line_Item__c> items;
     if (trigger.isDelete) {
         items = trigger.old;
     }
     else {
         items = trigger.new;
    }
    
	for(Line_Item__c item:items){ 
		if(item.Invoice__c != NULL && LineItemTotal.containsKey(item.Invoice__c)) {
			LineItemTotal.put(item.Invoice__c, LineItemTotal.get(item.Invoice__c) + (item.Cost__c != null ? item.Cost__c : 0)); 
		}else{
			LineItemTotal.put(item.Invoice__c, 0.0);
		}
		
		if(item.Invoice__c != NULL && LineItemTotalAdjusted.containsKey(item.Invoice__c)){
			LineItemTotalAdjusted.put(item.Invoice__c, LineItemTotalAdjusted.get(item.Invoice__c) + 
											(item.Total_Cost_incl_Adjustment__c != null ? item.Total_Cost_incl_Adjustment__c : 0)); 
		}else{
			LineItemTotalAdjusted.put(item.Invoice__c, 0.0);
		}
		
		if(item.Invoice__c != NULL && NumberofLineItems.containsKey(item.Invoice__c)){
			NumberofLineItems.put(item.Invoice__c, NumberofLineItems.get(item.Invoice__c)+1);
		}else{
			NumberofLineItems.put(item.Invoice__c, 0.0);
		}
		
		if(item.Invoice__c != null){
			invoices.add(item.Invoice__c);
		}
	}

	for(Invoice__c invoice:[SELECT Id, Line_Item_Total__c, Line_Item_Total_Adjusted__c, Number_of_Line_Items__c FROM Invoice__c WHERE Id IN :invoices]){
		if (LineItemTotal.containsKey(invoice.id) && LineItemTotal.containsKey(invoice.id) != null) {
			invoice.Line_Item_Total__c = LineItemTotal.get(invoice.id);
		}
		
		if (LineItemTotalAdjusted.containsKey(invoice.id) && LineItemTotalAdjusted.containsKey(invoice.id) != null) {
			invoice.Line_Item_Total_Adjusted__c = LineItemTotalAdjusted.get(invoice.id);
		}
		
		if (NumberofLineItems.containsKey(invoice.id) && NumberofLineItems.containsKey(invoice.id) != null) {
			invoice.Number_of_Line_Items__c = NumberofLineItems.get(invoice.id);
		}
		invoicesToUpdate.add(invoice);
	}

	if(invoicesToUpdate.size() > 0){
		update invoicesToUpdate;
	}
}

If this solves your problem, kindly mark it as the best answer.

Thanks,
Vatsal