• JustinWilliams2381
  • NEWBIE
  • 0 Points
  • Member since 2012

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 14
    Questions
  • 15
    Replies

I have a decent lead conversion trigger that works to convert the lead and check for existing contacts by email to add to existing contact and account rather than create new.  What I want to do is to also set fields on the opportunity that is created by the lead conversion in the same trigger.

 

I have a few lines to see if I could update that opportunity but they didn't seem to work.  is it possible?

 

trigger OnlineProposalConvertSE on Lead (after insert, after update) {
    //variable used to filter out non submittal exchange contacts.
    ID ContactType = Schema.SObjectType.Contact.getRecordTypeInfosByName().get('Submittal Exchange Contact').getRecordTypeId();
    
    for (Lead lead : Trigger.new) {
        if (lead.isConverted == false && lead.LeadSource == 'Online Order Form'){ //to prevent recursion
        
            Database.LeadConvert lc = new Database.LeadConvert();
            lc.setLeadId(lead.Id);
            
            String oppName =  lead.Project_Name__c;
            lc.setOpportunityName(oppName);
            
            LeadStatus convertStatus = [SELECT Id, MasterLabel FROM LeadStatus WHERE IsConverted=true LIMIT 1];
            lc.setConvertedStatus(convertStatus.MasterLabel);    
            
            //This section searches for existing contacts based on emails and instead of creating a new contact and account it 
            //uses the existing contact and its account record to add the new opportunity to.  Notice the filter in the SOQL
            //includes a variable created earlier in the code to limit the search to Submittal Exchange contacts 'ContactType'.
            //Despite this there may still be duplicate occurances of the same email address.  As far as I know it takes will 
            //associate the lead to the last result on the list.  Hopefully that won't be a problem :) 
            if (lead.email != null){
                String CurrentEmail = lead.email;
                List<Contact> ExistingContact = [SELECT ID, email, Account.Id FROM Contact WHERE email = :CurrentEmail AND RecordTypeID = :ContactType LIMIT 1 ];
                if(ExistingContact.size()!=0){
                    for(Contact c: ExistingContact){
                        ID aID = c.Account.Id;
                        ID cID = c.Id;
                        lc.setAccountID(aID);
                        lc.setContactID(cID);
                    }
                }
            }

            Database.LeadConvertResult lcr = Database.convertLead(lc);
            System.assert(lcr.isSuccess());
            
            String NewOpp = lead.ConvertedOpportunityId;
            
            For(Opportunity OppUpdate:[SELECT amount, Standard_List_Price__c, Contact__c FROM Opportunity WHERE ID = :NewOpp]){
                
                OppUpdate.Big_Deal_Post__c = true;
                OppUpdate.amount = OppUpdate.Standard_List_Price__c;
                OppUpdate.Contact__c = lc.getContactId();
                Update OppUpdate;
            }

        }

 

I am creating an apex generated chatter post to put big deals into a big deals group.  I want to put information about the deal including the amount.  I am having issues trying to get the amount to display in its currency format.  I am pushing it to a group so chatter free users can see it too.

 

trigger PostBigDeal on Opportunity (before update) {
    
    //vairables for use later
    List<Opportunity> OppIds = new List<Opportunity>();
    List<FeedItem> feeds = new list<FeedItem>();
            
    for( opportunity opp: Trigger.New){
        	
        if ((opp.Big_Deal_Post__c == true) && (trigger.oldMap.get(opp.id).Big_Deal_Post__c == false )){    
            oppIds.add(opp);
	        }
        }
    
    if (oppIds.size() != 0) {
        
        for( opportunity BigOpp: [SELECT Id, owner.name, Subscription_Type__c, amount FROM opportunity WHERE Id IN :OppIds]){
   
            FeedItem post = new FeedItem();
            post.ParentId = '0F9Q00000004SiM'; //eg. Opportunity id, custom object id..
            post.Body = 'A New ' + BigOpp.Subscription_Type__c + ' has been sold for ' + BigOpp.amount + '.  Congratulation to ' + BigOpp.Owner.Name + ' for their hard work!';
            post.LinkUrl = 'https://cs3.salesforce.com/' + BigOpp.Id;
            feeds.add(post);
        }
        if (feeds.size() > 0) {
        Database.insert(feeds,false); //notice the false value. This will allow some to fail if Chatter isn't available on that object
    }
    }    
}

 

I have created a simple auto-covert lead trigger that works.  I upgraded it to attach to an existing account ID if that account was identified on a custom lookup field on the lead.  Now I want to upgrade it again to add to an existing contact if the lead email matches one of the emails from a contact record related to the account that was identified on the lead.  Here is my code and I am trying to figure out how to reference the lead email and the contact email in a SOQL query.  I know I also need to add a chunck of code to check and see if my results are blank but I need to figure out this SOQL thing first.

 

trigger AutoConvertLead on Lead (After Update) {
    for (Lead lead : Trigger.new) {
        if (lead.isConverted == false && lead.Qualification_Score__c>=6) //to prevent recursion
        {
            Database.LeadConvert lc = new Database.LeadConvert();
            lc.setLeadId(lead.Id);
            
            String oppName =  lead.Name;
            lc.setOpportunityName(oppName);
            
            LeadStatus convertStatus = [SELECT Id, MasterLabel FROM LeadStatus WHERE IsConverted=true LIMIT 1];
            lc.setConvertedStatus(convertStatus.MasterLabel);
            
            //If the account lookup field is filled out then it will merge to that account instead of creating a new one.
            if (lead.Account__c != null)
            {
                String ExistingAccount = lead.Account__c;
                lc.setAccountID(ExistingAccount);
            }

            if (lead.email != null)
            {
                String CurrentEmail = lead.email;
                String ExistingContact = [SELECT Id FROM Contact WHERE email = CurrentEmail AND AccountID = ExistingAccount LIMIT 1];
                lc.setContactID(ExistingContact);
            }
            
            Database.LeadConvertResult lcr = Database.convertLead(lc);
            System.assert(lcr.isSuccess());
        }
    }
}

 

I inserted over 80,000 contacts into our system with the apex data loader.  They are properly related to the account as far as I can see, but when I go to an opportunity and add new contact roles no one shoes up.  Usually when you add new contact roles all the contacts related to the account show up so you can just assign roles and the primary without doing a lookup.  If I manually create a lead then it does show up in the contact role list feature.

 

Thoughts?

I can't seem to get my test code to check a chunk of my trigger.  I have a trigger, a class to prevent recursion, and my test class.

 

Trigger (basically any time the Opp Stage changes a pair or records are created in a custom object assigning points to the move to and from the stage.)  Lines 15 through 30 are not covered by the test class listed at the bottom.

 line 	 source
 1 	  trigger UpdateSalesScoreEvents on Opportunity (After update) {
 2 	  
 3 	   try {
 4 	  
 5 	   // List of variables to be used later.
 6 	   List<Sales_Score__c> ScoreEvents = new list<Sales_Score__c>();
 7 	   List<Opportunity> OldStage = New list<Opportunity>();
 8 	  
 9 	  
 10 	   // Add to the list all opps associated with an agreement in the trigger that has been signed
 11 	   for (Opportunity Opp: Trigger.New) {
 12 	   if ((Opp.Company_Division__c == 'Textura') && (Opp.StageName != trigger.oldMap.get(Opp.id).StageName) && (!ScoreEventHelper.hasAlreadyCreatedScores())){
 13 	  
 14 	   //
 15 	   Sales_Score__c OldEvent = new Sales_Score__c();
 16 	   OldEvent.Opportunity__c = opp.id;
 17 	   OldEvent.Direction__c = 'Leaving Stage';
 18 	   OldEvent.Movement_Date__c = system.Today();
 19 	   OldEvent.Stage__c = Trigger.oldMap.get(opp.ID).StageName;
 20 	   // Add to ScoreEvent list
 21 	   ScoreEvents.add(OldEvent);
 22 	  
 23 	   //
 24 	   Sales_Score__c Event = new Sales_Score__c();
 25 	   Event.Opportunity__c = opp.id;
 26 	   Event.Direction__c = 'Entering Stage';
 27 	   Event.Movement_Date__c = system.Today();
 28 	   Event.Stage__c = opp.StageName;
 29 	   // Add to ScoreEvent list
 30 	   ScoreEvents.add(Event);
 31 	  
 32 	  
 33 	   }
 34 	   ScoreEventHelper.setAlreadyCreatedScores();
 35 	   insert ScoreEvents;
 36 	   }
 37 	   } catch (Exception e) {Trigger.new[0].addError(e.getMessage());}
 38 	  }

 Class used to prevent recurrsion;

 1 	  public class ScoreEventHelper{
 2 	  
 3 	   // Static variables are local to the context of a Web request
 4 	  
 5 	   // (or testMethod during a runTests call)
 6 	  
 7 	   // Therefore, this variable will be initialized as false
 8 	  
 9 	   // at the beginning of each Web request which accesses it.
 10 	  
 11 	  
 12 	   private static boolean alreadyCreatedScores = false;
 13 	  
 14 	  
 15 	   public static boolean hasAlreadyCreatedScores() {
 16 	   return alreadyCreatedScores;
 17 	   }
 18 	  
 19 	   // By setting the variable to true, it maintains this
 20 	  
 21 	   // new value throughout the duration of the request
 22 	  
 23 	   // (or testMethod)
 24 	  
 25 	   public static void setAlreadyCreatedScores() {
 26 	   alreadyCreatedScores = true;
 27 	   }
 28 	  }

 This is the test method I created.  Something in it needs to be added to check more code from the trigger.

 1 	  public class ScoreEventTests {
 2 	   static testMethod void TestScoreEvents() {
 3 	   User user1 = new User();
 4 	   user1.FirstName = 'Steve';
 5 	   user1.LastName = 'Will';
 6 	   user1.UserName = 'stevew@submittalexchange.com';
 7 	   user1.Email = 'stevew@submittalexchange.com';
 8 	   user1.Alias = 'swill';
 9 	   user1.CommunityNickname = 'steve';
 10 	   user1.TimeZoneSidKey = 'America/Chicago';
 11 	   user1.LocaleSidKey = 'en_US';
 12 	   user1.LanguageLocaleKey = 'en_US';
 13 	   user1.EmailEncodingKey = 'UTF-8';
 14 	   user1.ProfileId = '00e70000000swZU';
 15 	   insert user1;
 16 	  
 17 	   Account account = new Account();
 18 	   account.Name = 'Test GradeBeam Account';
 19 	   account.Type = 'Architect';
 20 	   account.AD_Rep__c = user1.Id;
 21 	   account.NCA_Rep__c = user1.Id;
 22 	   account.Account_Source__c = 'BSD';
 23 	   insert account;
 24 	  
 25 	   Opportunity opp1 = new Opportunity();
 26 	   opp1.Name = 'Test Opp';
 27 	   opp1.AccountId = account.id;
 28 	   opp1.CloseDate = System.today();
 29 	   opp1.StageName = 'Qualified';
 30 	   opp1.Amount = 100;
 31 	   opp1.OwnerId = user1.Id;
 32 	   opp1.Company_Division__c = 'Textura';
 33 	   insert opp1;
 34 	  
 35 	  
 36 	   opp1.StageName = 'Sales Process';
 37 	   update Opp1;
 38 	  
 39 	   opp1.StageName = 'Written Agreement';
 40 	   update Opp1;
 41 	  
 42 	   opp1.StageName = 'Negotiation';
 43 	   update Opp1;
 44 	   }
 45 	  }

 

I have some apex classes and visualforce pages I received from a consultant for liking their facebook page.  It creates a button on the account and contact that when clicked it displayes the activity history in a grid like fasion instead of the less than visually apealing way it does out of the box.  I have figured out a bunch of problems to get the three classes to save and now I have to get to the page.

 

The visualforce page is below but SF won't allow me to add it to a button on the Account or Contact page.

 

<!--
Copyright (c) 2010, Lexnet Consulting Group, Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name of Lexnet Consulting Group, Inc. nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
<apex:page controller="ViewAllActivityController">
<apex:pageBlock title="Activity Details">
<apex:outputText styleClass="leftLabel"><b>&nbsp;Account:</b></apex:outputText>
<apex:outputLink value="/{!Summary.AccountId}" styleClass="leftValue">&nbsp;{!Summary.Account}</apex:outputLink><br />
<apex:outputPanel rendered="{!ShowContactDetail}">
<apex:outputText styleClass="leftLabel"><b>&nbsp;&nbsp;Contact:&nbsp;</b></apex:outputText>
<apex:outputLink value="/{!Summary.ContactId}" styleClass="leftValue">{!Summary.FirstName} {!Summary.LastName}</apex:outputLink><br />
</apex:outputPanel>
</apex:pageBlock>
<apex:pageBlock >
<apex:outputText rendered="{!IF(ActivityHistories.size = 0, true, false)}">No records to display</apex:outputText>
<apex:pageBlockTable value="{!ActivityHistories}" var="ah" rows="{!ActivityHistories.size}" rendered="{!IF(ActivityHistories.size > 0, true, false)}">
<apex:column value="{!ah.Subject}" width="130px" style="vertical-align: top;"/>
<apex:column value="{!ah.ActivityDate}" width="110px" style="vertical-align: top;"/>
<apex:column value="{!ah.Owner.Name}" width="130px" headerValue="Assigned To" style="vertical-align: top;"/>
<apex:column value="{!ah.Who.Name}" width="130px" headerValue="Contact" style="vertical-align: top;"/>
<apex:column value="{!ah.Description}" style="vertical-align: top;"/>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:page>

Every night around midnight all our unconverted lead records seem to get touched by me.  I get listed as the last modified user.  In many cases certain values get changed.  I activiated  some field history tracking on key fields like phone, company , name, fax, etc.  It looks like leads are being revereted to some prior value.  I just started the tracking yesterday and reported on the history.  Indeed several examples show our reps making a change to a phone number, and at midnight I get logged as changing it back.

 

I am the admin so i am the default workflow user.  What is the best way to track down this automated mass lead update that happens every midnight?

A few weeks after a successful ETL was developed to insert thousands of leads a day it started inserting without the email.  The email used to be in there, the source data has an email, and my etl developer says his results show he is passing an email address.

 

I setup a debug log on his User ID but reading it is difficult.  I search for 'Email' in several of the logs that run every 30 minutes.  The problem is the part that looks like it will give me insight into the issue is 'abbreviated'.  

13:00:32.817 (817773000)|VARIABLE_ASSIGNMENT|[5]|lead|{"Project_Mercury_Foll (8 more) ...":false,"Month_Became_Hot__c":"01Jan","RecordTypeId":"01270000000UKWbAAO","LastModifiedByID":"00570000002DffpAAC","LastTransferDate":"2013-01-14T19:00:32.000Z","Owner_ID__c":"00570000002DffpAAC","Demo_Attendee_1_Titl (4 more) ...":"populated from title (6 more) ...","Full_Name__c":"Sam Sacks","Unqualified__c":0,"LastModifiedDate":"2013-01-14T19:00:32.000Z","Gg_Accountability__c":false,"LeadSource":"GB Non-Member Sub","LastName":"Sacks","Firm_Name__c":"populated from compa (13 more) ...","Qualified__c":0,"New_Email_Address__c":false,"Gg_Efficiency__c":false,"DoNotCall":false,"Email_Address_Status (3 more) ...":0,"i__CreatedForUser__c":"00570000002DffpAAC","CreatedByID":"00570000002DffpAAC","SFGA__CorrelationID_ (2 more) ...":"none","Project_Marketing_Em (20 more) ...":false,"Email_to_Fax__c":"083006@send.trustfax (4 more) ...","Other_Questions_Requ (6 more) ...":false,"Project_Emailing__c":false,"Multiple_Project_Mar (21 more) ...":false,"cbSubEx__c":false,"Fred_Upgrade__c":false,"Activity_monitor__c":"_IM1_/img/samples/fl (34 more) ...","Date_of_Request_Mont (4 more) ...":"00","X2012_Driver_Status_ (2 more) ...":"D - Non-Driver - New","Log_a_Call__c":"_HL_ENCODED_/00T/e?t (170 more) ...","Hot_This_Month__c":"T","HasOptedOutOfEmail":false,"Last_GB_Update__c":"2013-01-14T18:59:16.000Z","Country":"USA","Online_Demo_Request_ (2 more) ...":false,"Activity_monitor_gro (5 more) ...":"0 - No Activity","Greengrade__c":false,"Numeric_Score__c":0.0,"CreatedById":"00570000002DffpAAC","IsDeleted":false,"cbTextura__c":false,"Gg_Profitability__c":false,"Id":"00Q7000000lwNTHEA2","Area_Code__c":"800","Any_Activity__c":1,"SFGA__Web_Source__c":"none","Month_Pardot_Score_G (7 more) ...":"Error","Accuracy__c":false,"Project_Mailing__c":false,"GB_Record_ID__c":"273030","IsConverted":false,"Street":"150 Dedham Street","Phone":"8002533539","Month_Created__c":"01Jan","HasOptedOutOfFax":false,"GradeBeam_Status__c":"Active-Fax","Hot_Last_Month__c":"F","OwnerId":"00570000002DffpAAC","Not_in_US__c":false,"SFGA__Correlation_Da (5 more) ...":"none","LEED_Postcard__c":false,"Days_since_created__ (1 more) ...":0,"LEED_AP__c":false,"Enterprise__c":false,"IsUnreadByOwner":true,"Paper_Savings__c":"18,000 pages","Automatic_Follow_up_ (12 more) ...":false,"General_Postcard__c":false,"SystemModstamp":"2013-01-14T19:00:32.000Z","FirstName":"Sam","Company":"Duraflex, Inc.","Gg_Auditability__c":false,"New_User__c":false,"cbMyShopDocs__c":false,"cbGradeBeam__c":false,"LastModifiedById":"00570000002DffpAAC","Website":"http://www.dur-a-fle (5 more) ...","Gg_Accessibility__c":false,"Fax":"5083840064","Automatic_Follow_Up_ (15 more) ...":false,"City":"Norfolk","Demo_Attendee_1_Name (3 more) ...":"populated from name  (5 more) ...","Resolved__c":0,"cbALL__c":false,"Status":"Open","PostalCode":"02056","State":"MA","Project_Marketing__c":false,"cbGreengrade__c":false,"CreatedDate":"2013-01-

 

I just have a hard time reading this.  Is there a better way to use the debug log to see why the ETL isn't populating the email field?

I wrote this code that once the opportunity is marked as "Closed Won" it is suppoed to clone the opp and primary contact role.  For some FRUSTERATING reason it almost always creates TWO clones instead of one and I can't figure out why.

 

trigger CreateGBRenewal on Opportunity (before update) {
try {

// List of opportunity IDs
Set<Id> oppIds = new Set<Id>();
//lists used for bulk
List<Opportunity> clonesToInsert = new List<Opportunity>();
List<OpportunityContactRole> RoleToInsert = new list<OpportunityContactRole>();

for( opportunity opp: Trigger.New){
if ((opp.StageName == 'Closed Won') && (opp.Subscription_Type__c == 'GradeBeam'||opp.Subscription_Type__c == 'GradeBeam for Subs' )&& (trigger.oldMap.get(opp.id).StageName != 'Closed Won' )){
oppIds.add(opp.Id);
}
}


for( opportunity oldOpp: [SELECT ID, accountId, account.name, Estimated_Renewal_Date__c FROM opportunity WHERE Id IN :OppIds]){

opportunity renewOpp = New opportunity();
renewOpp.closedate = oldOpp.Estimated_Renewal_Date__c;
renewOpp.AccountId = oldOpp.accountId;
renewOpp.name = oldOpp.account.name + ' Renewal';
renewOpp.stagename = 'Renewal Scheduled';
renewOpp.Type = 'Repeat Client';
renewOpp.RecordTypeId = '012S00000008r99';
clonesToInsert.add(renewOpp);
insert clonesToInsert;

for( opportunityContactRole OppCon: [SELECT ContactID, IsPrimary, Role FROM OpportunityContactRole WHERE OpportunityId IN :OppIds AND IsPrimary = TRUE]) {

OpportunityContactRole ConRole = New OpportunityContactRole();
ConRole.ContactID = OppCon.ContactID;
ConRole.OpportunityId = renewOpp.ID;
ConRole.IsPrimary = OppCon.IsPrimary;
ConRole.Role = oppCon.Role;
RoleToInsert.add(ConRole);
insert RoleToInsert;
}
break;
}
}catch (Exception e) {Trigger.new[0].addError(e.getMessage());}
}

The purpose of this trigger is to take a closed won opportunity that is of a certain picklist option 'Subscription_Type__c = 'GradeBeam' and clone it along with the primary contact if there is one.  The reeason is that when we sell a subscription we want to create a renewal oppotunity 1,2, or 3 years down the road.  I have two issues with this code otherwise it works:

 

1. When I close an opportunity it creates 2 clones instead of 1.

2. I have to have a product on the opp before I close otherwise I get "Attempt to de-refference a null object" which is a problem because certain opportunities won't use products, just those who's subscription type is 'GradeBeam'.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
trigger RenewalOppCreate on Opportunity (After update) {
    
  try {

        // List of opportunity IDs
      ID OppId ;
        
        for( opportunity opp: Trigger.New){
        if ((opp.StageName == 'Closed Won') && (opp.Subscription_Type__c == 'GradeBeam')&& (trigger.oldMap.get(opp.id).StageName != 'Closed Won' )){
            OppId = opp.Id;
        }
        }

        
    for( opportunity oldOpp: [SELECT ID, accountId, account.name, Estimated_Renewal_Date__c FROM opportunity WHERE Id = :OppId]){
        
        opportunity renewOpp = New opportunity();
            renewOpp.closedate = oldOpp.Estimated_Renewal_Date__c;
            renewOpp.AccountId = oldOpp.accountId;
            renewOpp.name = oldOpp.account.name + ' Renewal';
            renewOpp.stagename = 'Renewal Scheduled';
            renewOpp.Type = 'Repeat Client';
            insert renewOpp;
            
        
            for( OpportunityContactRole Role: [SELECT ID, ContactId, Role FROM opportunityContactRole WHERE IsPrimary = TRUE AND opportunityId = :OldOpp.ID]){
        
        opportunityContactRole ContactRole = New opportunityContactRole();
            ContactRole.ContactId = Role.ContactId;
            ContactRole.OpportunityId = renewOpp.Id;
            ContactRole.IsPrimary = true;
     
            insert ContactRole;
        }
        }
        
    }catch (Exception e) {Trigger.new[0].addError(e.getMessage());}
}

Trying to figure out why I'm getting a Error:Attempt to de-reference a null object on this code.  I swear it worked Friday and now it doesn't.

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
trigger RenewalOppCreate on Opportunity (Before update) {
    
  try {

        // List of opportunity IDs
      List<Id> OppId = new List<Id>();
        
        for( opportunity opp: Trigger.New) {
        if ((opp.StageName == 'Closed Won') && (opp.Subscription_Type__c == 'GradeBeam')){
            OppId.add(opp.Id);
        }
    }

        
    for (opportunity oldOpp:[SELECT ID, accountId, account.name, closedate FROM opportunity WHERE Id in :OppId]){
        
        opportunity renewOpp = New opportunity();
            renewOpp.closedate = oldOpp.closedate+365;
            renewOpp.AccountId = oldOpp.accountId;
            renewOpp.name = oldOpp.account.name + ' Renewal';
            renewOpp.stagename = '1. Prospecting';
            renewOpp.Type = 'Repeat Client';
            insert renewOpp;
            }
        
    }catch (Exception e) {Trigger.new[0].addError(e.getMessage());}
}

I have some code that was written by someone before me.  It checks to see if a field is a certain value and if so executes the trigger.  I am trying to modify it so that it checks to see if two fields are true before executing it.  We expanded our opportunities to include multiple record types and this old trigger only needs to fire with one specific record type. 

 

 

Here is the original If statement that works.

 

// Add to the list all opps associated with an agreement in the trigger that has been signed
for (echosign_dev1__SIGN_Agreement__c form: Trigger.New) {
if (form.echosign_dev1__Status__c == 'Signed') {
list_forms.add(form.echosign_dev1__Opportunity__c);
}
}

 

I try and update the If statement to validate two field before fireing.  The trigger is referencing an EchoSign object called "echosign_dev1__SIGN_Agreement__c".  The status field is a picklist that Adobe updates when a document is eSigned.  Company_Division__c is a formula field referencing a picklist on the related Opportunity object.  I have also tried making it a text field instead of a formula field in case the trigger didn't like referencing a formula field.

 

// Add to the list all opps associated with an agreement in the trigger that has been signed
for (echosign_dev1__SIGN_Agreement__c form: Trigger.New) {
if ((form.echosign_dev1__Status__c == 'Signed') && (form.company_Division__c == 'GradeBeam')){
list_forms.add(form.echosign_dev1__Opportunity__c);
}
}

I need to run a trigger before insert, before update on leads.

 

I need to grab the value from a custom field in the lead record that was just updated/inserted.  Lead.customFieldValue

 

I then need to query the accounts table and find a match e.g.

 

Account[] accountId = [SELECT Id FROM Account WHERE Account.customField__c = Lead.customFieldValue];

 

I then need to take that account record ID that was a match to my lead record and place that value into the custom relationship field on the lead record called "Account".  

 

Basically I just took a lead, found an account record whose custom field value matched the lead's custom field value and linked the lead up to the Account record

 

 

I have will have leads coming into the object from an external system.  It will include an external record number.  If the lead gets converted but it does not sell the opportunity it will stay in the lead pool on the external database.  This means at some point after that it may come back into the Leads object with the same external record ID.  I need an apex trigger to search the account records after the lead is inserted and find any matches for this unique external record identifier.  If found take the SF record ID for that matching account and insert it into the matching Lead record custom lookup field to the account.

 

Anyone have a good place to point me to get me started?  Sound like it should be simple but I'm just starting on Apex code and its been years since I did any programming back in college. 

I am creating an apex generated chatter post to put big deals into a big deals group.  I want to put information about the deal including the amount.  I am having issues trying to get the amount to display in its currency format.  I am pushing it to a group so chatter free users can see it too.

 

trigger PostBigDeal on Opportunity (before update) {
    
    //vairables for use later
    List<Opportunity> OppIds = new List<Opportunity>();
    List<FeedItem> feeds = new list<FeedItem>();
            
    for( opportunity opp: Trigger.New){
        	
        if ((opp.Big_Deal_Post__c == true) && (trigger.oldMap.get(opp.id).Big_Deal_Post__c == false )){    
            oppIds.add(opp);
	        }
        }
    
    if (oppIds.size() != 0) {
        
        for( opportunity BigOpp: [SELECT Id, owner.name, Subscription_Type__c, amount FROM opportunity WHERE Id IN :OppIds]){
   
            FeedItem post = new FeedItem();
            post.ParentId = '0F9Q00000004SiM'; //eg. Opportunity id, custom object id..
            post.Body = 'A New ' + BigOpp.Subscription_Type__c + ' has been sold for ' + BigOpp.amount + '.  Congratulation to ' + BigOpp.Owner.Name + ' for their hard work!';
            post.LinkUrl = 'https://cs3.salesforce.com/' + BigOpp.Id;
            feeds.add(post);
        }
        if (feeds.size() > 0) {
        Database.insert(feeds,false); //notice the false value. This will allow some to fail if Chatter isn't available on that object
    }
    }    
}

 

I inserted over 80,000 contacts into our system with the apex data loader.  They are properly related to the account as far as I can see, but when I go to an opportunity and add new contact roles no one shoes up.  Usually when you add new contact roles all the contacts related to the account show up so you can just assign roles and the primary without doing a lookup.  If I manually create a lead then it does show up in the contact role list feature.

 

Thoughts?

I can't seem to get my test code to check a chunk of my trigger.  I have a trigger, a class to prevent recursion, and my test class.

 

Trigger (basically any time the Opp Stage changes a pair or records are created in a custom object assigning points to the move to and from the stage.)  Lines 15 through 30 are not covered by the test class listed at the bottom.

 line 	 source
 1 	  trigger UpdateSalesScoreEvents on Opportunity (After update) {
 2 	  
 3 	   try {
 4 	  
 5 	   // List of variables to be used later.
 6 	   List<Sales_Score__c> ScoreEvents = new list<Sales_Score__c>();
 7 	   List<Opportunity> OldStage = New list<Opportunity>();
 8 	  
 9 	  
 10 	   // Add to the list all opps associated with an agreement in the trigger that has been signed
 11 	   for (Opportunity Opp: Trigger.New) {
 12 	   if ((Opp.Company_Division__c == 'Textura') && (Opp.StageName != trigger.oldMap.get(Opp.id).StageName) && (!ScoreEventHelper.hasAlreadyCreatedScores())){
 13 	  
 14 	   //
 15 	   Sales_Score__c OldEvent = new Sales_Score__c();
 16 	   OldEvent.Opportunity__c = opp.id;
 17 	   OldEvent.Direction__c = 'Leaving Stage';
 18 	   OldEvent.Movement_Date__c = system.Today();
 19 	   OldEvent.Stage__c = Trigger.oldMap.get(opp.ID).StageName;
 20 	   // Add to ScoreEvent list
 21 	   ScoreEvents.add(OldEvent);
 22 	  
 23 	   //
 24 	   Sales_Score__c Event = new Sales_Score__c();
 25 	   Event.Opportunity__c = opp.id;
 26 	   Event.Direction__c = 'Entering Stage';
 27 	   Event.Movement_Date__c = system.Today();
 28 	   Event.Stage__c = opp.StageName;
 29 	   // Add to ScoreEvent list
 30 	   ScoreEvents.add(Event);
 31 	  
 32 	  
 33 	   }
 34 	   ScoreEventHelper.setAlreadyCreatedScores();
 35 	   insert ScoreEvents;
 36 	   }
 37 	   } catch (Exception e) {Trigger.new[0].addError(e.getMessage());}
 38 	  }

 Class used to prevent recurrsion;

 1 	  public class ScoreEventHelper{
 2 	  
 3 	   // Static variables are local to the context of a Web request
 4 	  
 5 	   // (or testMethod during a runTests call)
 6 	  
 7 	   // Therefore, this variable will be initialized as false
 8 	  
 9 	   // at the beginning of each Web request which accesses it.
 10 	  
 11 	  
 12 	   private static boolean alreadyCreatedScores = false;
 13 	  
 14 	  
 15 	   public static boolean hasAlreadyCreatedScores() {
 16 	   return alreadyCreatedScores;
 17 	   }
 18 	  
 19 	   // By setting the variable to true, it maintains this
 20 	  
 21 	   // new value throughout the duration of the request
 22 	  
 23 	   // (or testMethod)
 24 	  
 25 	   public static void setAlreadyCreatedScores() {
 26 	   alreadyCreatedScores = true;
 27 	   }
 28 	  }

 This is the test method I created.  Something in it needs to be added to check more code from the trigger.

 1 	  public class ScoreEventTests {
 2 	   static testMethod void TestScoreEvents() {
 3 	   User user1 = new User();
 4 	   user1.FirstName = 'Steve';
 5 	   user1.LastName = 'Will';
 6 	   user1.UserName = 'stevew@submittalexchange.com';
 7 	   user1.Email = 'stevew@submittalexchange.com';
 8 	   user1.Alias = 'swill';
 9 	   user1.CommunityNickname = 'steve';
 10 	   user1.TimeZoneSidKey = 'America/Chicago';
 11 	   user1.LocaleSidKey = 'en_US';
 12 	   user1.LanguageLocaleKey = 'en_US';
 13 	   user1.EmailEncodingKey = 'UTF-8';
 14 	   user1.ProfileId = '00e70000000swZU';
 15 	   insert user1;
 16 	  
 17 	   Account account = new Account();
 18 	   account.Name = 'Test GradeBeam Account';
 19 	   account.Type = 'Architect';
 20 	   account.AD_Rep__c = user1.Id;
 21 	   account.NCA_Rep__c = user1.Id;
 22 	   account.Account_Source__c = 'BSD';
 23 	   insert account;
 24 	  
 25 	   Opportunity opp1 = new Opportunity();
 26 	   opp1.Name = 'Test Opp';
 27 	   opp1.AccountId = account.id;
 28 	   opp1.CloseDate = System.today();
 29 	   opp1.StageName = 'Qualified';
 30 	   opp1.Amount = 100;
 31 	   opp1.OwnerId = user1.Id;
 32 	   opp1.Company_Division__c = 'Textura';
 33 	   insert opp1;
 34 	  
 35 	  
 36 	   opp1.StageName = 'Sales Process';
 37 	   update Opp1;
 38 	  
 39 	   opp1.StageName = 'Written Agreement';
 40 	   update Opp1;
 41 	  
 42 	   opp1.StageName = 'Negotiation';
 43 	   update Opp1;
 44 	   }
 45 	  }

 

Every night around midnight all our unconverted lead records seem to get touched by me.  I get listed as the last modified user.  In many cases certain values get changed.  I activiated  some field history tracking on key fields like phone, company , name, fax, etc.  It looks like leads are being revereted to some prior value.  I just started the tracking yesterday and reported on the history.  Indeed several examples show our reps making a change to a phone number, and at midnight I get logged as changing it back.

 

I am the admin so i am the default workflow user.  What is the best way to track down this automated mass lead update that happens every midnight?

A few weeks after a successful ETL was developed to insert thousands of leads a day it started inserting without the email.  The email used to be in there, the source data has an email, and my etl developer says his results show he is passing an email address.

 

I setup a debug log on his User ID but reading it is difficult.  I search for 'Email' in several of the logs that run every 30 minutes.  The problem is the part that looks like it will give me insight into the issue is 'abbreviated'.  

13:00:32.817 (817773000)|VARIABLE_ASSIGNMENT|[5]|lead|{"Project_Mercury_Foll (8 more) ...":false,"Month_Became_Hot__c":"01Jan","RecordTypeId":"01270000000UKWbAAO","LastModifiedByID":"00570000002DffpAAC","LastTransferDate":"2013-01-14T19:00:32.000Z","Owner_ID__c":"00570000002DffpAAC","Demo_Attendee_1_Titl (4 more) ...":"populated from title (6 more) ...","Full_Name__c":"Sam Sacks","Unqualified__c":0,"LastModifiedDate":"2013-01-14T19:00:32.000Z","Gg_Accountability__c":false,"LeadSource":"GB Non-Member Sub","LastName":"Sacks","Firm_Name__c":"populated from compa (13 more) ...","Qualified__c":0,"New_Email_Address__c":false,"Gg_Efficiency__c":false,"DoNotCall":false,"Email_Address_Status (3 more) ...":0,"i__CreatedForUser__c":"00570000002DffpAAC","CreatedByID":"00570000002DffpAAC","SFGA__CorrelationID_ (2 more) ...":"none","Project_Marketing_Em (20 more) ...":false,"Email_to_Fax__c":"083006@send.trustfax (4 more) ...","Other_Questions_Requ (6 more) ...":false,"Project_Emailing__c":false,"Multiple_Project_Mar (21 more) ...":false,"cbSubEx__c":false,"Fred_Upgrade__c":false,"Activity_monitor__c":"_IM1_/img/samples/fl (34 more) ...","Date_of_Request_Mont (4 more) ...":"00","X2012_Driver_Status_ (2 more) ...":"D - Non-Driver - New","Log_a_Call__c":"_HL_ENCODED_/00T/e?t (170 more) ...","Hot_This_Month__c":"T","HasOptedOutOfEmail":false,"Last_GB_Update__c":"2013-01-14T18:59:16.000Z","Country":"USA","Online_Demo_Request_ (2 more) ...":false,"Activity_monitor_gro (5 more) ...":"0 - No Activity","Greengrade__c":false,"Numeric_Score__c":0.0,"CreatedById":"00570000002DffpAAC","IsDeleted":false,"cbTextura__c":false,"Gg_Profitability__c":false,"Id":"00Q7000000lwNTHEA2","Area_Code__c":"800","Any_Activity__c":1,"SFGA__Web_Source__c":"none","Month_Pardot_Score_G (7 more) ...":"Error","Accuracy__c":false,"Project_Mailing__c":false,"GB_Record_ID__c":"273030","IsConverted":false,"Street":"150 Dedham Street","Phone":"8002533539","Month_Created__c":"01Jan","HasOptedOutOfFax":false,"GradeBeam_Status__c":"Active-Fax","Hot_Last_Month__c":"F","OwnerId":"00570000002DffpAAC","Not_in_US__c":false,"SFGA__Correlation_Da (5 more) ...":"none","LEED_Postcard__c":false,"Days_since_created__ (1 more) ...":0,"LEED_AP__c":false,"Enterprise__c":false,"IsUnreadByOwner":true,"Paper_Savings__c":"18,000 pages","Automatic_Follow_up_ (12 more) ...":false,"General_Postcard__c":false,"SystemModstamp":"2013-01-14T19:00:32.000Z","FirstName":"Sam","Company":"Duraflex, Inc.","Gg_Auditability__c":false,"New_User__c":false,"cbMyShopDocs__c":false,"cbGradeBeam__c":false,"LastModifiedById":"00570000002DffpAAC","Website":"http://www.dur-a-fle (5 more) ...","Gg_Accessibility__c":false,"Fax":"5083840064","Automatic_Follow_Up_ (15 more) ...":false,"City":"Norfolk","Demo_Attendee_1_Name (3 more) ...":"populated from name  (5 more) ...","Resolved__c":0,"cbALL__c":false,"Status":"Open","PostalCode":"02056","State":"MA","Project_Marketing__c":false,"cbGreengrade__c":false,"CreatedDate":"2013-01-

 

I just have a hard time reading this.  Is there a better way to use the debug log to see why the ETL isn't populating the email field?

The purpose of this trigger is to take a closed won opportunity that is of a certain picklist option 'Subscription_Type__c = 'GradeBeam' and clone it along with the primary contact if there is one.  The reeason is that when we sell a subscription we want to create a renewal oppotunity 1,2, or 3 years down the road.  I have two issues with this code otherwise it works:

 

1. When I close an opportunity it creates 2 clones instead of 1.

2. I have to have a product on the opp before I close otherwise I get "Attempt to de-refference a null object" which is a problem because certain opportunities won't use products, just those who's subscription type is 'GradeBeam'.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
trigger RenewalOppCreate on Opportunity (After update) {
    
  try {

        // List of opportunity IDs
      ID OppId ;
        
        for( opportunity opp: Trigger.New){
        if ((opp.StageName == 'Closed Won') && (opp.Subscription_Type__c == 'GradeBeam')&& (trigger.oldMap.get(opp.id).StageName != 'Closed Won' )){
            OppId = opp.Id;
        }
        }

        
    for( opportunity oldOpp: [SELECT ID, accountId, account.name, Estimated_Renewal_Date__c FROM opportunity WHERE Id = :OppId]){
        
        opportunity renewOpp = New opportunity();
            renewOpp.closedate = oldOpp.Estimated_Renewal_Date__c;
            renewOpp.AccountId = oldOpp.accountId;
            renewOpp.name = oldOpp.account.name + ' Renewal';
            renewOpp.stagename = 'Renewal Scheduled';
            renewOpp.Type = 'Repeat Client';
            insert renewOpp;
            
        
            for( OpportunityContactRole Role: [SELECT ID, ContactId, Role FROM opportunityContactRole WHERE IsPrimary = TRUE AND opportunityId = :OldOpp.ID]){
        
        opportunityContactRole ContactRole = New opportunityContactRole();
            ContactRole.ContactId = Role.ContactId;
            ContactRole.OpportunityId = renewOpp.Id;
            ContactRole.IsPrimary = true;
     
            insert ContactRole;
        }
        }
        
    }catch (Exception e) {Trigger.new[0].addError(e.getMessage());}
}

Trying to figure out why I'm getting a Error:Attempt to de-reference a null object on this code.  I swear it worked Friday and now it doesn't.

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
trigger RenewalOppCreate on Opportunity (Before update) {
    
  try {

        // List of opportunity IDs
      List<Id> OppId = new List<Id>();
        
        for( opportunity opp: Trigger.New) {
        if ((opp.StageName == 'Closed Won') && (opp.Subscription_Type__c == 'GradeBeam')){
            OppId.add(opp.Id);
        }
    }

        
    for (opportunity oldOpp:[SELECT ID, accountId, account.name, closedate FROM opportunity WHERE Id in :OppId]){
        
        opportunity renewOpp = New opportunity();
            renewOpp.closedate = oldOpp.closedate+365;
            renewOpp.AccountId = oldOpp.accountId;
            renewOpp.name = oldOpp.account.name + ' Renewal';
            renewOpp.stagename = '1. Prospecting';
            renewOpp.Type = 'Repeat Client';
            insert renewOpp;
            }
        
    }catch (Exception e) {Trigger.new[0].addError(e.getMessage());}
}

I have some code that was written by someone before me.  It checks to see if a field is a certain value and if so executes the trigger.  I am trying to modify it so that it checks to see if two fields are true before executing it.  We expanded our opportunities to include multiple record types and this old trigger only needs to fire with one specific record type. 

 

 

Here is the original If statement that works.

 

// Add to the list all opps associated with an agreement in the trigger that has been signed
for (echosign_dev1__SIGN_Agreement__c form: Trigger.New) {
if (form.echosign_dev1__Status__c == 'Signed') {
list_forms.add(form.echosign_dev1__Opportunity__c);
}
}

 

I try and update the If statement to validate two field before fireing.  The trigger is referencing an EchoSign object called "echosign_dev1__SIGN_Agreement__c".  The status field is a picklist that Adobe updates when a document is eSigned.  Company_Division__c is a formula field referencing a picklist on the related Opportunity object.  I have also tried making it a text field instead of a formula field in case the trigger didn't like referencing a formula field.

 

// Add to the list all opps associated with an agreement in the trigger that has been signed
for (echosign_dev1__SIGN_Agreement__c form: Trigger.New) {
if ((form.echosign_dev1__Status__c == 'Signed') && (form.company_Division__c == 'GradeBeam')){
list_forms.add(form.echosign_dev1__Opportunity__c);
}
}

I need to run a trigger before insert, before update on leads.

 

I need to grab the value from a custom field in the lead record that was just updated/inserted.  Lead.customFieldValue

 

I then need to query the accounts table and find a match e.g.

 

Account[] accountId = [SELECT Id FROM Account WHERE Account.customField__c = Lead.customFieldValue];

 

I then need to take that account record ID that was a match to my lead record and place that value into the custom relationship field on the lead record called "Account".  

 

Basically I just took a lead, found an account record whose custom field value matched the lead's custom field value and linked the lead up to the Account record