• ChickenOrBeef
  • NEWBIE
  • 190 Points
  • Member since 2013

  • Chatter
    Feed
  • 0
    Best Answers
  • 1
    Likes Received
  • 0
    Likes Given
  • 40
    Questions
  • 92
    Replies
Hey everyone,

We have a custom object called "Properties" and a junction object called "Property/Opportunity Relationship" that allows for a Many-To-Many relatiosnhip between Opportunities and Properties. Anywho, I need to create a slick VisualForce section on our Opportunity page that allows our users to  the following:
  1. Search for an existing Property record
  2. If existing Property record is found, then that record is attached to the Opportunity (via the creation of a junction record)
  3. If user can't find existing Property record, they can then fill out a couple fields to create both the new Property record and the junction record to connect it to the Opportunity
Is there any example code out there that does something similar to what I'm describing? Of if not, can someone provide some example code? I have decent experience with VisualForce, but I've never made anything quite like this.

Thanks a bunch,
Greg
Hey everyone,

I have a VisualForce page embedded within our standard Opportunity layout. Up until now this VF page has just been a table with custom checkbox fields using "inputCheckbox". When a user went to an Opportunity the page would open as normal at the top of the Opportunity page.

However, I've since added an "inputField" to the VF page, which allows the user to fill in one of our existing Lookup fields. The problem is that whenever the user goes to an Opportunity now, the Opportunity will open and then the user is directed down to the VF page instead of staying at the top of the Opportunity.

Is there a reason why the "inputField" parameter causes the screen to immediately redirect down to the VF page?

Thanks,
Greg
I have a VisualForce page embedded in my Opportunity layout. If a user makes changes to the Opportunity fields and then also makes changes in the embedded VisualForce page, they can't save both changes. They either have to save the Opportunity or save the VisualForce page, losing their changes to the other one.

Is there any way to let our users save both changes at the same time? For reference, see below for the VisualForce Page and Extension involved:


VisualForce Page:
<apex:page standardController="Opportunity" Extensions="ControllerContactSelectionOpportunity">
    
    <style>
        .added {
            background-color: #a4f3fc;
        }
        .removed {
            background-color: white;
        }
    </style>
    
    <apex:form >
    
        <apex:pageBlock >
            
            <apex:pageBlockTable  value="{!Records}" var="Con">
                
                <apex:column headerValue="Add To Opportunity" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.attach}"/>
                </apex:column>
                <apex:column headerValue="Name" value="{!Con.Name}" styleClass="{!IF(Con.attach == TRUE,'added','removed')}"/>
                <apex:column headerValue="Main User" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.mainUser}"/>
                </apex:column>
                <apex:column headerValue="General User" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.genUser}"/>
                </apex:column>
                <apex:column headerValue="Billing" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.billing}"/>
                </apex:column>
                <apex:column headerValue="E-Commerce" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.eComm}"/>
                </apex:column>
                <apex:column headerValue="Email" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.email}"/>
                </apex:column>
                <apex:column headerValue="CRM" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.crm}"/>
                </apex:column>
                <apex:column headerValue="Junior Decision Maker" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.junior}"/>
                </apex:column>
                <apex:column headerValue="Senior Decision Maker" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.senior}"/>
                </apex:column>
                <apex:column headerValue="Signature" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.signature}"/>
                </apex:column>
                <apex:column headerValue="Coach" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.coach}"/>
                </apex:column>
                <apex:column headerValue="Champion" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.champion}"/>
                </apex:column>
                <apex:column headerValue="I Don't Know" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.idk}"/>
                </apex:column>
                
            </apex:pageBlockTable>
            
            <Apex:pageBlockButtons location="bottom">
            
                <apex:commandButton action="{!customSave}" value="Save"/>
            
            </Apex:pageBlockButtons>
            
            <apex:outputPanel rendered="{!refreshPage}">
               <script>
                  window.top.location='/{!Opportunity.Id}';
               </script>
            </apex:outputPanel>
        
        </apex:pageBlock>
    
    </apex:form>
    
</apex:page>


Extension:
public class ControllerContactSelectionOpportunity{
    
    public class contactAttach{
        
        public string name {get;set;}
        public Boolean attach {get; set;}
        public Boolean mainUser {get; set;}
        public Boolean genUser {get; set;}
        public Boolean billing {get; set;}
        public Boolean eComm {get; set;}
        public Boolean email {get; set;}
        public Boolean crm {get; set;}
        public Boolean junior {get; set;}
        public Boolean senior {get; set;}
        public Boolean signature {get; set;}
        public Boolean coach {get; set;}
        public Boolean champion {get; set;}
        public Boolean idk {get; set;}
        public Contact con {get; set;}
        
    }
    
    public List<contactAttach> Records {get; set;}
    public Boolean refreshPage {get; set;}
    public Opportunity Record;
    public Set<String> roleContacts;
    public Map<String,OpportunityContactRole> roleMap;
    public Map<String,String> roleIDMap;
    
    public ControllerContactSelectionOpportunity(ApexPages.StandardController controller){
        
        Records = new List<contactAttach>();
        List<contactAttach> addedRecords = new List<contactAttach>();
        List<contactAttach> removedRecords = new List<contactAttach>();
        Record = (Opportunity) controller.getRecord();
        String AccountId = [SELECT AccountId FROM Opportunity WHERE Id = :Record.Id LIMIT 1].AccountId;
        roleContacts = new Set<String>();
        roleMap = new Map<String,OpportunityContactRole>();
        roleIDMap = new Map<String,String>();
        refreshPage = FALSE;
        
        FOR(OpportunityContactRole ocr : [SELECT
                                         	Id,
                                         	ContactId
                                          FROM
                                         	OpportunityContactRole
                                          WHERE
                                          	OpportunityId = :Record.Id]){
                                              
                                              roleContacts.add(ocr.ContactId);
                                              roleMap.put(ocr.ContactId,ocr);
                                              roleIDMap.put(ocr.ContactId,ocr.Id);
                                              
                                          }
        
        FOR(Contact c : [SELECT 
                             	Id, 
                             	Name,
                             	Main_User__c, 
                             	General_User__c,
                             	Billing__c,
                             	E_Commerce__c,
                             	Email__c,
                             	CRM__c,
                             	Junior_Decision_Maker__c,
                             	Senior_Decision_Maker__c,
                             	Signature__c,
                             	Coach__c,
                             	Champion__c,
                             	I_Don_t_Know__c
                             FROM 
                             	Contact 
                             WHERE 
                             	AccountId = :AccountId
                        	 ORDER BY Name ASC]){
                                    
                                    contactAttach ca = new contactAttach();
                                    ca.Name = c.Name;
                                    ca.attach = roleContacts.contains(c.Id) ? TRUE : FALSE;
                                    ca.mainUser = c.Main_User__c;
                                    ca.genUser = c.General_User__c;
                                    ca.billing = c.Billing__c;
                                    ca.eComm = c.E_Commerce__c;
                                    ca.email = c.Email__c;
                                    ca.crm = c.CRM__c;
                                    ca.junior = c.Junior_Decision_Maker__c;
                                    ca.senior = c.Senior_Decision_Maker__c;
                                    ca.signature = c.Signature__c;
                                    ca.coach = c.Coach__c;
                                    ca.champion = c.Champion__c;
                                    ca.idk = c.I_Don_t_Know__c;
                                    ca.con = c;
                                 
                                 IF(ca.attach == TRUE){
                                     
                                     addedRecords.add(ca);
                                     
                                 }
                                 ELSE{
                                     
                                     removedRecords.add(ca);
                                     
                                 }
            
        }
        
        FOR(contactAttach ar : addedRecords){
            
            Records.add(ar);
            
        }
        
        FOR(contactAttach rr : removedRecords){
            
            Records.add(rr);
            
        }
        
        
    }
    
    public PageReference CustomSave(){
        
        Set<String> contactsChanged = new Set<String>();
        List<Contact> contactsToUpdate = new List<Contact>();
        List<OpportunityContactRole> rolesToAdd = new List<OpportunityContactRole>();
        List<OpportunityContactRole> rolesToChange = new List<OpportunityContactRole>();
        List<OpportunityContactRole> rolesToDelete = new List<OpportunityContactRole>();
        
        FOR(contactAttach cna : Records){
                
            IF(cna.con.Main_User__c != cna.mainUser || cna.con.General_User__c != cna.genUser ||
               cna.con.Billing__c != cna.billing || cna.con.E_Commerce__c != cna.eComm ||
               cna.con.Email__c != cna.email || cna.con.CRM__c != cna.crm ||
               cna.con.Junior_Decision_Maker__c != cna.junior ||  cna.con.Senior_Decision_Maker__c != cna.senior ||
               cna.con.Signature__c != cna.signature || cna.con.Coach__c != cna.coach ||
               cna.con.Champion__c != cna.champion || cna.con.I_Don_t_Know__c != cna.idk){
                
                cna.con.Main_User__c = cna.mainUser;
                cna.con.General_User__c = cna.genUser;
                cna.con.Billing__c = cna.billing;
                cna.con.E_Commerce__c = cna.eComm;
                cna.con.Email__c = cna.email;
                cna.con.CRM__c = cna.crm;
                cna.con.Junior_Decision_Maker__c = cna.junior;
                cna.con.Senior_Decision_Maker__c = cna.senior;
                cna.con.Signature__c = cna.signature;
                cna.con.Coach__c = cna.coach;
                cna.con.Champion__c = cna.champion;
                cna.con.I_Don_t_Know__c = cna.idk;
                contactsToUpdate.add(cna.con);
                contactsChanged.add(cna.con.Id);
                
            }
            
            IF(cna.attach == TRUE && !roleContacts.contains(cna.con.Id)){
                
                OpportunityContactRole cr = new OpportunityContactRole();
                cr.ContactId = cna.con.Id;
                cr.OpportunityId = Record.Id;
                cr.Role = cna.mainUser == TRUE ? 'Main User' 
                    	: cna.genUser == TRUE ? 'General User' 
                    	: cna.billing == TRUE ? 'Billing' 
                    	: cna.eComm == TRUE ? 'E-Commerce' 
                    	: cna.email == TRUE ? 'Email' 
                    	: cna.crm == TRUE ? 'CRM' 
                    	: cna.junior == TRUE ? 'Junior' 
                    	: cna.senior == TRUE ? 'Senior' 
                    	: cna.signature == TRUE ? 'Signature' 
                    	: cna.coach == TRUE ? 'Coach' 
                    	: cna.champion == TRUE ? 'Champion' 
                    	: 'Other';
                rolesToAdd.add(cr);
                
            }
            ELSE IF(cna.attach == TRUE && roleContacts.contains(cna.con.Id) && contactsChanged.contains(cna.con.Id)){
                
                OpportunityContactRole cru = new OpportunityContactRole();
                cru.Id = roleIDMap.get(cna.con.Id);
                cru.Role = cna.mainUser == TRUE ? 'Main User' 
                    	 : cna.genUser == TRUE ? 'General User' 
                    	 : cna.billing == TRUE ? 'Billing' 
                    	 : cna.eComm == TRUE ? 'E-Commerce' 
                    	 : cna.email == TRUE ? 'Email' 
                    	 : cna.crm == TRUE ? 'CRM' 
                    	 : cna.junior == TRUE ? 'Junior' 
                    	 : cna.senior == TRUE ? 'Senior' 
                    	 : cna.signature == TRUE ? 'Signature' 
                    	 : cna.coach == TRUE ? 'Coach' 
                    	 : cna.champion == TRUE ? 'Champion' 
                    	 : 'Other';
                rolesToChange.add(cru);
                
            }
            ELSE IF(cna.attach == FALSE && roleContacts.contains(cna.con.Id)){
                
                rolesToDelete.add(roleMap.get(cna.con.Id));
                
            }
            
        }
        
        IF(!contactsToUpdate.isEmpty()){
            
            UPDATE contactsToUpdate;
            
        }
    
        IF(!rolesToAdd.isEmpty()){
            
            INSERT rolesToAdd;
            
        }
        
        IF(!rolesToChange.isEmpty()){
            
            UPDATE rolesToChange;
            
        }
        
        IF(!rolesToDelete.isEmpty()){
            
            DELETE rolesToDelete;
            
        }
        
        refreshPage = TRUE;
        RETURN null;
        
    }

}


Thanks,
Greg
Hey everyone,

We have five checkbox fields on the Contact object called:
  • Main User
  • General User
  • Signature Contact
  • Billing Contact
  • Stakeholder
We want to have a VisualForce page embedded on the Account page that lists all the Contacts on that respective Account along with a column for each of the checkbox fields, showing the current values. So it would look like this:

User-added image

It would be ideal if the user can just visit a certain Account, scroll down to the embedded VisualForce table (seen above), check and uncheck any boxes they need to, and then click Save, which would update the values on the Contacts. If the user needs to click an "Edit" button first in order to check/uncheck any boxes, then that would fine (but not ideal obviously).

I would be hugely appreciative if someone could provide example VisualForce and Controller code for something like this.  I have minor experience with VisualForce, but this is a step above what I've done. 

Thanks!
Greg 
Hey everyone,

I have a SOQL query of the Contact object that includes a relationship query of the Tasks associated to the Contacts:
 
FOR(Contact c1 : [SELECT
                         	Id,Last_Contacted__c
                            (SELECT 
                             	Id,Completed_Time_Formula__c 
                             FROM 
                             	Tasks 
                             WHERE 
                             	CreatedById != '005A0000004PQwZ' AND Completed_Time_Formula__c != NULL 
                             ORDER BY Completed_Time_Formula__c
                             DESC LIMIT 1)
                          FROM
                         	Contact
                          WHERE
                          	Id In :contactsInTrigger]){

        //code here

}

Right now the Task query doesn't seem to include archived tasks. I tried to include "ALL ROWS" somewhere in the Task query, but I kept getting errors. Then I tried adding "(IsArchived = TRUE OR IsArchived = FALSE)" to the query, but that didn't seem to include archived tasks when I tested the code.

Is there a way to include all Tasks (both archived and unarchived) in a Task relationship query? Am I doing it wrong?

Thanks,
Greg
Hey everyone,

I have batch code that's designed to find the last logged task out of every Account in an entire Account's hierarchy. To do this I did the following:
  1. I created a custom Text field on the Account object called Ultimate Parent Account ID Stamp that simply contains the ID of the ultimate parent Account in the hierarchy. (The ultimate parent Account itself contains its own ID in the Ultimate Parent Account ID Stamp field.)
  2. In the batch code I created an Aggregrate SOQL queury that's grouped by the Ultimate Parent Account ID Stamp field and finds the latest Last Contacted date from all the Accounts in the grouping

So a typical Account hierarchy would look like this:

User-added image


And here's the aforementioned Aggregate queury: 
 
List<AggregateResult> lastHierarchy = [SELECT
                                          Ultimate_Parent_Account_ID_Stamp__c,
                                          MAX(Last_Contacted__c) lastC
                                       FROM
                                          Account
                                       WHERE
                                          Ultimate_Parent_Account_ID_Stamp__c In :initialAccounts
                                       GROUP BY
                                          Ultimate_Parent_Account_ID_Stamp__c];


The problem I'm running into is that the Ultimate Parent Account ID Stamp field is a text field and not some type of ID field. IDs can have the exact same characters, but with different capitalizations. So APEX treats IDs as case-sensitive and Text as case-insensitive. So if there's a bunch of Accounts with an Ultimate Parent Account ID Stamp of 001A000000uMLPs and another bunch of Accounts with an Ultimate Parent Account ID Stamp of 001A000000uMLPS, they'll all be grouped together in the queury even though the "S" is capitalized in one ID and not in the other.

The reason I used a Text field for Ultimate Parent Account ID Stamp is so that the ultimate parent could contain its own ID. If I used an Account lookup field instead, then the ultimate parent couldn't lookup to itself. So I used a Text field. But then I noticed the above issue.

So my question is: Is there a way to make the Aggregate grouping text field case-sensitive somehow? If not, do you know a better way to handle what I'm doing?

Thanks!
-Greg
Hey everyone,

When trying to delete an Apex class via the Force IDE I'm getting the "Destination organization must be different from the Project organization" error. I found this article, which tells me to go to the ".settings" folder and set the endpointServer to a blank value.

Here is the tutorial picture provided by the article:

User-added image



The problem is that I don't see the ".settings" folder anywhere in my instance:

User-added image

I'm guessing the article was written for an older verion of Force IDE. Does anyone know where to find the ".settings" folder (and therefore the endpointServer attribute)?

Thanks!
-Greg
Hey everyone,

I'm pretty new to Visualforce. I'm trying to create a Visualforce page for an Opportunity List button, which calls a visual flow to create a new Opportunity. I need to pass in the AccountID, but when I tried doing like this...

User-added image 

<apex:param name="AccountID" value="{!Opportunity.AccountId}"/>

...AccountID doesn't get populated in the flow. I'm assuming that's because this Opportunity doesn't have an AccountID yet, but this Visualforce page is using the Opportunity controller, so I don't have access to the Account's fields. How do I grab that AccountID?

Thanks,
Greg
Hey everyone,

I had to create my first custom controller that allows for one of my visual flows to be re-directed to the created record (an Account) at the end of the flow. The controller works great, but now I need to create my first custom controller test class.

Here is the custom controller:
 
public class ControllerNewSubAccount{

    public ControllerNewSubAccount(ApexPages.StandardController controller) {

    }

    
 public Flow.Interview.Create_Account_w_Parent crAcc {get;set;}
    
 public PageReference prFinishLocation {
     
     get{
         
         PageReference prRef = new PageReference('/' + strOutputVariable);
         prRef.setRedirect(true);
         return prRef;
         
     }
     set{prFinishLocation = value;}
     
 }

 public String strOutputVariable {
     
     get{
         
         String strTemp = '';
        
         if(crAcc != null) {
             
         	strTemp = string.valueOf(crAcc.getVariableValue('AccountID'));
             
         }
        
         return strTemp;
         
     }
     set{strOutputVariable = value;}
     
 }
 
}

Here is the beginnings of the test class I created (but obviously this only covers the first few lines):
 
@isTest
public class TestVisualforceControllers {
    
    static testmethod void testControllerNewSubAccount(){
        
        Account a = New Account(Name='Tester');
        INSERT a;
        ApexPages.StandardController sc = new ApexPages.standardController(a);
        ControllerNewSubAccount e = new ControllerNewSubAccount(sc);
        
    }

}

I have no idea how to approach this. I'm assuming I need to trigger the flow somehow, or something along those lines.

Thanks,
Greg
Hey everyone,

We've been exceeding our daily API requests limit (140,000). I checked the "API Usage - Last 7 Days" report, and it seems that the vast majority of the requests are under my name, but there's no "Client Id" associated with them. So I have no idea where they're coming from.

Is there any way to identify the source of those requests?

Thanks,
Greg
Hello everyone,

If a logged email was sent to three different email addresses (as an example), we'd like to have a trigger that associates that Task to all three Contacts in Salesforce. I know we can manually associate a Task to multiple Contacts, but is this possible to do in Apex automatically? And if so, how would I go about writing the Name field to hold multiple Contacts?

Thanks!
-Greg
Hey everyone,

I've been running into "CPU Time Limit" errors recently, and I believe it has something to do with my sloppy use of loops within loops. So with that said, here's an example of how I normally handle loops within loops. For example, this could be a trigger where I want to simply count the number of Opportunities present under each Account:
 
Set<String> accountsInTrigger = new Set<String>();
        
        FOR(Opportunity o : opps){
            
            IF(o.AccountId != NULL){
                
                accountsInTrigger.add(o.AccountId);
                
            }
            
        }
        
        List<Opportunity> relatedOpps = [SELECT
                                            Id,AccountId
                                         FROM
                                            Opportunity
                                         WHERE
                                            AccountId In :accountsInTrigger];
        
        FOR(String account : accountsInTrigger){
            
            FOR(Opportunity opp : oppsInTrigger){
                
                IF(opp.AccountId == account){
                    
                    /* Insert code here */ 
                    
                }
                
            }
            
        }

I'm assuming that this isn't efficient since this code will loop through every Opp when looping through each Account, regardless if the Opp is attached to that Account or not. Then the IF statement filters down the Opps within each loop, but I'm assuming the code is still looping through every single Opp.

Is there a more efficient way to handle this loop within a loop? Or should I try to avoid loops within loops all together?

Thanks!
-Greg

 
Hey everyone,

I've run into the incredibly frustrating "Apex CPU time limit exceeded" error, so I put in debug statements throughout my triggers, in between each class call, which should show the CPU time after each class is called. That should theoretically tell me which class is causing the issue.

The problem is that only some of the debug logs show up.

For example, here is my main opportunity trigger, where all the opportunity classes are called. I have a debug statement after each call:
 
trigger MainTriggerOpportunity on Opportunity (before insert, before update, after insert, after update) {
    
    if(trigger.isBefore){
            
        if(trigger.isInsert){
            
            if(checkRecursive.runBeforeInsertOnce()){
            
            ClassOppIndustry updater = new ClassOppIndustry();
            updater.updateOppIndustry(Trigger.new);
                
               	System.debug(LoggingLevel.ERROR,'[OPP] BEFORE INSERT: CPU time after ClassOppIndustry is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
            
            ClassRenewalDate updater1 = new ClassRenewalDate();
            updater1.updateRenewalDate(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] BEFORE INSERT: CPU time after ClassRenewalDate is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            ClassLeadConvertUpdates updater2 = new ClassLeadConvertUpdates();
            updater2.updateLeadConvertFields(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] BEFORE INSERT: CPU time after ClassLeadConvertUpdates is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            }
            
        }
        if(trigger.isUpdate){
            
            if(checkRecursive.runBeforeUpdateOnce()){
            
            ClassOppIndustry updater = new ClassOppIndustry();
            updater.updateOppIndustry(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] BEFORE UPDATE: CPU time after ClassOppIndustry is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
            
            ClassRenewalDate updater1 = new ClassRenewalDate();
            updater1.updateRenewalDate(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] BEFORE UPDATE: CPU time after ClassRenewalDate is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            ClassBrandParent updater2 = new ClassBrandParent();
            updater2.addBrandParent(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] BEFORE UPDATE: CPU time after ClassBrandParent is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            ClassCallScheduledAdvance updater3 = new ClassCallScheduledAdvance();
            updater3.addCallScheduledDate(Trigger.new,Trigger.oldMap);
                
                System.debug(LoggingLevel.ERROR,'[OPP] BEFORE UPDATE: CPU time after ClassCallScheduledAdvance is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            }
     }
  }
    
    
    if(trigger.isAfter){
        
        if(trigger.isInsert){
            
            if(checkRecursive.runAfterInsertOnce()){
            
            ClassRenewalProcess updater = new ClassRenewalProcess();
            updater.updateRenewalStatus(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] AFTER INSERT: CPU time after ClassRenewalProcess is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
            
            ClassOppBrandCreate updater1 = new ClassOppBrandCreate();
            updater1.addBrand(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] AFTER INSERT: CPU time after ClassOppBrandCreate is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            ClassOppTeamMember updater2 = new ClassOppTeamMember();
            updater2.insertOpp(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] AFTER INSERT: CPU time after ClassOppTeamMember is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            ClassPrimaryContactCopy updater4 = new ClassPrimaryContactCopy();
            updater4.copyPrimary(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] AFTER INSERT: CPU time after ClassPrimaryContactCopy is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            ClassOppPicklists updater5 = new ClassOppPicklists();
            updater5.updatePicklists(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] AFTER INSERT: CPU time after ClassOppPicklists is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            ClassBDSourceCreate updater6 = new ClassBDSourceCreate();
            updater6.addBDSource(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] AFTER INSERT: CPU time after ClassBDSourceCreate is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            ClassMapPlatform updater7 = new ClassMapPlatform();
            updater7.copyPlatform(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] AFTER INSERT: CPU time after ClassMapPlatform is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            ClassAnnualDealRevenue updater8 = new ClassAnnualDealRevenue();
            updater8.addAnnualRevenue(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] AFTER INSERT: CPU time after ClassAnnualDealRevenue is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            ClassDemandGenOpportunity updater9 = new ClassDemandGenOpportunity();
            updater9.addContactRoles(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] AFTER INSERT: CPU time after ClassDemandGenOpportunity is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            }
       }
        if(trigger.isUpdate){
            
            if(checkRecursive.runAfterUpdateOnce()){
            
            ClassRenewalProcess updater = new ClassRenewalProcess();
            updater.updateRenewalStatus(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] AFTER UPDATE: CPU time after ClassRenewalProcess is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
            
            ClassOppBrandCreate updater1 = new ClassOppBrandCreate();
            updater1.addBrand(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] AFTER UPDATE: CPU time after ClassOppBrandCreate is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            ClassDrawLoopUpdates updater3 = new ClassDrawLoopUpdates();
            updater3.updateDrawLoopFields(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] AFTER UPDATE: CPU time after ClassDrawLoopUpdates is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            ClassPrimaryContactCopy updater4 = new ClassPrimaryContactCopy();
            updater4.copyPrimary(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] AFTER UPDATE: CPU time after ClassPrimaryContactCopy is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            ClassOppPicklists updater5 = new ClassOppPicklists();
            updater5.updatePicklists(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] AFTER UPDATE: CPU time after ClassOppPicklists is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            ClassBDSourceCreate updater6 = new ClassBDSourceCreate();
            updater6.addBDSource(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] AFTER UPDATE: CPU time after ClassBDSourceCreate is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            ClassMapPlatform updater7 = new ClassMapPlatform();
            updater7.copyPlatform(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] AFTER UPDATE: CPU time after ClassMapPlatform is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            ClassAnnualDealRevenue updater8 = new ClassAnnualDealRevenue();
            updater8.addAnnualRevenue(Trigger.new);
                
                System.debug(LoggingLevel.ERROR,'[OPP] AFTER UPDATE: CPU time after ClassAnnualDealRevenue is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
                
            ClassDemandGenOpportunityUpdate updater9 = new ClassDemandGenOpportunityUpdate();
            updater9.addContactRoles(Trigger.new,Trigger.oldMap);
                
       

                
            }
        }
    }
}

But here is the log after I mass updated some opportunities in production:

User-added image

As you can see, only the final debug statements are showing up. Any idea why that would be? Also, if you have any suggestions on how to better find out where the CPU limit error is coming from, that would be extremely appreciated.

Thanks!
-Greg
Hey everyone,

I need to write a test class for a trigger that heavily involves the CreatedById and CreatedDate of a task. I can't input values for these fields in a test class, since they're not writeable.

How can I set the CreatedById and CreatedDate for the insertion of a task record in a test class?

Thanks!
-Greg
Hey everyone,

I have a task trigger that depends entirely upon the value in the WhoID field upon creation. I noticed that if a task is created via a BCC'd email, the trigger doesn't work. After putting in some debug statements, I saw that WhoID isn't populated upon creation when the task if from a BCC'd email.

Any idea what I should do?

Thanks,
Greg
Hey everyone,

When creating an opportunity, I'm getting those "Apex governor limit warning" emails telling me that 89 SOQL queries were ran (out of the limit of 100).

For my triggers, I create one main trigger for each object which calls a bunch of classes. So the SOQL queries are made in each class. Here is my opportunity trigger:

trigger MainTriggerOpportunity on Opportunity (before insert, before update, after insert, after update) {
    
    if(trigger.isBefore){
            
        if(trigger.isInsert){
            
            if(checkRecursive.runBeforeInsertOnce()){
            
            ClassOppIndustry updater = new ClassOppIndustry();
            updater.updateOppIndustry(Trigger.new);
            
            ClassRenewalDate updater1 = new ClassRenewalDate();
            updater1.updateRenewalDate(Trigger.new);
                
            ClassLeadConvertUpdates updater2 = new ClassLeadConvertUpdates();
            updater2.updateLeadConvertFields(Trigger.new);
                
            ClassStageDateStampInsert updater3 = new ClassStageDateStampInsert();
            updater3.stampDate(Trigger.new);
                
            }
            
        }
        if(trigger.isUpdate){
            
            if(checkRecursive.runBeforeUpdateOnce()){
            
            ClassOppIndustry updater = new ClassOppIndustry();
            updater.updateOppIndustry(Trigger.new);
            
            ClassRenewalDate updater1 = new ClassRenewalDate();
            updater1.updateRenewalDate(Trigger.new);
                
            ClassBrandParent updater2 = new ClassBrandParent();
            updater2.addBrandParent(Trigger.new);
                
            ClassCallScheduledAdvance updater3 = new ClassCallScheduledAdvance();
            updater3.addCallScheduledDate(Trigger.new,Trigger.oldMap);
                
            ClassStageDateStamp updater4 = new ClassStageDateStamp();
            updater4.stampDate(Trigger.new,Trigger.oldMap);
                
            }
     }
  }
    
    
    if(trigger.isAfter){
        
        if(trigger.isInsert){
            
            if(checkRecursive.runAfterInsertOnce()){
            
            ClassRenewalProcess updater = new ClassRenewalProcess();
            updater.updateRenewalStatus(Trigger.new);
            
            ClassOppBrandCreate updater1 = new ClassOppBrandCreate();
            updater1.addBrand(Trigger.new);
                
            ClassOppTeamMember updater2 = new ClassOppTeamMember();
            updater2.insertOpp(Trigger.new);
                
            ClassPrimaryContactCopy updater4 = new ClassPrimaryContactCopy();
            updater4.copyPrimary(Trigger.new);
                
            ClassOppPicklists updater5 = new ClassOppPicklists();
            updater5.updatePicklists(Trigger.new);
                
            ClassBDSourceCreate updater6 = new ClassBDSourceCreate();
            updater6.addBDSource(Trigger.new);
                
            ClassMapPlatform updater7 = new ClassMapPlatform();
            updater7.copyPlatform(Trigger.new);
                
            ClassAnnualDealRevenue updater8 = new ClassAnnualDealRevenue();
            updater8.addAnnualRevenue(Trigger.new);
                
            ClassDemandGenOpportunity updater9 = new ClassDemandGenOpportunity();
            updater9.addContactRoles(Trigger.new);
                
            }
       }
        if(trigger.isUpdate){
            
            if(checkRecursive.runAfterUpdateOnce()){
            
            ClassRenewalProcess updater = new ClassRenewalProcess();
            updater.updateRenewalStatus(Trigger.new);
            
            ClassOppBrandCreate updater1 = new ClassOppBrandCreate();
            updater1.addBrand(Trigger.new);
                
            ClassDrawLoopUpdates updater3 = new ClassDrawLoopUpdates();
            updater3.updateDrawLoopFields(Trigger.new);
                
            ClassPrimaryContactCopy updater4 = new ClassPrimaryContactCopy();
            updater4.copyPrimary(Trigger.new);
                
            ClassOppPicklists updater5 = new ClassOppPicklists();
            updater5.updatePicklists(Trigger.new);
                
            ClassBDSourceCreate updater6 = new ClassBDSourceCreate();
            updater6.addBDSource(Trigger.new);
                
            ClassMapPlatform updater7 = new ClassMapPlatform();
            updater7.copyPlatform(Trigger.new);
                
            ClassAnnualDealRevenue updater8 = new ClassAnnualDealRevenue();
            updater8.addAnnualRevenue(Trigger.new);
                
            }
        }
    }
}

The individual classes don't have too many unneeded SOQL queries, so I'm guessing the only way to improve this situation is to make large queries in the main trigger itself, pass those lists into the classes, and then iterate on them? Does that sound right?

Thanks!
-Greg
Hey everyone,

When a certain account field is updated, I need all the sub accounts to be updated to have that same value. And I'm not just talking about the immediate sub accounts, but the subs of those subs, the subs of those subs, and so on.

What is the simpliest way to query/update all those sub accounts?

Thanks!
-Greg
Hey Everyone,

I have a task trigger that creates a bunch of records once a task is inserted. This trigger works fine when I manually create a task in Salesforce. But if we use the BCC-to-Salesforce address to log an email as a task, the trigger doesn't seem to run. I've tried manually creating tasks that have the same exact same values as the tasks created via BCC, and the manuallly created tasks will run the trigger while the BCC-created tasks do not.

Is there something I need to take into account? Does BCCing simply not support triggers?


Here is the class I'm testing:

public class ClassRelatedActivitiesInsert {
    
    public void insertRelatedActivities(List<Task> tasks){
        
        Set<String> accountsInTrigger = new Set<String>();
        Set<String> contactsInTrigger = new Set<String>();
        Set<String> parentSet = new Set<String>();
        Set<String> clientSet = new Set<String>();
        Set<String> agencySet = new Set<String>();
        Set<String> siblingAccounts = new Set<String>();
        
        Map<String,String> contactMap = new Map<String,String>();
        Map<String,String> parentMap = new Map<String,String>();
        Map<String,String> siblingParentMap = new Map<String,String>();
        Map<String,String> clientAgencyMap = new Map<String,String>();
        Map<String,String> agencyClientMap = new Map<String,String>();
        
        List<Account> childAccounts = new List<Account>();
        List<Client_Agency_Relationship__c> clientAgencies = new List<Client_Agency_Relationship__c>();
        List<Related_Activity__c> relatedActivitiesToAdd = new List<Related_Activity__c>();
        
        
    FOR(Task t : tasks){        
                IF(t.WhatId != NULL && string.valueOf(t.WhatId).startsWith('001')){
                    accountsInTrigger.add(t.WhatId);
                }
                ELSE IF(t.WhatId == NULL && t.WhoId != NULL && string.valueOf(t.WhoId).startsWith('003')){
                        contactsInTrigger.add(t.WhoId);
                    }       
        }
        
        System.debug(LoggingLevel.ERROR,'INSERT: Heap size after initial task loop is ' + Limits.getHeapSize() + '/' + Limits.getLimitHeapSize());
        System.debug(LoggingLevel.ERROR,'INSERT: CPU time after initial task loop is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
        
        IF(contactsInTrigger.size() > 0){
            FOR(Contact c : [SELECT
                                Id,AccountId
                             FROM
                                Contact
                             WHERE
                                Id In :contactsInTrigger
                             AND
                              AccountId != NULL]){
                                 
                                     contactMap.put(c.Id,c.AccountId);
                                     accountsInTrigger.add(c.AccountId);
                                 
                                }
        }
        
        System.debug(LoggingLevel.ERROR,'INSERT: Heap size after account contacts SOQL is ' + Limits.getHeapSize() + '/' + Limits.getLimitHeapSize());
        System.debug(LoggingLevel.ERROR,'INSERT: CPU time after account contacts SOQL is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
        
        IF(accountsInTrigger.size() > 0){
            FOR(Account ca : [SELECT 
                                 Id,ParentId
                              FROM 
                                 Account
                              WHERE
                                 ParentId In :accountsInTrigger
                              OR
                                 (ParentId != NULL
                              AND
                                  Id In :accountsInTrigger)]){
                                      
                                      IF(accountsInTrigger.contains(ca.ParentId)){
                                          childAccounts.add(ca);
                                      }
                                      IF(accountsInTrigger.contains(ca.Id) && ca.ParentId != NULL){
                                          parentMap.put(ca.Id,ca.ParentId);
                                          parentSet.add(ca.ParentId);
                                      }
                                      
                                  }
        }
        
        System.debug(LoggingLevel.ERROR,'INSERT: Heap size after parent/child account SOQL is ' + Limits.getHeapSize() + '/' + Limits.getLimitHeapSize());
        System.debug(LoggingLevel.ERROR,'INSERT: CPU time after parent/child account SOQL is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
        
        IF(parentSet.size() > 0){
            FOR(Account sa : [SELECT
                                 Id, ParentId
                              FROM
                                 Account
                              WHERE
                                 ParentId In :parentSet]){
                                  
                                    siblingParentMap.put(sa.Id,sa.ParentId);
                                    siblingAccounts.add(sa.Id);
                                  
                                }
        }
        
        System.debug(LoggingLevel.ERROR,'INSERT: Heap size after sibling SOQL is ' + Limits.getHeapSize() + '/' + Limits.getLimitHeapSize());
        System.debug(LoggingLevel.ERROR,'INSERT: CPU time after sibling SOQL is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
        
        IF(accountsInTrigger.size() > 0){
            clientAgencies = [SELECT
                                 Id,Client__c,Agency__c
                              FROM
                                 Client_Agency_Relationship__c
                              WHERE
                                 Client__c In :accountsInTrigger
                              OR
                                 Agency__c In :accountsInTrigger];
        }
        
        
        System.debug(LoggingLevel.ERROR,'INSERT: Heap size after clientAgencies SOQL is ' + Limits.getHeapSize() + '/' + Limits.getLimitHeapSize());
        System.debug(LoggingLevel.ERROR,'INSERT: CPU time after clientAgencies SOQL is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
            
        FOR(Task t0 : tasks){
            
            String accountID0;
            String parentID0;
                
                  IF(t0.WhatId != NULL){
                          accountID0 = t0.WhatId;
                          parentID0 = parentMap.get(t0.WhatId);
                    }
                                        
                    ELSE IF(t0.WhatId == NULL && t0.WhoId != NULL && contactMap.get(t0.WhoId) != NULL){
                          accountID0 = contactMap.get(t0.WhoId);
                          parentID0 = parentMap.get(contactMap.get(t0.WhoId));
                    }
        
            FOR(Account a : childAccounts){
                
                IF(a.ParentId == accountID0){
                    
                    Related_Activity__c ra0 = new Related_Activity__c();
                    
                    IF(t0.Subject.length() > 80){
                        ra0.Name = t0.Subject.SubString(0,80);
                    }
                    ELSE{
                        ra0.Name = t0.Subject;
                    }
                    
                    IF(t0.WhoId != NULL && string.valueOf(t0.WhoId).startsWith('003')){
                        ra0.Name__c = t0.WhoId;
                    }
                    
                        ra0.Date__c = t0.ActivityDate;
                        ra0.Description__c = t0.Description;
                        ra0.Assigned_To__c = t0.OwnerId;
                        ra0.Activity_ID__c = t0.Id;
                        ra0.Relationship__c = 'Parent';
                        ra0.Account__c = a.Id;
                        ra0.Related_To__c = accountID0;
                
                    relatedActivitiesToAdd.add(ra0);
                    
                }
                
            }
            
            FOR(String a1 : siblingAccounts){
                    
                    IF(siblingParentMap.get(a1) == parentID0 && a1 != accountID0){
                    
                    Related_Activity__c ra1 = new Related_Activity__c();
                        
                        IF(t0.Subject.length() > 80){
                            ra1.Name = t0.Subject.SubString(0,80);
                        }
                        ELSE{
                            ra1.Name = t0.Subject;
                        }
                        
                        IF(t0.WhoId != NULL && string.valueOf(t0.WhoId).startsWith('003')){
                          ra1.Name__c = t0.WhoId;
                      }
                        
                    ra1.Date__c = t0.ActivityDate;
                    ra1.Description__c = t0.Description;
                    ra1.Assigned_To__c = t0.OwnerId;
                  ra1.Activity_ID__c = t0.Id;
                    ra1.Name__c = t0.WhoId;
                    ra1.Relationship__c = 'Sibling';
                    ra1.Account__c = a1;
                    ra1.Related_To__c = accountID0;
                    
                    relatedActivitiesToAdd.add(ra1);
                        
                    }
                }
            
            FOR(Client_Agency_Relationship__c car0 : clientAgencies){
                
                IF(car0.Agency__c == accountID0){
                
                    Related_Activity__c ra2 = new Related_Activity__c();
                    
                    IF(t0.Subject.length() > 80){
                        ra2.Name = t0.Subject.SubString(0,80);
                    }
                    ELSE{
                        ra2.Name = t0.Subject;
                    }
                    
                    IF(t0.WhoId != NULL && string.valueOf(t0.WhoId).startsWith('003')){
                          ra2.Name__c = t0.WhoId;
                      }
                    
                    ra2.Date__c = t0.ActivityDate;
                    ra2.Description__c = t0.Description;
                    ra2.Assigned_To__c = t0.OwnerId;
                    ra2.Activity_ID__c = t0.Id;
                    ra2.Relationship__c = 'Agency';
                    ra2.Account__c = car0.Client__c;
                    ra2.Related_To__c = accountID0;
                
                    relatedActivitiesToAdd.add(ra2);
                    
                }
            }
            
            FOR(Client_Agency_Relationship__c car1 : clientAgencies){
                
                IF(car1.Client__c == accountID0){
                
                    Related_Activity__c ra3 = new Related_Activity__c();
                    
                    IF(t0.Subject.length() > 80){
                        ra3.Name = t0.Subject.SubString(0,80);
                    }
                    ELSE{
                        ra3.Name = t0.Subject;
                    }
                    
                    IF(t0.WhoId != NULL && string.valueOf(t0.WhoId).startsWith('003')){
                          ra3.Name__c = t0.WhoId;
                      }
                    
                    ra3.Date__c = t0.ActivityDate;
                    ra3.Description__c = t0.Description;
                    ra3.Assigned_To__c = t0.OwnerId;
                    ra3.Activity_ID__c = t0.Id;
                    ra3.Relationship__c = 'Client';
                    ra3.Account__c = car1.Agency__c;
                    ra3.Related_To__c = accountID0;
               
                    relatedActivitiesToAdd.add(ra3);
                    
                }
            }
            
            FOR(String a4 : parentSet){
                
                IF(parentID0 == a4){
                
                    Related_Activity__c ra4 = new Related_Activity__c();
                    
                    IF(t0.Subject.length() > 80){
                        ra4.Name = t0.Subject.SubString(0,80);
                    }
                    ELSE{
                        ra4.Name = t0.Subject;
                    }
                    
                    IF(t0.WhoId != NULL && string.valueOf(t0.WhoId).startsWith('003')){
                          ra4.Name__c = t0.WhoId;
                      }
                    
                    ra4.Date__c = t0.ActivityDate;
                    ra4.Description__c = t0.Description;
                    ra4.Assigned_To__c = t0.OwnerId;
                    ra4.Activity_ID__c = t0.Id;
                    ra4.Relationship__c = 'Child';
                    ra4.Account__c = a4;
                    ra4.Related_To__c = accountID0;
               
                    relatedActivitiesToAdd.add(ra4);
                    
                }
          }
       
      } 
           
        System.debug(LoggingLevel.ERROR,'INSERT: Heap size after related activities creation is ' + Limits.getHeapSize() + '/' + Limits.getLimitHeapSize());
        System.debug(LoggingLevel.ERROR,'INSERT: CPU time after related activities creation is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
        
        
        IF(relatedActivitiesToAdd.size() > 0){
          INSERT relatedActivitiesToAdd;
        }
        
        System.debug(LoggingLevel.ERROR,'INSERT: Heap size after trigger completion is ' + Limits.getHeapSize() + '/' + Limits.getLimitHeapSize());
        System.debug(LoggingLevel.ERROR,'INSERT: CPU time after trigger completion is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
        
    }

}

And here is our task trigger, which calls all the classes:

trigger MainTriggerTask on Task (after insert, after update) {
    
    IF(Trigger.IsAfter){
        IF(Trigger.IsInsert){
            
            if(checkRecursive.runAfterInsertOnce()){
                
                ClassLeadContacted updater = new ClassLeadContacted();
                updater.updateLastContacted(Trigger.new);
                
                ClassLibraryTaskEmail updater1 = new ClassLibraryTaskEmail();
                updater1.sendEmail(Trigger.new);
                
                ClassRelatedActivitiesInsert updater2 = new ClassRelatedActivitiesInsert();
                updater2.insertRelatedActivities(Trigger.new);
                
            }
        }
        IF(Trigger.IsUpdate){
            
            if(checkRecursive.runAfterUpdateOnce()){
                
                ClassLeadContacted updater1 = new ClassLeadContacted();
                updater1.updateLastContacted(Trigger.new);
                
                ClassRelatedActivities updater2 = new ClassRelatedActivities();
                updater2.addRelatedActivities(Trigger.new,Trigger.oldMap);
                
                ClassTaskUpdateRelatedActivity updater3 = new ClassTaskUpdateRelatedActivity();
                updater3.updateRelatedActivity(Trigger.new,Trigger.oldMap);
                
            }
        }
    }
}

Let me know if you need any other info from me.

Thanks!
-Greg


Hey everyone,

I have an After Update trigger on the Account object that transfers the Contact owners to the current Account owner, while also setting a Contact field to a certain value. The problem is that when I manually transfer the account in Salesforce, the trigger doesn't work. But if I transfer the account by using something like Dataloader or Workbench, the trigger works.

Does manually transferring an Account in Salesforce not cause triggers to run?

Thanks!
-Greg
Hello everyone,

When our users edit a task, they receive this error:


MainTriggerTask: execution of AfterUpdate

caused by: System.QueryException: Non-selective query against large object type (more than 100000 rows). Consider an indexed filter or contact salesforce.com about custom indexing.
Even if a field is indexed a filter might still not be selective when:
1. The filter value includes null (for instance binding with a list that contains null)
2. Data skew exists whereby the number of matching rows is very large (for instance, filtering for a particular foreign key value that occurs many times)

Class.ClassTaskUpdateRelatedActivity.updateRelatedActivity: line 30, column 1
Trigger.MainTriggerTask: line 30, column 1




Here is the trigger that's causing the issue:

public class ClassTaskUpdateRelatedActivity{
    
    public void updateRelatedActivity(List<Task> tasks, Map<ID,Task> oldTasks){
        
        Set<String> tasksInTrigger = new Set<String>();
        Map<String,String> ownerMap = new Map<String,String>();
        Map<String,String> descriptionMap = new Map<String,String>();
        Map<String,String> subjectMap = new Map<String,String>();
        Map<String,Date> dateMap = new Map<String,Date>();
        List<Related_Activity__c> relatedActivitiesToUpdate = new List<Related_Activity__c>();
        
        FOR(Task t : tasks){
            IF(t.OwnerId != oldTasks.get(t.Id).OwnerId || t.Description != oldTasks.get(t.Id).Description || t.Subject != oldTasks.get(t.Id).Subject
               || t.ActivityDate != oldTasks.get(t.Id).ActivityDate){
                
                tasksInTrigger.add(t.Id);
                ownerMap.put(t.Id,t.OwnerId);
                descriptionMap.put(t.Id,t.Description);
                subjectMap.put(t.Id,t.Subject);
                dateMap.put(t.Id,t.ActivityDate);
                
            }
        }
        
        IF(tasksInTrigger.size() > 0){
            FOR(Related_Activity__c ra : [SELECT
                                            Id,Assigned_To__c,Activity_ID__c,Description__c,Name,Date__c
                                          FROM
                                            Related_Activity__c
                                          WHERE
                                            Activity_ID__c In :tasksInTrigger]){
                                                
                                                IF(subjectMap.get(ra.Activity_ID__c).length() > 80){
                                                    ra.Name = subjectMap.get(ra.Activity_ID__c).SubString(0,80);
                                                }
                                                ELSE{
                                                    ra.Name = subjectMap.get(ra.Activity_ID__c);
                                                }
                                              
                                              ra.Assigned_To__c = ownerMap.get(ra.Activity_ID__c);
                                              ra.Description__c = descriptionMap.get(ra.Activity_ID__c);
                                              ra.Date__c = dateMap.get(ra.Activity_ID__c);
                                                
                                              relatedActivitiesToUpdate.add(ra);
                                              
                                          }
        }
        
        IF(relatedActivitiesToUpdate.size() > 0){
            
            UPDATE relatedActivitiesToUpdate;
            
        }
        
    }

}

Some background on what's going on here:

We have a custom object called "Related Activity", which is basically a copy of a task. It's attached to all the accounts related to that respective task's account. So for example, if you create a task on an account that has a parent account and two sibling accounts, then a Related Activity will be created for the parent and two siblings. It's a copy of that task.

The trigger posted above simply updates the related activites when a task has been updated. But as you can see, when our users try editing a task, they receive the error above.

Any idea why that error would occur? One thing I should mention is that there may not be any Related Activities for a given task, since the account may not have any related accounts. I'm not sure if that would cause an issue.

Let me know if you need any other info from me!

Thanks!
-Greg
Hello everyone,

I made a thread on here a few weeks ago about how I couldn't deploy a new trigger, because a previous 'After' trigger I deployed was causing too many SOQL queries in my new 'Before' trigger.

Anywho, a fine gentleman on here told me I needed to check the aforementioned 'After' trigger for recursion, so that it wouldn't run more than once. That allowed me to deploy the new 'Before' trigger.

So what is the problem now? That 'After' trigger that I'm checking for recursion....it doesn't work anymore. I only checked today to see if it was still working, but it seems it hasn't been working since I made that change to the code. When I remove the recursion check and test out the trigger in the sandbox, it works again.

Why do I think this is? Because the purpose of that 'After' trigger is to update another opportunity (the same object). I'm assuming it won't work if it only runs once. Perhaps I have to run it twice? If so, how can I make that change? Please keep in mind that I'm still a newb to coding.


Here is the class I'm using to check for recursion:

public Class checkRecursive{
   
    private static boolean run = true;
   
    public static boolean runOnce(){
       
    if(run){
     run=false;
     return true;  
    }
    else{
        return run;
    }
       
    }
}




Here is the trigger that no longer works:

trigger RenewalProcess on Opportunity (after insert, after update) {
   
     if(checkRecursive.runOnce()){
   
   Set<String> allOpps = new Set<String>();
    for(Opportunity renewalOpp : Trigger.new) {
        if (renewalOpp.Renewed_Opportunity__c != null) {
            allOpps.add(renewalOpp.Renewed_Opportunity__c);
          }
    }

    List<Opportunity> potentialOpps = [SELECT Id FROM Opportunity WHERE Id IN :allOpps];

    Map<String,Opportunity> opportunityMap = new Map<String,Opportunity>();
        for (Opportunity o : potentialOpps) {
            opportunityMap.put(o.id,o);
        }
   
    List<Opportunity> firstOppsToUpdate = new List<Opportunity>();

        for (Opportunity renewalOpp : Trigger.new) {
             if (renewalOpp.Renewed_Opportunity__c != null) {
             Opportunity renewedOpp = opportunityMap.get(renewalOpp.Renewed_Opportunity__c);
             renewedOpp.Renewal_Process_Checkbox__c = TRUE;
             firstOppsToUpdate.add(renewedOpp);
           }
           
        }

    update firstOppsToUpdate;
     
     List<Opportunity> oppsToUpdate = new List<Opportunity>();
       
        for (Opportunity renewalOpp : Trigger.new) {
            if (renewalOpp.Renewed_Opportunity__c != null && renewalOpp.StageName.equals('Closed Won')) {
                Opportunity renewedOpp = opportunityMap.get(renewalOpp.Renewed_Opportunity__c);
                renewedOpp.Renewal_Status__c = 'Renewed';
                oppsToUpdate.add(renewedOpp);
            }
            else if(renewalOpp.Renewed_Opportunity__c != null && !renewalOpp.IsClosed) {
                Opportunity renewedOpp = opportunityMap.get(renewalOpp.Renewed_Opportunity__c);
                renewedOpp.Renewal_Status__c = 'In Negotiations';
                oppsToUpdate.add(renewedOpp);
            }
            else if(renewalOpp.Renewed_Opportunity__c != null && (renewalOpp.StageName.equals('Closed Lost') || renewalOpp.StageName.equals('Closed Stalled'))) {
                Opportunity renewedOpp = opportunityMap.get(renewalOpp.Renewed_Opportunity__c);
                renewedOpp.Renewal_Status__c = 'Did Not Renew';
                oppsToUpdate.add(renewedOpp);
            }
           
        }
   
    update oppsToUpdate;
        
     }
   
}



Let me know if you need any other info from me!

Thanks,
Greg
Hey everyone,

I have a VisualForce page embedded within our standard Opportunity layout. Up until now this VF page has just been a table with custom checkbox fields using "inputCheckbox". When a user went to an Opportunity the page would open as normal at the top of the Opportunity page.

However, I've since added an "inputField" to the VF page, which allows the user to fill in one of our existing Lookup fields. The problem is that whenever the user goes to an Opportunity now, the Opportunity will open and then the user is directed down to the VF page instead of staying at the top of the Opportunity.

Is there a reason why the "inputField" parameter causes the screen to immediately redirect down to the VF page?

Thanks,
Greg
I have a VisualForce page embedded in my Opportunity layout. If a user makes changes to the Opportunity fields and then also makes changes in the embedded VisualForce page, they can't save both changes. They either have to save the Opportunity or save the VisualForce page, losing their changes to the other one.

Is there any way to let our users save both changes at the same time? For reference, see below for the VisualForce Page and Extension involved:


VisualForce Page:
<apex:page standardController="Opportunity" Extensions="ControllerContactSelectionOpportunity">
    
    <style>
        .added {
            background-color: #a4f3fc;
        }
        .removed {
            background-color: white;
        }
    </style>
    
    <apex:form >
    
        <apex:pageBlock >
            
            <apex:pageBlockTable  value="{!Records}" var="Con">
                
                <apex:column headerValue="Add To Opportunity" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.attach}"/>
                </apex:column>
                <apex:column headerValue="Name" value="{!Con.Name}" styleClass="{!IF(Con.attach == TRUE,'added','removed')}"/>
                <apex:column headerValue="Main User" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.mainUser}"/>
                </apex:column>
                <apex:column headerValue="General User" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.genUser}"/>
                </apex:column>
                <apex:column headerValue="Billing" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.billing}"/>
                </apex:column>
                <apex:column headerValue="E-Commerce" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.eComm}"/>
                </apex:column>
                <apex:column headerValue="Email" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.email}"/>
                </apex:column>
                <apex:column headerValue="CRM" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.crm}"/>
                </apex:column>
                <apex:column headerValue="Junior Decision Maker" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.junior}"/>
                </apex:column>
                <apex:column headerValue="Senior Decision Maker" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.senior}"/>
                </apex:column>
                <apex:column headerValue="Signature" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.signature}"/>
                </apex:column>
                <apex:column headerValue="Coach" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.coach}"/>
                </apex:column>
                <apex:column headerValue="Champion" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.champion}"/>
                </apex:column>
                <apex:column headerValue="I Don't Know" styleClass="{!IF(Con.attach == TRUE,'added','removed')}">
                    <apex:inputCheckbox value="{!Con.idk}"/>
                </apex:column>
                
            </apex:pageBlockTable>
            
            <Apex:pageBlockButtons location="bottom">
            
                <apex:commandButton action="{!customSave}" value="Save"/>
            
            </Apex:pageBlockButtons>
            
            <apex:outputPanel rendered="{!refreshPage}">
               <script>
                  window.top.location='/{!Opportunity.Id}';
               </script>
            </apex:outputPanel>
        
        </apex:pageBlock>
    
    </apex:form>
    
</apex:page>


Extension:
public class ControllerContactSelectionOpportunity{
    
    public class contactAttach{
        
        public string name {get;set;}
        public Boolean attach {get; set;}
        public Boolean mainUser {get; set;}
        public Boolean genUser {get; set;}
        public Boolean billing {get; set;}
        public Boolean eComm {get; set;}
        public Boolean email {get; set;}
        public Boolean crm {get; set;}
        public Boolean junior {get; set;}
        public Boolean senior {get; set;}
        public Boolean signature {get; set;}
        public Boolean coach {get; set;}
        public Boolean champion {get; set;}
        public Boolean idk {get; set;}
        public Contact con {get; set;}
        
    }
    
    public List<contactAttach> Records {get; set;}
    public Boolean refreshPage {get; set;}
    public Opportunity Record;
    public Set<String> roleContacts;
    public Map<String,OpportunityContactRole> roleMap;
    public Map<String,String> roleIDMap;
    
    public ControllerContactSelectionOpportunity(ApexPages.StandardController controller){
        
        Records = new List<contactAttach>();
        List<contactAttach> addedRecords = new List<contactAttach>();
        List<contactAttach> removedRecords = new List<contactAttach>();
        Record = (Opportunity) controller.getRecord();
        String AccountId = [SELECT AccountId FROM Opportunity WHERE Id = :Record.Id LIMIT 1].AccountId;
        roleContacts = new Set<String>();
        roleMap = new Map<String,OpportunityContactRole>();
        roleIDMap = new Map<String,String>();
        refreshPage = FALSE;
        
        FOR(OpportunityContactRole ocr : [SELECT
                                         	Id,
                                         	ContactId
                                          FROM
                                         	OpportunityContactRole
                                          WHERE
                                          	OpportunityId = :Record.Id]){
                                              
                                              roleContacts.add(ocr.ContactId);
                                              roleMap.put(ocr.ContactId,ocr);
                                              roleIDMap.put(ocr.ContactId,ocr.Id);
                                              
                                          }
        
        FOR(Contact c : [SELECT 
                             	Id, 
                             	Name,
                             	Main_User__c, 
                             	General_User__c,
                             	Billing__c,
                             	E_Commerce__c,
                             	Email__c,
                             	CRM__c,
                             	Junior_Decision_Maker__c,
                             	Senior_Decision_Maker__c,
                             	Signature__c,
                             	Coach__c,
                             	Champion__c,
                             	I_Don_t_Know__c
                             FROM 
                             	Contact 
                             WHERE 
                             	AccountId = :AccountId
                        	 ORDER BY Name ASC]){
                                    
                                    contactAttach ca = new contactAttach();
                                    ca.Name = c.Name;
                                    ca.attach = roleContacts.contains(c.Id) ? TRUE : FALSE;
                                    ca.mainUser = c.Main_User__c;
                                    ca.genUser = c.General_User__c;
                                    ca.billing = c.Billing__c;
                                    ca.eComm = c.E_Commerce__c;
                                    ca.email = c.Email__c;
                                    ca.crm = c.CRM__c;
                                    ca.junior = c.Junior_Decision_Maker__c;
                                    ca.senior = c.Senior_Decision_Maker__c;
                                    ca.signature = c.Signature__c;
                                    ca.coach = c.Coach__c;
                                    ca.champion = c.Champion__c;
                                    ca.idk = c.I_Don_t_Know__c;
                                    ca.con = c;
                                 
                                 IF(ca.attach == TRUE){
                                     
                                     addedRecords.add(ca);
                                     
                                 }
                                 ELSE{
                                     
                                     removedRecords.add(ca);
                                     
                                 }
            
        }
        
        FOR(contactAttach ar : addedRecords){
            
            Records.add(ar);
            
        }
        
        FOR(contactAttach rr : removedRecords){
            
            Records.add(rr);
            
        }
        
        
    }
    
    public PageReference CustomSave(){
        
        Set<String> contactsChanged = new Set<String>();
        List<Contact> contactsToUpdate = new List<Contact>();
        List<OpportunityContactRole> rolesToAdd = new List<OpportunityContactRole>();
        List<OpportunityContactRole> rolesToChange = new List<OpportunityContactRole>();
        List<OpportunityContactRole> rolesToDelete = new List<OpportunityContactRole>();
        
        FOR(contactAttach cna : Records){
                
            IF(cna.con.Main_User__c != cna.mainUser || cna.con.General_User__c != cna.genUser ||
               cna.con.Billing__c != cna.billing || cna.con.E_Commerce__c != cna.eComm ||
               cna.con.Email__c != cna.email || cna.con.CRM__c != cna.crm ||
               cna.con.Junior_Decision_Maker__c != cna.junior ||  cna.con.Senior_Decision_Maker__c != cna.senior ||
               cna.con.Signature__c != cna.signature || cna.con.Coach__c != cna.coach ||
               cna.con.Champion__c != cna.champion || cna.con.I_Don_t_Know__c != cna.idk){
                
                cna.con.Main_User__c = cna.mainUser;
                cna.con.General_User__c = cna.genUser;
                cna.con.Billing__c = cna.billing;
                cna.con.E_Commerce__c = cna.eComm;
                cna.con.Email__c = cna.email;
                cna.con.CRM__c = cna.crm;
                cna.con.Junior_Decision_Maker__c = cna.junior;
                cna.con.Senior_Decision_Maker__c = cna.senior;
                cna.con.Signature__c = cna.signature;
                cna.con.Coach__c = cna.coach;
                cna.con.Champion__c = cna.champion;
                cna.con.I_Don_t_Know__c = cna.idk;
                contactsToUpdate.add(cna.con);
                contactsChanged.add(cna.con.Id);
                
            }
            
            IF(cna.attach == TRUE && !roleContacts.contains(cna.con.Id)){
                
                OpportunityContactRole cr = new OpportunityContactRole();
                cr.ContactId = cna.con.Id;
                cr.OpportunityId = Record.Id;
                cr.Role = cna.mainUser == TRUE ? 'Main User' 
                    	: cna.genUser == TRUE ? 'General User' 
                    	: cna.billing == TRUE ? 'Billing' 
                    	: cna.eComm == TRUE ? 'E-Commerce' 
                    	: cna.email == TRUE ? 'Email' 
                    	: cna.crm == TRUE ? 'CRM' 
                    	: cna.junior == TRUE ? 'Junior' 
                    	: cna.senior == TRUE ? 'Senior' 
                    	: cna.signature == TRUE ? 'Signature' 
                    	: cna.coach == TRUE ? 'Coach' 
                    	: cna.champion == TRUE ? 'Champion' 
                    	: 'Other';
                rolesToAdd.add(cr);
                
            }
            ELSE IF(cna.attach == TRUE && roleContacts.contains(cna.con.Id) && contactsChanged.contains(cna.con.Id)){
                
                OpportunityContactRole cru = new OpportunityContactRole();
                cru.Id = roleIDMap.get(cna.con.Id);
                cru.Role = cna.mainUser == TRUE ? 'Main User' 
                    	 : cna.genUser == TRUE ? 'General User' 
                    	 : cna.billing == TRUE ? 'Billing' 
                    	 : cna.eComm == TRUE ? 'E-Commerce' 
                    	 : cna.email == TRUE ? 'Email' 
                    	 : cna.crm == TRUE ? 'CRM' 
                    	 : cna.junior == TRUE ? 'Junior' 
                    	 : cna.senior == TRUE ? 'Senior' 
                    	 : cna.signature == TRUE ? 'Signature' 
                    	 : cna.coach == TRUE ? 'Coach' 
                    	 : cna.champion == TRUE ? 'Champion' 
                    	 : 'Other';
                rolesToChange.add(cru);
                
            }
            ELSE IF(cna.attach == FALSE && roleContacts.contains(cna.con.Id)){
                
                rolesToDelete.add(roleMap.get(cna.con.Id));
                
            }
            
        }
        
        IF(!contactsToUpdate.isEmpty()){
            
            UPDATE contactsToUpdate;
            
        }
    
        IF(!rolesToAdd.isEmpty()){
            
            INSERT rolesToAdd;
            
        }
        
        IF(!rolesToChange.isEmpty()){
            
            UPDATE rolesToChange;
            
        }
        
        IF(!rolesToDelete.isEmpty()){
            
            DELETE rolesToDelete;
            
        }
        
        refreshPage = TRUE;
        RETURN null;
        
    }

}


Thanks,
Greg
Hey everyone,

We have five checkbox fields on the Contact object called:
  • Main User
  • General User
  • Signature Contact
  • Billing Contact
  • Stakeholder
We want to have a VisualForce page embedded on the Account page that lists all the Contacts on that respective Account along with a column for each of the checkbox fields, showing the current values. So it would look like this:

User-added image

It would be ideal if the user can just visit a certain Account, scroll down to the embedded VisualForce table (seen above), check and uncheck any boxes they need to, and then click Save, which would update the values on the Contacts. If the user needs to click an "Edit" button first in order to check/uncheck any boxes, then that would fine (but not ideal obviously).

I would be hugely appreciative if someone could provide example VisualForce and Controller code for something like this.  I have minor experience with VisualForce, but this is a step above what I've done. 

Thanks!
Greg 
Hey everyone,

I have a SOQL query of the Contact object that includes a relationship query of the Tasks associated to the Contacts:
 
FOR(Contact c1 : [SELECT
                         	Id,Last_Contacted__c
                            (SELECT 
                             	Id,Completed_Time_Formula__c 
                             FROM 
                             	Tasks 
                             WHERE 
                             	CreatedById != '005A0000004PQwZ' AND Completed_Time_Formula__c != NULL 
                             ORDER BY Completed_Time_Formula__c
                             DESC LIMIT 1)
                          FROM
                         	Contact
                          WHERE
                          	Id In :contactsInTrigger]){

        //code here

}

Right now the Task query doesn't seem to include archived tasks. I tried to include "ALL ROWS" somewhere in the Task query, but I kept getting errors. Then I tried adding "(IsArchived = TRUE OR IsArchived = FALSE)" to the query, but that didn't seem to include archived tasks when I tested the code.

Is there a way to include all Tasks (both archived and unarchived) in a Task relationship query? Am I doing it wrong?

Thanks,
Greg
I created a button on a custom object: Policy__c. 
I want the button to fire and call an Apex Class. The method of the class I am calling takes a Set called ids. 

Here is my JavaScript:
 
{!REQUIRESCRIPT("/soap/ajax/25.0/connection.js")}
{!REQUIRESCRIPT("/soap/ajax/25.0/apex.js")}

var mySet = new Set();
mySet.add({!Policy__c.Id});

var result = sforce.apex.execute("ClientDelta","sendQuery",{ids: mySet});
alert(result);
window.location.reload();

The error I am recieving when button is selected is the following:
 
A problem with the OnClick JavaScript for this button or link was encountered:

Can't find variable: a0019000002vmyy

It is showing the records Id as the variable that it can't find. Any help would be appreciated. 

Just for refrence here is the class and method I am trying to call. 
 
global class ClientDelta {
    
@future (callout=true)
@RemoteAction
global static void sendQuery(Set<ID> ids) {  ...... }

 
Hey everyone,

When trying to delete an Apex class via the Force IDE I'm getting the "Destination organization must be different from the Project organization" error. I found this article, which tells me to go to the ".settings" folder and set the endpointServer to a blank value.

Here is the tutorial picture provided by the article:

User-added image



The problem is that I don't see the ".settings" folder anywhere in my instance:

User-added image

I'm guessing the article was written for an older verion of Force IDE. Does anyone know where to find the ".settings" folder (and therefore the endpointServer attribute)?

Thanks!
-Greg
Hey everyone,

I had to create my first custom controller that allows for one of my visual flows to be re-directed to the created record (an Account) at the end of the flow. The controller works great, but now I need to create my first custom controller test class.

Here is the custom controller:
 
public class ControllerNewSubAccount{

    public ControllerNewSubAccount(ApexPages.StandardController controller) {

    }

    
 public Flow.Interview.Create_Account_w_Parent crAcc {get;set;}
    
 public PageReference prFinishLocation {
     
     get{
         
         PageReference prRef = new PageReference('/' + strOutputVariable);
         prRef.setRedirect(true);
         return prRef;
         
     }
     set{prFinishLocation = value;}
     
 }

 public String strOutputVariable {
     
     get{
         
         String strTemp = '';
        
         if(crAcc != null) {
             
         	strTemp = string.valueOf(crAcc.getVariableValue('AccountID'));
             
         }
        
         return strTemp;
         
     }
     set{strOutputVariable = value;}
     
 }
 
}

Here is the beginnings of the test class I created (but obviously this only covers the first few lines):
 
@isTest
public class TestVisualforceControllers {
    
    static testmethod void testControllerNewSubAccount(){
        
        Account a = New Account(Name='Tester');
        INSERT a;
        ApexPages.StandardController sc = new ApexPages.standardController(a);
        ControllerNewSubAccount e = new ControllerNewSubAccount(sc);
        
    }

}

I have no idea how to approach this. I'm assuming I need to trigger the flow somehow, or something along those lines.

Thanks,
Greg
Hey everyone,

We've been exceeding our daily API requests limit (140,000). I checked the "API Usage - Last 7 Days" report, and it seems that the vast majority of the requests are under my name, but there's no "Client Id" associated with them. So I have no idea where they're coming from.

Is there any way to identify the source of those requests?

Thanks,
Greg
Hey Everyone,

I have a task trigger that creates a bunch of records once a task is inserted. This trigger works fine when I manually create a task in Salesforce. But if we use the BCC-to-Salesforce address to log an email as a task, the trigger doesn't seem to run. I've tried manually creating tasks that have the same exact same values as the tasks created via BCC, and the manuallly created tasks will run the trigger while the BCC-created tasks do not.

Is there something I need to take into account? Does BCCing simply not support triggers?


Here is the class I'm testing:

public class ClassRelatedActivitiesInsert {
    
    public void insertRelatedActivities(List<Task> tasks){
        
        Set<String> accountsInTrigger = new Set<String>();
        Set<String> contactsInTrigger = new Set<String>();
        Set<String> parentSet = new Set<String>();
        Set<String> clientSet = new Set<String>();
        Set<String> agencySet = new Set<String>();
        Set<String> siblingAccounts = new Set<String>();
        
        Map<String,String> contactMap = new Map<String,String>();
        Map<String,String> parentMap = new Map<String,String>();
        Map<String,String> siblingParentMap = new Map<String,String>();
        Map<String,String> clientAgencyMap = new Map<String,String>();
        Map<String,String> agencyClientMap = new Map<String,String>();
        
        List<Account> childAccounts = new List<Account>();
        List<Client_Agency_Relationship__c> clientAgencies = new List<Client_Agency_Relationship__c>();
        List<Related_Activity__c> relatedActivitiesToAdd = new List<Related_Activity__c>();
        
        
    FOR(Task t : tasks){        
                IF(t.WhatId != NULL && string.valueOf(t.WhatId).startsWith('001')){
                    accountsInTrigger.add(t.WhatId);
                }
                ELSE IF(t.WhatId == NULL && t.WhoId != NULL && string.valueOf(t.WhoId).startsWith('003')){
                        contactsInTrigger.add(t.WhoId);
                    }       
        }
        
        System.debug(LoggingLevel.ERROR,'INSERT: Heap size after initial task loop is ' + Limits.getHeapSize() + '/' + Limits.getLimitHeapSize());
        System.debug(LoggingLevel.ERROR,'INSERT: CPU time after initial task loop is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
        
        IF(contactsInTrigger.size() > 0){
            FOR(Contact c : [SELECT
                                Id,AccountId
                             FROM
                                Contact
                             WHERE
                                Id In :contactsInTrigger
                             AND
                              AccountId != NULL]){
                                 
                                     contactMap.put(c.Id,c.AccountId);
                                     accountsInTrigger.add(c.AccountId);
                                 
                                }
        }
        
        System.debug(LoggingLevel.ERROR,'INSERT: Heap size after account contacts SOQL is ' + Limits.getHeapSize() + '/' + Limits.getLimitHeapSize());
        System.debug(LoggingLevel.ERROR,'INSERT: CPU time after account contacts SOQL is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
        
        IF(accountsInTrigger.size() > 0){
            FOR(Account ca : [SELECT 
                                 Id,ParentId
                              FROM 
                                 Account
                              WHERE
                                 ParentId In :accountsInTrigger
                              OR
                                 (ParentId != NULL
                              AND
                                  Id In :accountsInTrigger)]){
                                      
                                      IF(accountsInTrigger.contains(ca.ParentId)){
                                          childAccounts.add(ca);
                                      }
                                      IF(accountsInTrigger.contains(ca.Id) && ca.ParentId != NULL){
                                          parentMap.put(ca.Id,ca.ParentId);
                                          parentSet.add(ca.ParentId);
                                      }
                                      
                                  }
        }
        
        System.debug(LoggingLevel.ERROR,'INSERT: Heap size after parent/child account SOQL is ' + Limits.getHeapSize() + '/' + Limits.getLimitHeapSize());
        System.debug(LoggingLevel.ERROR,'INSERT: CPU time after parent/child account SOQL is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
        
        IF(parentSet.size() > 0){
            FOR(Account sa : [SELECT
                                 Id, ParentId
                              FROM
                                 Account
                              WHERE
                                 ParentId In :parentSet]){
                                  
                                    siblingParentMap.put(sa.Id,sa.ParentId);
                                    siblingAccounts.add(sa.Id);
                                  
                                }
        }
        
        System.debug(LoggingLevel.ERROR,'INSERT: Heap size after sibling SOQL is ' + Limits.getHeapSize() + '/' + Limits.getLimitHeapSize());
        System.debug(LoggingLevel.ERROR,'INSERT: CPU time after sibling SOQL is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
        
        IF(accountsInTrigger.size() > 0){
            clientAgencies = [SELECT
                                 Id,Client__c,Agency__c
                              FROM
                                 Client_Agency_Relationship__c
                              WHERE
                                 Client__c In :accountsInTrigger
                              OR
                                 Agency__c In :accountsInTrigger];
        }
        
        
        System.debug(LoggingLevel.ERROR,'INSERT: Heap size after clientAgencies SOQL is ' + Limits.getHeapSize() + '/' + Limits.getLimitHeapSize());
        System.debug(LoggingLevel.ERROR,'INSERT: CPU time after clientAgencies SOQL is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
            
        FOR(Task t0 : tasks){
            
            String accountID0;
            String parentID0;
                
                  IF(t0.WhatId != NULL){
                          accountID0 = t0.WhatId;
                          parentID0 = parentMap.get(t0.WhatId);
                    }
                                        
                    ELSE IF(t0.WhatId == NULL && t0.WhoId != NULL && contactMap.get(t0.WhoId) != NULL){
                          accountID0 = contactMap.get(t0.WhoId);
                          parentID0 = parentMap.get(contactMap.get(t0.WhoId));
                    }
        
            FOR(Account a : childAccounts){
                
                IF(a.ParentId == accountID0){
                    
                    Related_Activity__c ra0 = new Related_Activity__c();
                    
                    IF(t0.Subject.length() > 80){
                        ra0.Name = t0.Subject.SubString(0,80);
                    }
                    ELSE{
                        ra0.Name = t0.Subject;
                    }
                    
                    IF(t0.WhoId != NULL && string.valueOf(t0.WhoId).startsWith('003')){
                        ra0.Name__c = t0.WhoId;
                    }
                    
                        ra0.Date__c = t0.ActivityDate;
                        ra0.Description__c = t0.Description;
                        ra0.Assigned_To__c = t0.OwnerId;
                        ra0.Activity_ID__c = t0.Id;
                        ra0.Relationship__c = 'Parent';
                        ra0.Account__c = a.Id;
                        ra0.Related_To__c = accountID0;
                
                    relatedActivitiesToAdd.add(ra0);
                    
                }
                
            }
            
            FOR(String a1 : siblingAccounts){
                    
                    IF(siblingParentMap.get(a1) == parentID0 && a1 != accountID0){
                    
                    Related_Activity__c ra1 = new Related_Activity__c();
                        
                        IF(t0.Subject.length() > 80){
                            ra1.Name = t0.Subject.SubString(0,80);
                        }
                        ELSE{
                            ra1.Name = t0.Subject;
                        }
                        
                        IF(t0.WhoId != NULL && string.valueOf(t0.WhoId).startsWith('003')){
                          ra1.Name__c = t0.WhoId;
                      }
                        
                    ra1.Date__c = t0.ActivityDate;
                    ra1.Description__c = t0.Description;
                    ra1.Assigned_To__c = t0.OwnerId;
                  ra1.Activity_ID__c = t0.Id;
                    ra1.Name__c = t0.WhoId;
                    ra1.Relationship__c = 'Sibling';
                    ra1.Account__c = a1;
                    ra1.Related_To__c = accountID0;
                    
                    relatedActivitiesToAdd.add(ra1);
                        
                    }
                }
            
            FOR(Client_Agency_Relationship__c car0 : clientAgencies){
                
                IF(car0.Agency__c == accountID0){
                
                    Related_Activity__c ra2 = new Related_Activity__c();
                    
                    IF(t0.Subject.length() > 80){
                        ra2.Name = t0.Subject.SubString(0,80);
                    }
                    ELSE{
                        ra2.Name = t0.Subject;
                    }
                    
                    IF(t0.WhoId != NULL && string.valueOf(t0.WhoId).startsWith('003')){
                          ra2.Name__c = t0.WhoId;
                      }
                    
                    ra2.Date__c = t0.ActivityDate;
                    ra2.Description__c = t0.Description;
                    ra2.Assigned_To__c = t0.OwnerId;
                    ra2.Activity_ID__c = t0.Id;
                    ra2.Relationship__c = 'Agency';
                    ra2.Account__c = car0.Client__c;
                    ra2.Related_To__c = accountID0;
                
                    relatedActivitiesToAdd.add(ra2);
                    
                }
            }
            
            FOR(Client_Agency_Relationship__c car1 : clientAgencies){
                
                IF(car1.Client__c == accountID0){
                
                    Related_Activity__c ra3 = new Related_Activity__c();
                    
                    IF(t0.Subject.length() > 80){
                        ra3.Name = t0.Subject.SubString(0,80);
                    }
                    ELSE{
                        ra3.Name = t0.Subject;
                    }
                    
                    IF(t0.WhoId != NULL && string.valueOf(t0.WhoId).startsWith('003')){
                          ra3.Name__c = t0.WhoId;
                      }
                    
                    ra3.Date__c = t0.ActivityDate;
                    ra3.Description__c = t0.Description;
                    ra3.Assigned_To__c = t0.OwnerId;
                    ra3.Activity_ID__c = t0.Id;
                    ra3.Relationship__c = 'Client';
                    ra3.Account__c = car1.Agency__c;
                    ra3.Related_To__c = accountID0;
               
                    relatedActivitiesToAdd.add(ra3);
                    
                }
            }
            
            FOR(String a4 : parentSet){
                
                IF(parentID0 == a4){
                
                    Related_Activity__c ra4 = new Related_Activity__c();
                    
                    IF(t0.Subject.length() > 80){
                        ra4.Name = t0.Subject.SubString(0,80);
                    }
                    ELSE{
                        ra4.Name = t0.Subject;
                    }
                    
                    IF(t0.WhoId != NULL && string.valueOf(t0.WhoId).startsWith('003')){
                          ra4.Name__c = t0.WhoId;
                      }
                    
                    ra4.Date__c = t0.ActivityDate;
                    ra4.Description__c = t0.Description;
                    ra4.Assigned_To__c = t0.OwnerId;
                    ra4.Activity_ID__c = t0.Id;
                    ra4.Relationship__c = 'Child';
                    ra4.Account__c = a4;
                    ra4.Related_To__c = accountID0;
               
                    relatedActivitiesToAdd.add(ra4);
                    
                }
          }
       
      } 
           
        System.debug(LoggingLevel.ERROR,'INSERT: Heap size after related activities creation is ' + Limits.getHeapSize() + '/' + Limits.getLimitHeapSize());
        System.debug(LoggingLevel.ERROR,'INSERT: CPU time after related activities creation is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
        
        
        IF(relatedActivitiesToAdd.size() > 0){
          INSERT relatedActivitiesToAdd;
        }
        
        System.debug(LoggingLevel.ERROR,'INSERT: Heap size after trigger completion is ' + Limits.getHeapSize() + '/' + Limits.getLimitHeapSize());
        System.debug(LoggingLevel.ERROR,'INSERT: CPU time after trigger completion is ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime());
        
    }

}

And here is our task trigger, which calls all the classes:

trigger MainTriggerTask on Task (after insert, after update) {
    
    IF(Trigger.IsAfter){
        IF(Trigger.IsInsert){
            
            if(checkRecursive.runAfterInsertOnce()){
                
                ClassLeadContacted updater = new ClassLeadContacted();
                updater.updateLastContacted(Trigger.new);
                
                ClassLibraryTaskEmail updater1 = new ClassLibraryTaskEmail();
                updater1.sendEmail(Trigger.new);
                
                ClassRelatedActivitiesInsert updater2 = new ClassRelatedActivitiesInsert();
                updater2.insertRelatedActivities(Trigger.new);
                
            }
        }
        IF(Trigger.IsUpdate){
            
            if(checkRecursive.runAfterUpdateOnce()){
                
                ClassLeadContacted updater1 = new ClassLeadContacted();
                updater1.updateLastContacted(Trigger.new);
                
                ClassRelatedActivities updater2 = new ClassRelatedActivities();
                updater2.addRelatedActivities(Trigger.new,Trigger.oldMap);
                
                ClassTaskUpdateRelatedActivity updater3 = new ClassTaskUpdateRelatedActivity();
                updater3.updateRelatedActivity(Trigger.new,Trigger.oldMap);
                
            }
        }
    }
}

Let me know if you need any other info from me.

Thanks!
-Greg


Hey everyone,

Here is the issue we need to resolve:

1) A lead is converted to an opportunity without being in a campaign yet
2) The lead is now the Primary Contact on the opportunity
3) After a while that Primary Contact gets put in a campaign

The issue?

4) The 'Primary Campaign Source' field on the opportunity needs to be populated with the last campaign the Primary Contact was added to

Can I do this with a regular Apex trigger? Or do I need to use batch Apex?

Thanks!
-Greg
Greetings everyone,

I recently changed all my triggers to classes and then created a main trigger for each object that calls the classes for each respective object.

Anywho, my opportunity trigger calls quite a few classes. The issue is that if I don't add a recursion check, I can't deploy the trigger due to the SOQL query limit being broken. But if I do add the recursion check, only the Before triggers work. Not the After triggers.


Here is the trigger (with the recursion call up top):

trigger MainTriggerOpportunity on Opportunity (before insert, before update, after insert, after update) {
   
    if(checkRecursive.runOnce()){
   
    if(trigger.isBefore){
        if(trigger.isInsert){
            ClassOppIndustry updater = new ClassOppIndustry();
            updater.updateOppIndustry(trigger.new);
           
            ClassRenewalDate updater1 = new ClassRenewalDate();
            updater1.updateRenewalDate(trigger.new);
        }
        if(trigger.isUpdate){
            ClassOppIndustry updater = new ClassOppIndustry();
            updater.updateOppIndustry(trigger.new);
           
            ClassRenewalDate updater1 = new ClassRenewalDate();
            updater1.updateRenewalDate(trigger.new);
        }
    }
   
    if(trigger.isAfter){
        if(trigger.isInsert){
            ClassRenewalProcess updater = new ClassRenewalProcess();
            updater.updateRenewalStatus(Trigger.new);
           
            ClassOppBrandCreate updater1 = new ClassOppBrandCreate();
            updater1.addBrand(trigger.new);
        }
        if(trigger.isUpdate){
            ClassRenewalProcess updater = new ClassRenewalProcess();
            updater.updateRenewalStatus(Trigger.new);
           
            ClassOppBrandCreate updater1 = new ClassOppBrandCreate();
            updater1.addBrand(trigger.new);
           
            ClassChatterAlerts updater2 = new ClassChatterAlerts();
            updater2.addChatterAlert(Trigger.new,Trigger.oldMap);
        }
    }
}
   
}




Here is the recursion check class:

public Class checkRecursive{
   
    private static boolean run = true;
   
    public static boolean runOnce(){
       
    if(run){
     run=false;
     return true;  
    }
    else{
        return run;
    }
       
    }
}



Perhaps I have to allow the trigger to run twice? I'm a newb, so any help would be much appreciated!

Thanks,
Greg
Hey everyone,

Let me briefly explain the trigger I wrote (my frist trigger actually). On the opportunity, we have a look-up field to other opportunities called 'Renewed Opportunity'. The idea is that when you create an opp that is a renewal, you use that field to reference the previous opportunity that is being renewed.

The trigger looks at the stage of the new renewal opp and updates a field on the referenced 'Renewed Opporunity' called 'Renewal Status'. The goal is to be able to see if an opp ended up renewing or not.

The issue here is that many of our older opportunities don't meet the validation rules we currently have in place. So if you populate that look-up field with an opp with missing data, you'll get an error message preventing you from updating the new, renewal opp you're creating.

Obviously, one solution would be to go back and update all our older opps, but that's practically impossible. So here is my question:

1) Is there something I can write in either the trigger or the validation rules to set up a bypass? For the validation rules, I tried writing in 'NOT(ISCHANGED(Renewal_Status__c))', but it seems that as long as a record is referenced, the validation rules will be required. The trigger doesn't even have to update the record.

2) If option 1 is not possible, is there a way to write an error message in the trigger that at least explains to the user in a clear manner that they have to update the referenced opp? I'd also like to list in the error the validation rules that must be met, but that would be a bonus.

In case you want to take a look at my trigger, here it is:


trigger RenewalProcess on Opportunity (after insert, after update) {
   
   Set<String> allOpps = new Set<String>();
    for(Opportunity renewalOpp : Trigger.new) {
        if (renewalOpp.Renewed_Opportunity__c != null) {
            allOpps.add(renewalOpp.Renewed_Opportunity__c);
         }
    }

    List<Opportunity> potentialOpps = [SELECT Id FROM Opportunity WHERE Id IN :allOpps];

    Map<String,Opportunity> opportunityMap = new Map<String,Opportunity>();
        for (Opportunity o : potentialOpps) {
            opportunityMap.put(o.id,o);
        }
     
     List<Opportunity> oppsToUpdate = new List<Opportunity>();
       
        for (Opportunity renewalOpp : Trigger.new) {
            if (renewalOpp.Renewed_Opportunity__c != null && renewalOpp.StageName.equals('Closed Won')) {
                Opportunity renewedOpp = opportunityMap.get(renewalOpp.Renewed_Opportunity__c);
                renewedOpp.Renewal_Status__c = 'Renewed';
                oppsToUpdate.add(renewedOpp);
            }
            else if(renewalOpp.Renewed_Opportunity__c != null && !renewalOpp.IsClosed) {
                Opportunity renewedOpp = opportunityMap.get(renewalOpp.Renewed_Opportunity__c);
                renewedOpp.Renewal_Status__c = 'In Negotiations';
                oppsToUpdate.add(renewedOpp);
            }
            else if(renewalOpp.Renewed_Opportunity__c != null && (renewalOpp.StageName.equals('Closed Lost') || renewalOpp.StageName.equals('Closed Stalled'))) {
                Opportunity renewedOpp = opportunityMap.get(renewalOpp.Renewed_Opportunity__c);
                renewedOpp.Renewal_Status__c = 'Did Not Renew';
                oppsToUpdate.add(renewedOpp);
            }
           
           
        }
   
    update oppsToUpdate;
   
}



Let me know if you need anymore info from me!
-Greg