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
sonam gupthasonam guptha 

Total Amount opportunites print on Account.

Hi,

In My account object  “total_ amount__c" field is there,and in opportunity "amount" field  is there,
I want to dispaly sum of amount of all child  opportunities in the total _amount__c field in the parent account.
I written below trigger which is working fine,but here i need to fire this trigger when opportunity.stagename is set to closed won,but its not working accordingly.its firing for all the stages.
Can anyone help me to fix this.
 
trigger totalamount on Account (before insert,before update) {
  List<opportunity> Lstopp = [Select id,stagename from opportunity];
     for(Account record: Trigger.new) {
       record.total_Amount__c = null;
     }  
     for(Opportunity opp : Lstopp){
      if(opp.stagename == ‘Closed - won'){
     for(AggregateResult result: [SELECT SUM(Amount) Amt, AccountId Id FROM opportunity WHERE AccountId IN :Trigger.new GROUP BY AccountId]) { 
        Trigger.newMap.get((Id)result.get('Id')).Sum_of_Opportunity_Amount__c = (Decimal)result.get('Amt');
     }
   }
  }

Thanks Everyone!
Best Answer chosen by sonam guptha
LBKLBK
I guess the trigger has to be on Opportunity object to achieve the result when the stage is changed.

Here is the sample code.
 
trigger UpdateTotalAmount on Opportunity (after insert,after update) {
     List<Id> lstAccountIDs = new List<Id>();
     for(Opportunity opp: Trigger.new) {
       lstAccountIDs.add(opp.AccountId);
     }
     
     Map<Id, Account> mapAccount = new Map<Id, Account>([SELECT Id, Name, Sum_of_Opportunity_Amount__c FROM Account WHERE Id =:lstAccountIDs]);

     List<Account> lstAccounts = new List<Account>();
     for(AggregateResult result: [SELECT SUM(Amount) Amt, AccountId FROM Opportunity GROUP BY AccountId, StageName Having AccountId IN :mapAccount.keyset() AND StageName = 'Closed Won' ]) { 
        Account acc = mapAccount.get((Id)result.get('AccountID'));
        acc.Sum_of_Opportunity_Amount__c = (Decimal)result.get('Amt');
        lstAccounts.add(acc);
     }
     if(lstAccounts.size() > 0){
        update lstAccounts;
     }
   }
Also, your trigger is not bulkified to handle Bulk Insert or Update of the Accounts.

Hope this helps.
 

All Answers

brahmaji tammanabrahmaji tammana
You should write a trigger on Opportunity as you insert or update opp record.

Here is the sample code:
 
trigger SumOfOppAmount on Opportunity (after insert, after update) {
    
    Set<Id> accId = new Set<Id>();
    for(Opportunity o:Trigger.new){
        accId.add(o.AccountId);
    }
    
    List<Account> accList = [select Id, name, (select Amount, Id from Opportunities) from Account where id in:accId];
    List<Account> accListUpd = new List<Account>();
    for(Account a : accList){
        decimal oppamount = 0;
        for(Opportunity o: a.Opportunities){            
            oppamount = oppamount + o.Amount;            
        }
        a.total_Amount__c = oppamount;
        accListUpd.add(a);
    }
    
    update accListUpd;

}

If it works, Mark it as best answer.

Thanks
Brahma
 
LBKLBK
I guess the trigger has to be on Opportunity object to achieve the result when the stage is changed.

Here is the sample code.
 
trigger UpdateTotalAmount on Opportunity (after insert,after update) {
     List<Id> lstAccountIDs = new List<Id>();
     for(Opportunity opp: Trigger.new) {
       lstAccountIDs.add(opp.AccountId);
     }
     
     Map<Id, Account> mapAccount = new Map<Id, Account>([SELECT Id, Name, Sum_of_Opportunity_Amount__c FROM Account WHERE Id =:lstAccountIDs]);

     List<Account> lstAccounts = new List<Account>();
     for(AggregateResult result: [SELECT SUM(Amount) Amt, AccountId FROM Opportunity GROUP BY AccountId, StageName Having AccountId IN :mapAccount.keyset() AND StageName = 'Closed Won' ]) { 
        Account acc = mapAccount.get((Id)result.get('AccountID'));
        acc.Sum_of_Opportunity_Amount__c = (Decimal)result.get('Amt');
        lstAccounts.add(acc);
     }
     if(lstAccounts.size() > 0){
        update lstAccounts;
     }
   }
Also, your trigger is not bulkified to handle Bulk Insert or Update of the Accounts.

Hope this helps.
 
This was selected as the best answer
sonam gupthasonam guptha
LBK,

Thank you its working like a charm, i need to call the same logic using class,then call that class from trigger.
LBKLBK
Sonam,

Try these.
 
//trigger code
trigger UpdateTotalAmount on Opportunity (after insert,after update) {
     clsUpdateAccount.updateAccount(Trigger.new);
}

//APEX Class
public class clsUpdateAccount{
	public static void updateAccount(List<Opportunity> lstOpportunities) {
		 List<Id> lstAccountIDs = new List<Id>();
		 for(Opportunity opp: lstOpportunities) {
		   lstAccountIDs.add(opp.AccountId);
		 }
		 
		 Map<Id, Account> mapAccount = new Map<Id, Account>([SELECT Id, Name, Sum_of_Opportunity_Amount__c FROM Account WHERE Id =:lstAccountIDs]);

		 List<Account> lstAccounts = new List<Account>();
		 for(AggregateResult result: [SELECT SUM(Amount) Amt, AccountId FROM Opportunity GROUP BY AccountId, StageName Having AccountId IN :mapAccount.keyset() AND StageName = 'Closed Won' ]) { 
			Account acc = mapAccount.get((Id)result.get('AccountID'));
			acc.Sum_of_Opportunity_Amount__c = (Decimal)result.get('Amt');
			lstAccounts.add(acc);
		 }
		 if(lstAccounts.size() > 0){
			update lstAccounts;
		 }
	}
}
Let me know if this works.

And, mark your question as solved, if it does.
 
sonam gupthasonam guptha
Thankyou so much LBK,its working as expected,but now am receving an error on test class,how can i cover my test class.
Methods defined as TestMethod do not support Web service callouts
LBKLBK
Hi Sonam,

I am glad it helped.

Web Service Callouts have to be tested using CalloutMock implementation.

Here are some information on this.
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_callouts_wsdl2apex_testing.htm

If you need more information on this, please post it a separate question. Because this is a different topic altogether.
sonam gupthasonam guptha
LBK, 

One Last help for test class,am not able to cover the below lines,can you please check once.
Account acc = mapAccount.get((Id)result.get('AccountID'));
			acc.Total_Amount__c = (Decimal)result.get('Amt');
			lstAccounts.add(acc);
		 }
		 if(lstAccounts.size() > 0){
			update lstAccounts;
		 }

 
LBKLBK
It should be pretty straight forward. You just need to create an account and an opportunity with right values and you are done.

Try this code.
 
@isTest(seeAllData=false)
private class testUpdateTotalAmount {
    static testMethod void testTotalAmount() {
    Test.startTest();
     
    Account acc = new Account();
    acc.Name = 'Test Company';
    insert acc;
    
    
    Opportunity opp = new Opportunity();
    opp.Name = 'Test Opportunity';
    opp.amount = 10000;
    opp.accountId = acc.Id;
    opp.stageName = 'Closed Won';
    opp.closedate = System.today();
    insert opp;
    
    Account acc1 = [SELECT id, Sum_of_Opportunity_Amount__c FROM Account WHERE Id = :acc.Id];
    // Verification
    System.assertEquals(acc1.Sum_of_Opportunity_Amount__c, opp.amount);
     
    Test.stopTest();
    }
}

 
sonam gupthasonam guptha
LBK,

Am Receving following error:--
Error Message	System.AssertException: Assertion Failed: Expected: null, Actual: 10000

 
sonam gupthasonam guptha
LBK,

On the same trigger i replaced the stagename with opp_check boolean value its working fine,but when it set to false i dont need to add that opp.amount  to account.Sum_of_Opportunity_Amount__c,this is also working fine when there are multiple opportunites on that account,but if we have only one opportunity per account and if the Opp_check = false,then account.Sum_of_Opportunity_Amount__c is not setting to zero. i need to set it to null if the checkbox is false and have only one opportunity on that account,how can i achieve this.Please have a look.
for(AggregateResult result: [SELECT SUM(Amount) Amt, AccountId FROM Opportunity GROUP BY AccountId, StageName Having AccountId IN :mapAccount.keyset() AND StageName = 'Closed Won' ]
replaced with :--
for(AggregateResult result: [SELECT SUM(Amount) Amt, AccountId FROM Opportunity GROUP BY AccountId, StageName Having AccountId IN :mapAccount.keyset() AND Opp_check = True]


 
LBKLBK
I guess your field name is Opp_check__c. Right?

Replace the for condition with the following code and try.
for(AggregateResult result: [SELECT SUM(Amount) Amt, AccountId FROM Opportunity GROUP BY AccountId, Opp_check__c Having AccountId IN :mapAccount.keyset() AND Opp_check__c = True]
If you are looking at setting the Sum_of_Opportunity_Amount__c field to 0 for the accounts without any opportunities (meeting the above mentioned condition), you may want to setup a default value in the field definition.
 
sonam gupthasonam guptha
LBK,

I replaced the code its working super fine,but the only problem is if again opp.Opp_check__c = false and had only one opp on account,that value is still am seeing on the account.Sum_of_Opportunity_Amount__c,that particualr value i want to make it null.
And for setting up default value i cannot see opp..Opp_check__c value on account,as the Sum_of_Opportunity_Amount__c is on account,can we do it the same thing in apex?
sonam gupthasonam guptha
Am trying something like this,but its not working,can you please have a look?
 
}
     if(lstAccounts.size() > 0){
        update lstAccounts;
     }else
     for(Account acct : [select id,name,(select id,name from opportunities__r) from Account]){
      for(opportunity op : oppid){
         if(acct.opportunities__r.size() = =1 && op.Opp_check__c == false){
            acct.Sum_of_Opportunity_Amount__c = 0;
         }

 
LBKLBK
Try this.
 
//APEX Class
public class clsUpdateAccount{
	public static void updateAccount(List<Opportunity> lstOpportunities) {
		 List<Id> lstAccountIDs = new List<Id>();
		 for(Opportunity opp: lstOpportunities) {
		   lstAccountIDs.add(opp.AccountId);
		 }
		 
		 Map<Id, Account> mapAccount = new Map<Id, Account>([SELECT Id, Name, Sum_of_Opportunity_Amount__c FROM Account WHERE Id =:lstAccountIDs]);


		 //Reset the Sum_of_Opportunity_Amount__c
		 for(Id acctId : mapAccount.keyset()){
			Account acct = mapAccount.get(acctId);
			acct.Sum_of_Opportunity_Amount__c = 0;
			mapAccount.put(acctId, acct);
		 }
		 //Reset the Sum_of_Opportunity_Amount__c
		 
		 for(AggregateResult result: [SELECT SUM(Amount) Amt, AccountId FROM Opportunity GROUP BY AccountId, Opp_check__c Having AccountId IN :mapAccount.keyset() AND Opp_check__c = True]) { 
			Account acc = mapAccount.get((Id)result.get('AccountID'));
			acc.Sum_of_Opportunity_Amount__c = (Decimal)result.get('Amt');
			mapAccount.put((Id)result.get('AccountID'), acc);
		 }
		 if(mapAccount.isEmpty() == false){
			update mapAccount.values();
		 }
	}
}

 
sonam gupthasonam guptha
Awesome LBK,its working like charm,thanks a lot.