Salesforce Roll-Up Summary Trigger Revised

  • submit to reddit
Salesforce Roll-Up Summary Trigger

Salesforce Roll-Up Summary Trigger

Why on earth would anybody want a Salesforce trigger to perform a roll-up summary type function when Salesforce already provides you with Roll-Up Summary fields?

The answer may not be apparent until you begin to be inhibited by the limitations of Roll-Up Summary fields. So what are these limitations?

  • Objects have a limit of 10 maximum roll-up summary fields
  • Objects on the master side of a master-detail relationship can have roll-up summary fields
  • Lookup relationships do not support roll-up summary fields
  • Long text area, multi-select picklist, and system fields are not supported as filters or bases for roll-up summary fields
  • Campaign roll-up summary fields do not recalculate values when Lead or Contacts are deleted

Colin Loretz and Jeff Douglas have both developed very similar solutions for combating these challenges through the use of Salesforce apex triggers:

However, both approaches still face some challenges:

  • Governor Limits – If their list<> contains more than the allowed amount (currently 10,000) then an exception will be thrown
  • Invalid Query Locator – Colin’s solutions relies on sub-query (related record) calls, which tend to break when processing thousands of records.

To address these challenges I put together an apex trigger that reduces the size of my list by taking advantage of sets, the SOQL SUM and Group By functions and the AggregateResult sObject.  I also used maps to retrieve my sum totals which eliminates the invalid query locator errors.

The following trigger sums a number field on a custom object and then updates an Opportunity number field with the total. The structure is as follows:

  • Opportunity
    • Payments (Lookup Relationship on Opportunity__c)

Salesforce Roll-Up Summary Trigger

trigger OpportunityRollUpPayments on Payment__c (after delete, after insert, after update) {

  //Limit the size of list by using Sets which do not contain duplicate elements
  set OpportunityIds = new set();

  //When adding new payments or updating existing payments
  if(trigger.isInsert || trigger.isUpdate){
    for(Payment__c p : trigger.new){
      OpportunityIds.add(p.Opportunity__c);
    }
  }

  //When deleting payments
  if(trigger.isDelete){
    for(Payment__c p : trigger.old){
      OpportunityIds.add(p.Opportunity__c);
    }
  }

  //Map will contain one Opportunity Id to one sum value
  map OpportunityMap = new map ();

  //Produce a sum of Payments__c and add them to the map
  //use group by to have a single Opportunity Id with a single sum value
  for(AggregateResult q : [select Opportunity__c,sum(Amount__c)
    from Payment__c where Opportunity__c IN :OpportunityIds group by Opportunity__c]){
      OpportunityMap.put((Id)q.get('Opportunity__c'),(Double)q.get('expr0'));
  }

  List OpportunitiesToUpdate = new List();

  //Run the for loop on Opportunity using the non-duplicate set of Opportunities Ids
  //Get the sum value from the map and create a list of Opportunities to update
  for(Opportunity o : [Select Id, Total_Payments__c from Opportunity where Id IN :OpportunityIds]){
    Double PaymentSum = OpportunityMap.get(o.Id);
    o.Total_Payments__c = PaymentSum;
    OpportunitiesToUpdate.add(o);
  }

  update OpportunitiesToUpdate;
}

I have tested this method and have successfully updated over 10,000 Opportunity records with over 35,000 payment records through the bulk-api, so I feel good about it. When I get around to it I’ll write up the test class and publish it here.

Update: Here’s the test class.

@isTest
private class TestOpportunityRollUpPayments {

    static testMethod void myUnitTest() {

        Profile pf = [Select Id from Profile where Name = 'System Administrator'];

        User u = new User();
        u.FirstName = 'Test';
        u.LastName = 'User';
        u.Email = 'testuser@test123456789.com';
        u.CompanyName = 'test.com';
        u.Title = 'Test User';
        u.Username = 'testuser@test123456789.com';
        u.Alias = 'testuser';
        u.CommunityNickname = 'Test User';
        u.TimeZoneSidKey = 'America/Mexico_City';
        u.LocaleSidKey = 'en_US';
        u.EmailEncodingKey = 'ISO-8859-1';
        u.ProfileId = pf.Id;
        u.LanguageLocaleKey = 'en_US';
        insert u;

        system.runAs(u){

            Opportunity o = new Opportunity();
            o.Name = 'Test Opportunity';
            o.StageName = 'Closed Won';
            o.CloseDate = system.today();
            insert o;

            system.assertEquals(o.Total_Payments__c, null);

            //Test payments on insert
            Payment__c p1 = new Payment__c();
            p1.Opportunity__c = o.Id;
            p1.Amount__c = 100;
            insert p1;

            Opportunity ou1 = [select Total_Payments__c from Opportunity where Id = :o.Id];
            system.assertEquals(ou1.Total_Payments__c,p1.Amount__c);

            //Test payments on update
            Payment__c p1u = [select Amount__c from Payment__c where Id = :p1.Id];
            p1u.Amount__c = 200;
            update p1u;

            Opportunity ou2 = [select Total_Payments__c from Opportunity where Id = :o.Id];
            system.assertEquals(ou2.Total_Payments__c,p1u.Amount__c);

            //Test payments on second insert
            Payment__c p2 = new Payment__c();
            p2.Opportunity__c = o.Id;
            p2.Amount__c = 800;
            insert p2;

            AggregateResult ag1 = [select sum(Amount__c) from Payment__c where Opportunity__c = :o.Id];

            Opportunity ou3 = [select Total_Payments__c from Opportunity where Id = :o.Id];
            system.assertEquals(ou3.Total_Payments__c,ag1.get('expr0'));

            //Test payment on delete
            delete p2;

            AggregateResult ag2 = [select sum(Amount__c) from Payment__c where Opportunity__c = :o.Id];

            Opportunity ou4 = [select Total_Payments__c from Opportunity where Id = :o.Id];
            system.assertEquals(ou4.Total_Payments__c,ag2.get('expr0'));

        }

    }

}

To see this trigger in action jump over to the roll-up summary trigger demo.

Do you see any holes in my code? Please point them out in the comment section below :)

Update: I’ve re-purposed this trigger in order to create a generic utility for performing roll-up summaries. Please see: Salesforce Roll-Up Summary Utility For Lookup Fields With Filter.


I have been working with the Salesforce.com platform since 2003 in both administrative and development roles. I also have experience in web design working with HTML, CSS, Javascript, and PHP. I hold certification for the Salesforce.com Developer program. I am also an employee of Model Metrics, a Salesforce.com company.

  • Benjaminplunkett

    Hi Anthony,

    Thanks for this code, I think it’s just what I’m after. I’m new to apex and code in general so I was wondering if you could assist with an error that I keep getting with it.

    Now the object I am rolling up has a master detail relation ship with the parent (both custom objects). The reason I have not used a normal roll up summary field is that I wish to track changes to the roll up in a chatter feed.

    The error relates to the first image below. the error I get is in the second image. The complete adapted trigger is in the 3rd.

    Any assistance would be awesome

    Thanks

    Ben

  • Ben

    Sorry I forgot to add the full trigger

  • Anonymous

    Benjamin,

    Try using Double instead of Integer. Aggregate sums are returned as Double anyways.

    map ChangeRequestMap = new map ();

    If you’re still experiencing the same problem, feel free to email me the full code to anthony.victorio@gmail.com so I can try it out on my end :)

  • Anonymous

    Benjamin,

    Try using Double instead of Integer. Aggregate sums are returned as Double anyways.

    map ChangeRequestMap = new map ();

    If you’re still experiencing the same problem, feel free to email me the full code to anthony.victorio@gmail.com so I can try it out on my end :)

  • Ben

    Hey, yes I tried that first but got the same error. As it happens I have tried a different approach with has actually worked out better for what I wanted.

    a) a normal roll up for the count
    b) trigger to update a date/time field on the parent each time a new child is added, which can be displayed on the chatter feed

    thanks for your help

  • colemab

    Outstanding post from a functionality standpoint and A++ post from a write-up standpoint. Thank you sir for the excellent lesson.

  • Sonu

    Thanks Anthony,
    This helped me a lot..but i have quick question.. i need to put filter on the Amount__c field. how can i do that?? can you please help me out with this issue..

    thanks,

  • SACHIN AGARWAL

    I think when you create a trigger to maintain value as like roll-up summary field,
    then trigger on “UNDELETE” is also required
    otherwise it update the wrong value when we undelete the child record.

  • http://www.anthonyvictorio.com Anthony Victorio

    See line 25 and 26 where the aggregate query is located. In there you can add a “where” statement for your filter. For example:

    [select Opportunity__c,sum(Amount__c) from Payment__c where Opportunity__c IN :OpportunityIds and Category = ‘Filtered Category’ group by Opportunity__c]

    In the above example ” Category = ‘Filtered Category’ ” is our filter.

  • http://www.anthonyvictorio.com Anthony Victorio

    Sachin, you’re absolutely correct. I’ll update the trigger and post the revision soon.

  • Sonu

    thanks for helping me out. 
    i was not able to filter it out. i have field called manager__c text field. critiria is manager__c contains “TR” and status is active sum the Amount field and update it into the parent object. can you please help me out how to use the contains data type here..

    thanks, 

  • Sonu

    I have 1 more question. how can we use this code to rollup more than one field??

  • Sidagarwal22

    Hey Anthony
    Nice post, I have a quick question.What if i am using Max aggregate function, and want the Id of the Payment record which contains the Max Amount.Right now the following SOQl returns the Oppurtunity ID with Expr0.I need, Oppurtunity ID, PaymentID with Expr0.Is that possible?

    Thanks
    Sid

  • indy

    trigger AccountRollUpContracts on Contract (after delete, after insert, after update) {

      //Limit the size of list by using Sets which do not contain duplicate elements
      set AccountIds= new set();

      //When adding new payments or updating existing payments
      if(trigger.isInsert || trigger.isUpdate){
        for(Contract p : trigger.new){
          AccountIds.add(p.Account);
        }
      }

      //When deleting payments
      if(trigger.isDelete){
        for(Contract p : trigger.old){
          AccountIds.add(p.Account);
        }
      }

      //Map will contain one Account Id to one sum value
      map AccountMap = new map ();

      //Produce a sum of Contracts and add them to the map
      //use group by to have a single Account Id with a single sum value
      for(AggregateResult q : [select Account,sum(Amount__c)
        from Contract where Account IN :AccountIdsgroup group by Account]){
          AccountMap.put((Id)q.get(‘Account’),(Double)q.get(‘expr0′));
      }

      List AccountToUpdate = new List();

      //Run the for loop on Account using the non-duplicate set of Opportunities Ids
      //Get the sum value from the map and create a list of Opportunities to update
      for(Account o : [Select Id, Contract_Count__c from Account where Id IN :AccountIds]){
        Double PaymentSum = AccountMap.get(o.Id);
        o.Amount__c= PaymentSum;
        AccountToUpdate .add(o);
      }

      update AccountToUpdate;
    }

    I am having and issue in line 25:
    //use group by to have a single Account Id with a single sum value

      for(AggregateResult q : [select Account,sum(Amount__c)

    Amount__c is a Contract custom number field

    Error: Compile Error: Invalid field: ‘Account’ at line 25 column 27
    Thank you!!

  • indy

    trigger AccountRollUpContracts on Contract (after delete, after insert, after update) {

      //Limit the size of list by using Sets which do not contain duplicate elements
      set AccountIds= new set();

      //When adding new payments or updating existing payments
      if(trigger.isInsert || trigger.isUpdate){
        for(Contract p : trigger.new){
          AccountIds.add(p.Account);
        }
      }

      //When deleting payments
      if(trigger.isDelete){
        for(Contract p : trigger.old){
          AccountIds.add(p.Account);
        }
      }

      //Map will contain one Account Id to one sum value
      map AccountMap = new map ();

      //Produce a sum of Contracts and add them to the map
      //use group by to have a single Account Id with a single sum value
      for(AggregateResult q : [select Account,sum(Amount__c)
        from Contract where Account IN :AccountIdsgroup group by Account]){
          AccountMap.put((Id)q.get(‘Account’),(Double)q.get(‘expr0′));
      }

      List AccountToUpdate = new List();

      //Run the for loop on Account using the non-duplicate set of Opportunities Ids
      //Get the sum value from the map and create a list of Opportunities to update
      for(Account o : [Select Id, Contract_Count__c from Account where Id IN :AccountIds]){
        Double PaymentSum = AccountMap.get(o.Id);
        o.Amount__c= PaymentSum;
        AccountToUpdate .add(o);
      }

      update AccountToUpdate;
    }

    ______________________________________________________________________ç

    I am having and issue in line 25:
    //use group by to have a single Account Id with a single sum value

      for(AggregateResult q : [select Account,sum(Amount__c)

    Amount__c is a Contract custom number field

    Error: Compile Error: Invalid field: ‘Account’ at line 25 column 27

    Thank you!!

  • Marco

    When updating child and update of payment (child) is actually changing opportunity (parent) from one opportunity to another, i belive it is necessary also to update also “old” parent. So

    something like this need to be added

      if(trigger.isUpdate){

        for(Payment__c p : trigger.old){

          OpportunityIds.add(p.Opportunity__c);

        }

    after

      if(trigger.isInsert || trigger.isUpdate){    for(Payment__c p : trigger.new){
          OpportunityIds.add(p.Opportunity__c);
    }

  • David Cheng

    Hello Anthony.  This is an excellent post, but there is a hidden bug.  If you delete the last payment record on the opp, the summary does not calculate because the AggregateResult query finds 0 payment records for the opp and thus does not include the opp.

    My approach is: before the aggregateresult query, I create a map of opp records where each opp record contains the opp ID and a nulled-out summary field.  Then I loop through the aggregateresult records and assign the values to the appropriate opps.  Finally I run  update the map.values().  That way, if an opp’s last payment was deleted, the summary is  is correctly zeroed/nulled out.

  • Praveen Jaswal

    Thanks for providing this code. I tweaked the provided code as per my requirement and tested it in my Sandbox environment but while Test class is not getting deployed in production. Below i have pasted my code of Test Class and error message as well

    Code :

    //Test RFP on second insert            RFP__c p2 = new RFP__c();            p2.Supplier_Account__c = o.Id;            p2.Name = ‘Test RFP2′;            p2.RFP_Code__c = ‘Test Code2′;            p2.Unique_Code__c = ‘Test Unique Code2′;            p2.Status__c = ‘Awaiting Proposal';            insert p2;

                AggregateResult ag1 = [select sum(RFP_Value__c) from RFP__c where Supplier_Account__c = :o.Id];

                Account ou3 = [select Value_of_RFPs_Received_New__c from Account where Id = :o.Id];            system.assertEquals(ou3.Value_of_RFPs_Received_New__c,ag1.get(‘expr0′));

                //Test RFP on delete            delete p2;
                AggregateResult ag2 = [select sum(RFP_Value__c) from RFP__c where Supplier_Account__c = :o.Id];
                Account ou4 = [select Value_of_RFPs_Received_New__c from Account where Id = :o.Id];            system.assertEquals(ou4.Value_of_RFPs_Received_New__c,ag2.get(‘expr0′));

    Error Message :

    Failure Message: “System.AssertException: Assertion Failed: Expected: null, Actual: 0.0″, Failure Stack Trace: “Class.TestRollUpofTotalRFPsReceivedNew1.myUnitTest: line 64, column 1″

    Line 64 is “system.assertEquals(ou3.Value_of_RFPs_Received_New__c,ag1.get(‘expr0′));”

    Please let me know what is wrong with this code.

  • Praveen Jaswal

    Hi – I am getting below pasted error while deploying the triggers.

    System.LimitException: Too many SOQL queries: 101″,

    Is there any workaround for this.

    Regards,
    Praveen Jaswal

  • http://www.anthonyvictorio.com Anthony Victorio

    Is that error caused by this trigger specifically? It sounds like you might have another trigger that’s performing queries inside of a for loop. 

  • http://www.anthonyvictorio.com Anthony Victorio

    Thank you for pointing out the bug David, I’ve fixed it in a new version of the code I published today, though I used a different method. When evaluating the results from map.get method I supply a value of 0 if the map is null, and if it’s not then I provide the map value. 

  • http://www.anthonyvictorio.com Anthony Victorio

    Hello guys, sorry for not staying on top of this post and replying more quickly.  If anyone would like to take a look a the re-worked version that allows for some of the features you discussed here (filters, count, max, etc).  Please see 
    http://www.anthonyvictorio.com/salesforce/roll-up-summary-utility/

  • Praveen Jaswal

    Actually I have 9 roll-up fields at Account Level and I have created seperate trigger fo each field and then created a test class as well. Everything works fine in Sandbox but when i try them to deploy in production i am getting this error.

  • Pingback: Salesforce Roll-up Summary Utility for Lookup Fields with Filter

  • http://profile.yahoo.com/SND3FBG6T7SVFXXP4MCG3KXRJQ oNur…

    Hi David,

    Can you please share your approach?

    Thanks

  • http://profile.yahoo.com/SND3FBG6T7SVFXXP4MCG3KXRJQ oNur…

    Hi David,

    I figured out how to fix the bug. The updated code is below, you can review the additional code between the ***********************************

    I did not test it but I wrote a code like this myself and it worked for mine. If anyone catches a bug please feel free to update.

    trigger OpportunityRollUpPayments on Payment__c (after delete, after insert, after update) {   //Limit the size of list by using Sets which do not contain duplicate elements  set OpportunityIds = new set();   //When adding new payments or updating existing payments  if(trigger.isInsert || trigger.isUpdate){    for(Payment__c p : trigger.new){      OpportunityIds.add(p.Opportunity__c);    }  }   //When deleting payments  if(trigger.isDelete){    for(Payment__c p : trigger.old){      OpportunityIds.add(p.Opportunity__c);    }  }   //Map will contain one Opportunity Id to one sum value  map OpportunityMap = new map ();   //Produce a sum of Payments__c and add them to the map  //use group by to have a single Opportunity Id with a single sum value  for(AggregateResult q : [select Opportunity__c,sum(Amount__c)    from Payment__c where Opportunity__c IN :OpportunityIds group by Opportunity__c]){      OpportunityMap.put((Id)q.get(‘Opportunity__c’),(Double)q.get(‘expr0′));  }   List OpportunitiesToUpdate = new List();   //Run the for loop on Opportunity using the non-duplicate set of Opportunities Ids  //Get the sum value from the map and create a list of Opportunities to update  for(Opportunity o : [Select Id, Total_Payments__c from Opportunity where Id IN :OpportunityIds]){    Double PaymentSum = OpportunityMap.get(o.Id);  //***********************************************************************************************  if(OpportunityMap.get(o.Id) == null){ o.Total_Payments__c = 0; } else{  //***********************************************************************************************    o.Total_Payments__c = PaymentSum;  //***********************************************************************************************   }   //***********************************************************************************************    OpportunitiesToUpdate.add(o);  }   update OpportunitiesToUpdate;}

  • Bethriaria

    Hey anthony,

    Nice work there man.

    Caught up into a weird situation. I have implemented your solutions for the roll up summary and it worked fine when tested manually for insert/update and deleting the child record. But the problem comes when any DML operation is done through code.

    I have a penalty object child to the parent i.e. Opportunity. Opportunity has the this field called Penalties Amount that’s the roll up of the sum of the amount of all the penalties as child to Opportunity.

    Somehow the Roll up field doesn’t catch up the DML performed through code (inset/update in a controller on child). What could be the catch here?

    Thanks

  • http://www.facebook.com/rbearfield Ritchie Bearfield

    Hi Anthony,
     
    Sorry if this is an old blog item, but if I could get this working it would be really useful!
     
    In my Salesforce I have Accounts, these own Cases. Cases have Time logged against them. I need to sum up all the time spent on cases of each account.
     
    I would be very grateful if you could tell me if I have done this wrong!
     
    My objects are thus;
     
    Account
    {Name} Type = Text purpose = Unique ID
    Im trying to get your code to sum the {Total_Time_c) into {Support_hours_used__c}
                Case
                Each case has a value in hours {Total_Time__c}. This is a rollup of all the time iems.
                Lookup relationship to Account {Account Name}
                         Time_c (custom object).
                         Each Time
     
    Code;

    trigger AccountRollUpCase on Case (after delete, after
    insert, after update) {

      //Limit the size of
    list by using Sets which do not contain duplicate elements

      set
    Name = new set();

      //When adding new
    Case or updating existing Case

      if(trigger.isInsert
    || trigger.isUpdate){

        for(Case p :
    trigger.new){

         
    Name.add(p.Account);

        }

      }

      //When deleting Case

     
    if(trigger.isDelete){

        for(Case p :
    trigger.old){

         
    Name.add(p.Account);

        }

      }

      //Map will contain
    one Account Id to one sum value

      map AccountMap = new map ();

      //Produce a sum of
    Case and add them to the map

      //use group by to
    have a single Account Id with a single sum value

      for(AggregateResult
    q : [select Support_hours_used__c,sum(Total_Time__c)

        from Case where
    Account IN :Name group by Account]){

         
    AccountMap.put((Id)q.get(‘Account’),(Double)q.get(‘expr0′));

      }

      List
    AccountsToUpdate = new List();

      //Run the for loop
    on Account using the non-duplicate set of Accounts Ids

      //Get the sum value
    from the map and create a list of Accounts to update

      for(Account o :
    [Select Id, Total_Case from Account where Id IN :Name]){

        Double CaseSum =
    AccountMap.get(o.Id);

        o.Total_Case =
    CaseSum;

       
    AccountsToUpdate.add(o);

      }

      update
    AccountsToUpdate;

    }

    Error;
     
    Compile Error: Invalid field: ‘Support_hours_used__c’ at line 20 column 27

  • Tleahy

    I need help. BADLY I tried doing this, the apex trigger is making it impossible to edit anything, nothing can be done. edited. created. This is BAD, really really BAD, please help me get this trigger disabled, nothing works. When i try to disable it in my sandbox and push the changed to production it fails saying ”
    Average test coverage across all Apex Classes and Triggers is 72%, at least 75% test coverage is required.” I have no idea what that means.

  • http://www.anthonyvictorio.com/ Anthony Victorio

    You may need to ensure that your production environment has passing test coverage first. What error message are you receiving when you attempt to edit the records at hand. Also, feel free to post your trigger code and test classes on a service like
    http://pastie.org/ or
    http://codepad.org/ an share it here so I can diagnose. Otherwise, feel free to email me at anthony.victorio //at// gmail.com

  • http://www.anthonyvictorio.com/ Anthony Victorio

    Hi Ritchie. Some things may not have come across when you pasted your code. If you’re still having issues, I recommend using a service like http://pastie.org/ or http://codepad.org/.

    From what I can tell, there are a few things off with your trigger.

    1) Your case aggregate query is malformed. You need to group by [AccountID] not by [Account].
    2) Your case aggregate query has a field that’s not being aggregated = [Support_hours_used__c]. I’ve removed it, assuming that you only want the sum of [Total_Time__c]
    3) [Name] while I don’t believe is a reserved word, I recommend against using it to store the Ids of related Accounts.
    4) You’re missing the “__c” from the Account for loop. Should be [Total_Case__c] instead of [Total_Case].
    5) Finally I would add an IF clause to determine if you list of “AccountsToUpdate” actually contains records before attempting to update an empty list.

    Here’s the revised code: http://pastie.org/4212324

    I haven’t tested it, so please let me know if you run into any other issues.

  • http://www.anthonyvictorio.com/ Anthony Victorio

    Hi Bethriaria, is this an issue still? Sorry for responding so late! :(

  • Harika

    Hi Anthony,
    Can you tell me If I can use Similar Trigger for my Scenario as well:

    HarikaI have a custom Object Booking, and I am trying to capture the no. of total bookings(Custom field created in Contact Object) associated with that particular account or Contact… So when I click on Account or Contact of any Person or Agency , Is it possible to chk the no. of bookings made by that contact on the contact object …. There is no relation between Bookings and Account, but there is another custome object Passenger, where Passenger records are available in the related list!!

    I assume that I can use these no. of passenger records to determine the no. of bookings as they are equal…(no. of passenger records=no. of bookings for that acount or contact)… No M-D Relation in between objects!!

    I am not sure how do I Trigger this ??
    Thank you!!

  • hsupriya

    I am quite new to apex and triggers and stuck at a point.

    I have 2 objects Account(Standard) and DummyObject(Custom) and a junction object AccountDummy joining these 2. The junction object has a look-up on both Account and the DummyObject. There is a related list of Accounts on DummyObject and I want to have the count of these Accounts which I will store in a custom number field on my DUmmy Object.

    I searched for various solutions online but nothing seems to be working as I want. Ane help is greatly appreciated :)

  • semira

    I’m trying to sum up total amount of related list on Contact. On line 27 it gives me error

    OpportunityMap.put((Id)q.get(‘Opportunity__c’),(Double)q.get(‘expr0′));

    I’m not even sure what does put() method does to even fix it. What is ‘expr0’? If I’m summing up currency field do I still need double?

  • Lisa Horne

    Anthony, Could you please help fix the error I am getting. I want to create a Roll up Summary trigger on the Account Page (Total_Active_Contracts__c field) from Contracts(Active_Contract_Count__c Field).

    I am getting this error:
    Error Error: Compile Error: Invalid field: ‘Account’ at line 25 column 27

    trigger ContractRollUpActiveContractCount on Account (after delete, after insert, after update) {

    //Limit the size of list by using Sets which do not contain duplicate elements
    set AccountIds = new set();

    //When adding new Contracts or updating existing Contracts
    if(trigger.isInsert || trigger.isUpdate){
    for(Contract p : trigger.new){
    AccountIds.add(p.Account);
    }
    }

    //When deleting Contracts
    if(trigger.isDelete){
    for(Contract p : trigger.old){
    AccountIds.add(p.Account);
    }
    }

    //Map will contain one Contract Id to one sum value
    map AccountMap = new map ();

    //Produce a sum of Total_Active_Contracts__c and add them to the map
    //use group by to have a single Contract Id with a single sum value
    for(AggregateResult q : [select Account,sum(Active_Contract_Count__c)
    from Contract where Account IN :AccountIdsgroup group by Account]){
    AccountMap.put((Id)q.get(‘Account’),(Double)q.get(‘expr0′));
    }

    List AccountsToUpdate = new List();

    //Run the for loop on Contract using the non-duplicate set of Contract Ids
    //Get the sum value from the map and create a list of Opportunities to update
    for(Account o : [Select Id, Total_Active_Contracts__c from Account where Id IN :AccountIds]){
    Double Active_Contract_Count__cSum = AccountMap.get(o.Id);
    o.Total_Active_Contracts__c = ContractSum;
    AccountToUpdate.add(o);
    }

    update AccountToUpdate;
    }

  • Matti Lakshminarayana

    Hi Anthony,

    Thanks for your post.
    i would like know what if i add after undelete event in this program,.will it work same or do we need to do some changes.

  • Sindoora Gopagoni

    Hi Anthony, Nice work. In this code the result will return the value in default org value. so if user want to have userdefine curreny then we can go with currencyconvert command on overall sum value. correct me if i go wrong

Read previous post:
Salesforce Apex / Visualforce Syntax Highlighter
Salesforce Apex & VisualForce Syntax Highlighter for WordPress

If you've ever used a search engine to find help on Salesforce development, then you're probably familiar with Jeff Douglas....

Close