1

I am completely new to apex and could use a bit of help (ok a lot of help) Thank you for the help in advance, this fellow Canadian could really use it.

Basically I have a lookup field on the account to opportunity (Related_Opp_c) and a checkbox on the opportunity that evaluates to true if the Opportunity is the most recent open opportunity. Essentially what I want to do is auto-populate the Related opp field on account with the opportunity that is checked as the most recent, and if no opportunities on the account are checked I want the field blanked out.

After looking through the site I found a similar scenario but not quite, I just don't understand how to get the opportunity to populate into the account lookup field.

Example code below:

trigger Account_Relatedoppudate on Opportunity(after insert, after update)
{     
    List<ID> OppId = new list<ID>();

    for(Opportunity opp : Trigger.new)
    {
        // get the previous value of the field.  need handle an insert/update
        Boolean previousRecentOpenSalesOppValue = Trigger.oldMap != null && Trigger.oldMap.containsKey(Opp.ID) ? Trigger.oldMap.get(Opp.ID).Recent_Open_Sales_Opp__c : false;

        // only do this when the value changes
        if(opp.Recent_Open_Sales_Opp__c == true && previousRecentOpenSalesOppValue == false)
            OppId.add(opp.id);
    }

    // Check that we have some records to update
    if(!OppId.isEmpty())
    {
        list<Account> acclist = [SELECT id, related_opp_c FROM Account WHERE 
                                             Name IN :OppId];

        // loop through the results and update the fields
        for(Account acc : acclist)
        {
            acc.related_opp_c = Opp.Id;
        }

        update acclist;
    }
}

1 Answer 1

0

I'll start with a few quick code style suggestions, just to get them out of the way

  • Although it isn't required to use curly braces for an if/else that is only a single line, I'd argue it's still a good idea. Consistency in code style is important, and omitting braces means it incurs a higher cognitive load to digest. This can also be a source of errors that are easy to gloss over
  • If you end up writing something like <condition> == true or <condition> == false, you can replace them with simply <condition> and !<condition>
  • If trigger.oldMap != null, then every Id in the oldMap will always exist in the newMap as well
  • It's highly recommended to use a trigger framework like Chris Aldrige's or Kevin O'Hara's. You don't have to do that now, especially if you're just getting your feet wet in Apex, but it's something you should keep in mind

Onto the main event now.

I find several aspects of this approach to be odd.

  • Unless there's a specific reason why you need a checckbox to indicate the most recent open Opp, I'd think that using the CreatedDate, LastModifiedDate, or CloseDate of the Opportunities would be more reliable (and require less user input)
  • Opportunity Ids look something like 006000002t3o001, and I think it's unlikely that your Accounts have names like that. The Opportunity SObject has a standard relationship field to Account called AccountId

Your trigger here can be one either Account or Opportunity, and I think having it on Opportunity is the right call. Since you're making changes to records other than those (Opporunties) being operated on, using after trigger contexts is also the right call.

If your trigger is able to be saved without issue and isn't throwing any exceptions (it's just not updating your Accounts), then I suspect the reason would be that your [SELECT id, related_opp_c FROM Account WHERE Name IN :OppId]; query isn't returning any results (which is the outcome I'd expect here).

Assuming that you're using Accounts and Opportunities the way Salesforce intended them to be used (more or less), the approach I'd take would look something like this

// This is pseudo-code, and will not compile as-is
trigger on Opportunity{
    // Assuming that we can determine the "most recent open opp" based on the CreatedDate, our
    //  job here is to:
    // 1) Figure out which Accounts are involved in the Opportunities going through this trigger
    // 2) Query for the Open Opportunities related to those Accounts
    // 3) Determine which Opportunity is the "most recent"
    // 4) Update the respective Accounts

    // This general pattern of looping over trigger context variables, gathering data, querying, 
    //   and then processing the result is one that you'll see used over and over.
    // Salesforce likes it when we work on collections of things instead of working on records
    //   one at a time

    // Step 1: Figuring out which Accounts are involved
    Set<Id> accountIds = new Set<Id>();
    for(opp from trigger.new){
        accountIds.add(opp.AccountId);
    }

    // Step 2: Querying for related Opps
    // This one can be done in a few different ways.
    // I think this one probably ends up being the least amount of work.
    // We can use a parent-child subquery inside of the main query to get related child records.
    // Here, Account = the parent record, Opportunities = the child records
    List<Account> accountsWithOpps = [SELECT Id, (SELECT Id FROM Opportunities WHERE ForecastCategory = 'Open' ORDER BY CreatedDate DESC LIMIT 1) FROM Account WHERE Id IN :accountIds];

    // Step 3, determining the most recent Opp, was taken care of by the query above.
    // It's nice to be able to have SOQL do the heavy lifting when possible, as it means
    //   we need to write less code (and therefore have a lesser chance of making a mistake)

    // Step 4, processing the results and updating records
    // Here is where we can make sure that the related_opp__c field is updated appropriately.
    // If there is no most recent open opp, then we can take care of clearing that field too
    for(account from the above query){
        // child records queried through a subquery are available as a list embedded within each
        //   parent record

        // One method to update fields is to assume a default, and then try to prove that it
        //   should be something else.
        // Doing this can possibly make the rest of the code easier to write.
        // Here, let's assume that the related_opp__c field should be null
        acct.related_opp__c = null;

        if(!acct.Opportunities.isEmpty()){
            acct.related_opp__c = acct.Opportunities[0].Id;
        }
    }

    // DML and Queries are two things that should virtually never be inside of a loop
    update accountsWithOpps;
}
5
  • Hi Derek, truly appreciate this you have no idea! I'm just having issues understanding this line : List<Account> accountsWithOpps = [SELECT Id, (SELECT Id FROM Opportunities WHERE ForecastCategory = 'Open' ORDER BY CreatedDate DESC LIMIT 1)]; it seems to be throwing errors on me, such as unexpected token. Apologies I'm a complete beginner so some clarity would be extremely appreciated
    – AS5900
    Mar 16, 2021 at 17:10
  • @AS5900 Whoops, looks like I stopped at the end of the subquery and didn't finish the main query. I've updated my answer to fix that. In general, the best place to get aquainted with new concepts/features on the Salesforce platform is trailhead.salesforce.com The "SOQL for Admins" module contains a section on relationship queries and it goes over both child-to-parent and parent-to-child queries.
    – Derek F
    Mar 16, 2021 at 17:59
  • Hi @Derek, it is now 12 am here in Canada, and I'm at my wits end..how did I get here hahaha...so when I execute the trigger, the related opportunity field on the account does not update. Is there something I missed ?
    – AS5900
    Mar 17, 2021 at 4:38
  • @AS5900 Hard to say without more information. You should edit your question to add more detail. If you're getting an error message, you should include the full text of it (and the stack trace) verbatim. Do your Opportunities have the AccountId field populated? Is Open one of your Forecast Categories?
    – Derek F
    Mar 17, 2021 at 13:23
  • thank you so much for your guidance, I stepped away for a bit to clear my mind, and your responses really helped guide me, its now working. I Cant thank you enough!
    – AS5900
    Mar 22, 2021 at 2:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .