[SalesForce] Trigger to update Account running total upon change to any child custom Invoice object

i have 3 objects: invoice,invoice line item & standard Account.

relationships:

  • invoice & invoice line item—>master-detail.

  • Account & invoice—>lookup.

On the invoice object i have one Rollup summary field called total price(sum of all prices on invoice line item).

On account i have 1 field called Account_balance

On the save event of a invoice line item i want to update Account_balance field with rollup summary value of invoice object.

Is this possible with a trigger ?

Best Answer

This is definitely possible with a trigger. To give you some pseudo code, I would write your trigger on the Invoice__c object. It will handle any updates of the Invoice_Line_Item__c object because of the rollup summary. You will want to have something like:

trigger InvoiceTrigger on Invoice__c (after insert, after update) {
    if(Trigger.isAfter && (Trigger.isInsert || Trigger.isUpdate)){
        InvoiceTriggerHandler.updateAccountBalance(Trigger.newMap);
    }
}

public class InvoiceTriggerHandler{
    public static void updateAccountBalance(Map<Id, Invoice__c> invoices){
        AggregateResult[] results = [
            SELECT 
                Account__c, SUM(Total_Price__c)
            FROM
                Invoice__c 
            WHERE 
                Id IN :invoices.keySet 
            GROUP BY 
                Account__c
        ];
        Set<Account> accountsToUpdate = new Set<Account>();
        for(AggregateResult result:results){
            accountsToUpdate.add(new Account(
                Id = result.get('Account__c'), 
                Account_Balance__c = result.get('expr0')
            );
        }
        update accountsToUpdate;
    }
}

You will have to clean that up and write your own tests, but that is the general idea. Every time an Invoice_Line_Item__c is updated and it changes the rollup summary field, this trigger will fire to update the account. There is some additional logic you may want to add, such as checking the old value of the Total_Price__c field with the new value and only running through Accounts who have had Invoice__c changes rather than all of them. There may be some other ways to tweak this as well, I just quickly wrote this up. Keep in mind this is not production ready by any means, but I hope this points you in the right direction.

The approach above utilizes aggregate functions and setting Id fields for update.


EDIT: I originally had the following code, which should still work, but the above is more optimal.

trigger InvoiceTrigger on Invoice__c (after insert, after update) {
    if(Trigger.isAfter && (Trigger.isInsert || Trigger.isUpdate)){
        InvoiceTriggerHandler.updateAccountBalance(Trigger.new);
    }
}

public class InvoiceTriggerHandler{
    public static void updateAccountBalance(List<Invoice__c> invoices){
        Set<Id> accountIds = new Set<Id>();
        for(Invoice__c invoice:invoices){
            accountIds.add(invoice.Account__c);
        }
        List<Account> accounts = [SELECT Id, Account_Balance__c, (SELECT Id, Total_Price__c FROM Invoices__r) FROM Account WHERE Id IN :accountIds];
        for(Account acc:accounts){
            acc.Account_Balance__c = 0;
            for(Invoice__c invoice:acc.Invoices__r){
                acc.Account_Balance__c += invoice.Total_Price__c;
            }
        }
        update accounts;
    }
}
Related Topic