+ Start a Discussion
Rob LilleyRob Lilley 

Opportunity trigger not working correctly in certain scenarios

Hi,
 
I wonder if someone could help please. I know very little about APEX…I probably need a developer but trying this first.

We use Salesforce for giving out grants – the main part being Organisations & Opportunities (Accounts renamed to Organisations and Opportunities renamed to Grant Requests). Opportunities have two custom fields: Grant Amount and a Decision Date. EG £5,000 12/07/2005

Organisations can apply every year and the Apex code we have had written, lists in a rich text field on the latest grant request the previous grants (ie previous to this grant on the same account) and updates a currency field named: Total of Previous Grants. Eg:
 
£2,500  2004-2005
£1,500  2010-2011
£3,400  2014-2015
 
Total of Previous Grants: £7,400
 
As far as I can tell the code is triggered in two ways:
When a new Grant Request (Opportunity) is created – Works perfectly
When the “Populate Previous Grants” button on a Grant Request is clicked – this has an issue...
 
 The issue with the button seems to be that if an old grant request is added (we are entering old ones) that it does not picked if the “Populate Previous Grants” is clicked. However if I just clone the new grant request, the old grant is picked up. If I then clear down the lists of previous grants and total, save, and then click the button it works fine, which I find a bit odd.
 
I can therefore reproduce the problem but cannot work out what the issue may be. I have put the code below.

Any pointers/suggestiosn would be helpful, thanks, Rob

Button Code
{!REQUIRESCRIPT("/soap/ajax/29.0/connection.js")}
{!REQUIRESCRIPT("/soap/ajax/29.0/apex.js")}
var accId="{!Opportunity.AccountId}";
if( accId != null && accId != '') {
var result = sforce.apex.execute("PopulatePreviousGrantsController","populatePreviousGrants",{oppId:"{!Opportunity.Id}"});
if(result=="Success") {
alert("Previous Grants value updated successfully");
}else {
alert(result);
}
location.reload();
} else {
alert('Opportunity must be associated with a Account');
}

Opportunity Trigger
trigger PopulatePreviousGrants on Opportunity (before insert) {

    Set<Id> accIdSet=new Set<Id>();
    Map<Id,List<Opportunity>> oldAccIdAndOppMap=new Map<Id,List<Opportunity>>();
     Map<Id,List<Opportunity>> newAccIdAndOppMap=new Map<Id,List<Opportunity>>();
    List<Opportunity> updateOppList=new List<Opportunity>();
    List<String> args = new String[]{'0','number','###,###,##0.00'};

    
    for(Opportunity opp:Trigger.New) {
        
        accIdSet.add(opp.AccountId);
        if( opp.AccountId != NULL && !newAccIdAndOppMap.containsKey(opp.AccountId)) {
            
            newAccIdAndOppMap.put(opp.AccountId,new List<Opportunity>());
        } 
        newAccIdAndOppMap.get(opp.AccountId).add(opp);
    }
    
    for(Opportunity opp:[SELECT Id,AccountId,Grant_Amount__c,Grant_Payment_Period__c,Previous_Grants_Total__c,Decision_Date__c From Opportunity WHERE AccountId IN :accIdSet ORDER BY Decision_Date__c ]) {
    
        if( opp.AccountId != NULL && !oldAccIdAndOppMap.containsKey(opp.AccountId)) {
            
            oldAccIdAndOppMap.put(opp.AccountId,new List<Opportunity>());
        } 
        oldAccIdAndOppMap.get(opp.AccountId).add(opp);   
    }
    for(Id accId :newAccIdAndOppMap.keySet()) {
        
        for(Opportunity newOpp:newAccIdAndOppMap.get(accId)) {    
            
            if(oldAccIdAndOppMap.containsKey(accId)) {
                
                String previousGrants='';
                Decimal previousGrantsTotal=0;
                for(Opportunity oldOpp:oldAccIdAndOppMap.get(accId)) {
                    
                    if(oldOpp.Grant_Amount__c > 1) {
                        
                        String period=oldOpp.Grant_Payment_Period__c==NULL?'':oldOpp.Grant_Payment_Period__c;
                        previousGrants+=period+'&nbsp;&nbsp;&nbsp;&pound;'+String.format(oldOpp.Grant_Amount__c.format(), args)+'<br>';
                        previousGrantsTotal+=oldOpp.Grant_Amount__c;
                    }        
                }
               newOpp.Previous_Grants__c=previousGrants;
               newOpp.Previous_Grants_Total__c=previousGrantsTotal; 
            }
            if(!oldAccIdAndOppMap.containsKey(accId)) {
                
                oldAccIdAndOppMap.put(accId,new List<Opportunity>()); 
                oldAccIdAndOppMap.get(accId).add(newOpp);   
            } else {
            
                List<Opportunity> tempOldOpp=new List<Opportunity>();
                boolean flag=false;
                for(Opportunity oldOpp:oldAccIdAndOppMap.get(accId)) {
                    
                    if(newOpp.Decision_Date__c<oldOpp.Decision_Date__c && flag == false) {
                    
                        tempOldOpp.add(newOpp);
                        flag=true;
                    }  
                     
                    tempOldOpp.add(oldOpp);  
                }
                if(flag==false) {
                     
                    tempOldOpp.add(newOpp);    
                }
                oldAccIdAndOppMap.get(accId).clear();
                oldAccIdAndOppMap.get(accId).addAll(tempOldOpp);
                System.debug('<--------------------------------->'+tempOldOpp.size());
            }
            
        }
    }    
}
 

Best Answer chosen by Rob Lilley
JD68JD68
Hi Rob, thanks for sending through.  There is no error in the code so it looks like it is a logic problem.

It seems the code fired from the button is not picking up 1 of the other grants.  The 'button' code is a little different from the 'trigger' code in that it looks for grants that were entered into Salesforcebefore the Grant from which the button is clicked.  Whereas the trigger code does not include this criteria.

So if my theory is correct, the missing grant (1980-1999 £3,750) was created after the grant that you clicked the button from, and the logic in the button code is excluding it.  Could you please verify that?  

All Answers

JD68JD68
Hi Rob,
The button is calling some other code, a method called 'populatePreviousGrants' in a class called 'PopulatePreviousGrantsController': 
 
var result = sforce.apex.execute("PopulatePreviousGrantsController","populatePreviousGrants",{oppId:"{!Opportunity.Id}"});

So I think this is where the code is not working as expected.  Are you able to share that piece of code please?  
Cheers
JD
Rob LilleyRob Lilley
Hi John,
Yes of course - thank you, here it is, Rob

global class PopulatePreviousGrantsController {
    
    webService static String populatePreviousGrants(Id oppId) {
       try {
           
            List<String> args = new String[]{'0','number','###,###,##0.00'};
            List<Opportunity> currentOppList=[SELECT Id,CreatedDate,AccountId FROM Opportunity WHERE Id= :oppId ];
            List<Opportunity> oppList=[SELECT Id,Grant_Payment_Period__c,Grant_Amount__c,Previous_Grants_Total__c,Decision_Date__c,CreatedDate FROM Opportunity WHERE AccountId = :currentOppList.get(0).AccountId AND CreatedDate <= :currentOppList.get(0).CreatedDate ORDER BY Decision_Date__c];
            String previousGrants='';
            Decimal previousGrantsTotal=0;
            if(oppList != NULL && oppList.size() > 0) {
            
                for(Opportunity opp :oppList) {
                    
                    if(opp.Grant_Amount__c > 0 && opp.Id != oppId) {
                    
                        String period=opp.Grant_Payment_Period__c == NULL ? '' :opp.Grant_Payment_Period__c;
                        previousGrants+=period+'&nbsp;&nbsp;&nbsp;&pound;'+String.format(opp.Grant_Amount__c.format(), args)+'<br>';
                        previousGrantsTotal+=opp.Grant_Amount__c;
                    }
                }
            }
            Opportunity opp=new Opportunity();
            opp.Id=oppId;
            opp.Previous_Grants__c=previousGrants;
            opp.Previous_Grants_Total__c=previousGrantsTotal;
            update opp; 
            return 'Success';  
        }catch(Exception e) {
        
            System.debug('<--------------ERROR LOG------------------>'+e);
            return e.getMessage();
        }     
    }
}
JD68JD68
Hi Rob, thanks, I can see that if an error occurs in that code it's not reported back to the user.  Instead it's 'failing silently' and writing the error to the debug log.  It could be that an error is happening.  Do you know how to view debug logs?  If so could you send me the log from when this happens?  Btw is your organisation a Nonprofit?
Rob LilleyRob Lilley
Hello John, Yes I think I have the debug logs for the same Grant Request for both scenarios now:

1 Clicking on the 'Populate Previous Grants'  button - the listing is incorrect
2 Creating (cloning) the Grant Request - the listing is correct.

They are rather long - shall I paste it into this blog or send to you?

Yes it is a Non Profit - but I work for another NonProfit and occasionally do work for other Nonprofits but not entirely free some of the time.. A little complicated to explain I sometime think.

Many thanks, Rob
JD68JD68
thanks Rob if you could please email the logs (or drop them somewhere I can pick them up)
johndavies1968@gmail.com
Rob LilleyRob Lilley
Hi John, Have just email them to you, Rob
JD68JD68
Hi Rob, thanks for sending through.  There is no error in the code so it looks like it is a logic problem.

It seems the code fired from the button is not picking up 1 of the other grants.  The 'button' code is a little different from the 'trigger' code in that it looks for grants that were entered into Salesforcebefore the Grant from which the button is clicked.  Whereas the trigger code does not include this criteria.

So if my theory is correct, the missing grant (1980-1999 £3,750) was created after the grant that you clicked the button from, and the logic in the button code is excluding it.  Could you please verify that?  
This was selected as the best answer
JD68JD68
Hi Rob if you're ok with this can you mark as resolved with my answer please?
Rob LilleyRob Lilley
Hi John,
Yes you were correct that the missing grant (1980-1999 £3,750) was created after the grant that you clicked the button from, and the logic in the button code is excluding it. As you said the class was looking at created date - all created date entries in class changed to decision date and works fine now.

Many thanks for your help, much appreciated

Rob