function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
GobbledigookGobbledigook 

Trigger to update Parent picklist from Child picklist

Hey all,

 

I'm having a problem with what is probably a very simple solution, but I just can't wrap my head around it.  

I'm trying to update an Account.Type field with a set value when an Opportunity hits a certain Stage, but only if an Account is a specific type already. 

 

Here's the code:

trigger SetAccountToP on Opportunity (before insert, before update) {
    
   for(Opportunity o : Trigger.New){
        if((o.StageName == 'Proposal/Price Quote' || o.StageName == 'Negotiation/Review' || o.StageName == 'Closed Won') && o.Account.Type == 'User')
        {   Account a = o.account;
            a.Type = 'Prospect';
            update a;  
         }   
    }
}

 

 

I know this code is pretty bad, but I've tried many things and this is the easiest to read through to illustrate my point.


Any help would be appreciated.

Best Answer chosen by Admin (Salesforce Developers) 
GobbledigookGobbledigook

First off, thanks for everyone's replies.  They really gave me a lot of direction as to thought processes and where to go. 

 

I figured it out.  I'm posting the solution I found here just in case anyone else is has the same problem.

 

trigger SetAccountToP on Opportunity (before insert, before update) 
{
     try
     {
     List<Account> ac = new List<Account>();
     
     //Set of Account Ids that we will iterate through
     Set<id> Ids = new Set<id>();
     for (Opportunity o : Trigger.new) {
         Ids.add(o.AccountId);
        }
     
     // Get the Account id and Type for each account
     Map<id, Account> owners = new Map<id, Account>([Select Type from Account Where Id in :Ids]);  
     
     for (Opportunity o : Trigger.new) 
     {
         //Gets o.Account.Type successfully and compares it to the status.  
         /*
             NOTE: Putting in o.Account.Type instead of owners.get(o.AccountId).Type will compile
                   yet will return a null value. 
         */             
         if(owners.get(o.AccountId).Type == 'User')
         {
             if(o.StageName == 'Proposal/Price Quote' || o.StageName == 'Negotiation/Review' || o.StageName == 'Closed Won')
             {
                 //Instantiate a new account and set it to the current opportunity parent.  
                 Account MK = owners.get(o.AccountId);
                 MK.Type = 'Prospect';
                 ac.add(MK);
             }    
         }
     }
     update ac;
     } 
     catch(Exception e) {
        System.debug('ERROR: '+ e);
        FD_Log.logError('Update Account Failure', ('' + e.getCause()), e.getMessage());
    }
}

 

Thanks again for everyone's assistance.  

All Answers

Anup JadhavAnup Jadhav

Hi there,

 

You haven't explained the nature of your problem though.

What kind of error is this code throwing?

If you are hitting governor limits, it's obviously because of the update statement inside the loop.

 

Or is the code not working as expected?

 

Regards,

 A J

ipsita.biswas@in.v2solutions.comipsita.biswas@in.v2solutions.com

Hi,

I guess the problem is due to the update in the for loop.

Use a List<Account> and store the accounts that you want to update in that list and fire the update statement at the end.

 

i.e.

 

trigger SetAccountToP on Opportunity (before insert, before update) {

List<Account> lstAccToBeUpdated = new List<Account();
   for(Opportunity o : Trigger.New){
        if((o.StageName == 'Proposal/Price Quote' || o.StageName == 'Negotiation/Review' || o.StageName == 'Closed Won') && o.Account.Type == 'User')
        {   Account a = new Account(Id=o.AccountId);
            a.Type = 'Prospect';
            lstAccToBeUpdated.add(a);
         }   
    }

 

if(lstAccToBeUpdated != null && !lstAccToBeUpdated.isEmpty())

{

update lstAccToBeUpdated;

}

}

bob_buzzardbob_buzzard

I'm not sure how successful you'll be in accessing fields from the related account object.  I've found that following the reference normally results in all fields being null.  Have you tried pulling the related accounts into the trigger via a SOQL call?

GobbledigookGobbledigook

Thanks for the replies. 

No I'm not hitting governer limits just yet.  I understand the code itself is very sloppy, but it just was to illustrate the nature of the problem.  It's just not working at all. 

 

I've also tried pulling in the related account information in a SOQL call itself, but the field still doesn't update.  Is it because it's a picklist value by any chance? (Yeah, I'm grasping at straws here) 

 

Here is the updated code: 

 

trigger SetAccountToP on Opportunity (before insert, before update) {
    
   List<Opportunity> o = [Select StageName, Account.Type from opportunity where Id in: trigger.new]; 
   for(Integer i = 0; i < trigger.new.size(); i++){
        if((o[i].StageName == 'Proposal/Price Quote' || o[i].StageName == 'Negotiation/Review' || o[i].StageName == 'Closed Won') && o[i].Account.Type == 'User')
        {   
            //Doesn't Work. 
            o[i].Account.Type = 'Prospect';
             
         }   
    }
    
}

 

GobbledigookGobbledigook

Ok, I got it to work for single processing.  Any ideas of how I could do this in bulk?

trigger SetAccountToP on Opportunity (before insert, before update) {
   
   List<Opportunity> o = trigger.new;
   
   for(Account a: [select Type from Account where Id =: o[0].AccountId])
   {
       if((o[0].StageName == 'Proposal/Price Quote' || o[0].StageName == 'Negotiation/Review' || o[0].StageName == 'Closed Won') && a.Type == 'User')
       {
        
           a.Type = 'Prospect';
       }
   
       update a;
   }

}

 

 

(Sorry about the code being drastically altered between posts)

frederic baudaxfrederic baudax

Hi,

 

As adviced by ipsita.biswas@in.v2solutions.com.  Something like bellow.

 

 

trigger SetAccountToP on Opportunity (before insert, before update) {
   List<Account> acctoupdate = new List<Account();
   List<Opportunity> opps = trigger.new;
   
for (Opportunity o : Trigger.new) {
//first we make a list of opps beeing inserted/updated so we only need 1 SOQL qry to get all we need
if(o.StageName == 'Proposal/Price Quote' || o.StageName == 'Negotiation/Review' || o.StageName == 'Closed Won'){ opps.add(o); } } //no need to qry at all if nothing in the opps list
if (opps.size()> 0){ //based on the list we can get all the concerned accounts at once
for(Account a: [select id,Type from Account where Id IN :opps]) {
if(a.Type == 'User') {
//then a list of accounts we want to update so we only perform 1 DML statement
           a.Type = 'Prospect'; acctoupdate.add(a); } } } //no need to DML if nothing to update
if (acctoupdate.size()> 0){ Update acctoupdate; } }

 

 

Not sure that one works but it should give you an idea on how to build it.

 

Cheers,

Fred

GobbledigookGobbledigook

First off, thanks for everyone's replies.  They really gave me a lot of direction as to thought processes and where to go. 

 

I figured it out.  I'm posting the solution I found here just in case anyone else is has the same problem.

 

trigger SetAccountToP on Opportunity (before insert, before update) 
{
     try
     {
     List<Account> ac = new List<Account>();
     
     //Set of Account Ids that we will iterate through
     Set<id> Ids = new Set<id>();
     for (Opportunity o : Trigger.new) {
         Ids.add(o.AccountId);
        }
     
     // Get the Account id and Type for each account
     Map<id, Account> owners = new Map<id, Account>([Select Type from Account Where Id in :Ids]);  
     
     for (Opportunity o : Trigger.new) 
     {
         //Gets o.Account.Type successfully and compares it to the status.  
         /*
             NOTE: Putting in o.Account.Type instead of owners.get(o.AccountId).Type will compile
                   yet will return a null value. 
         */             
         if(owners.get(o.AccountId).Type == 'User')
         {
             if(o.StageName == 'Proposal/Price Quote' || o.StageName == 'Negotiation/Review' || o.StageName == 'Closed Won')
             {
                 //Instantiate a new account and set it to the current opportunity parent.  
                 Account MK = owners.get(o.AccountId);
                 MK.Type = 'Prospect';
                 ac.add(MK);
             }    
         }
     }
     update ac;
     } 
     catch(Exception e) {
        System.debug('ERROR: '+ e);
        FD_Log.logError('Update Account Failure', ('' + e.getCause()), e.getMessage());
    }
}

 

Thanks again for everyone's assistance.  

This was selected as the best answer
sherazsheraz

Hi,

I am new to salesforce and i have to write trigger on custom object"Prod" and they purpose of that trigger is that when user enter data in field then its should update two more fields upon saving the record.

here is the example:

custom object = Prod

field 1 = field (this is text field)

field 2 = pick list field(option that should be populate is App)

field 3 = field(this text field)

if user enter in field 1 then its should poulate the field 2 = app and update the same value in field 3 = field 1.

please help me 

thanks

frederic baudaxfrederic baudax

Hi there,

 

This is something easier to achieve and to mainaint with workflow field updates as it is quite basic.

1 workflow to check if the field1 has been filled in and 2 field updates to give the correct value on both other fields (one for each of the 2 other fields) 

 

If you want to do it trigger based anyway best way to achieve this would be to use a before insert/update trigger, loop trough your trigger.new and based on the field 1 value populate field 2 and 3. Since you are in a before context no DML statement is used as it populates the fields on the fly before actualy commiting to the database. 

 

Something like this (didn't try to but should compile fine)

trigger sometrigger on Prod__c (before insert, before update) {

for (Prod__c o : Trigger.new){
if(o.field1__c != NULL){o.field2__c = 'app';
o.field3__c = o.field1__c;}

}

 

 Cheers,

Fred