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
BCDBSABCDBSA 

Batch update records in the same object under the same Account name with a specific value in a field when that field in one record is updated to that specific value

Hi All,

I have a sObject SSS that has a Customer_Account__c field looking up to Account standard object. I have a Status field in that sObject with default value "Open". I have setup an auto-update through Process Builder--whenever an SSS Line Item sObject (which is the child in a master-detail relationship with SSS) is checked in Billed__c checkbox field, the Status field in parent SSS sObject would be auto-populated to "On Hold".

Would it be possible to set up a trigger that once Status field is updated to "On Hold", the rest of SSS with the same Account and Status = "Open" would be auto-updated with the Status = "On Hold"? I have written the following codes, but I need some help with it...

Thanks  
Best Answer chosen by BCDBSA
James LoghryJames Loghry

Jolie,

A flow with a screen added to it, such as the interface you're thinking of is referred to as a "Visual Flow" or "Visual Workflow".  Otherwise, the Flow is referred to as a "Headless flow" or a "Triggered flow" in some cases.  The terminology is confusing often. 

The only difference between them is the addition of the screen for allowing user input / output.

You can invoke flows via processes, urls, visualforce pages, and more.

If you're looking for a declarive solution then I'd suggest looking at tinkering with Flows.

Otherwise, your trigger needs just a bit of work.  For one, it's not bulkified (for every account you insert, you're querying records, which is a bad practice).  Furthermore, you query to bring in additional SSS records and you change the field, but you never call a DML update on the record(s). Let's dive into this real quick:

If you were to iterate over records in the trigger scope, and since you're using a before update, the change would stick.  An example of this is the following:

trigger UpdateSSSStatusToOnHold on SSS__c (before insert, before update) {
    
    for(SSS__c SO : Trigger.New){
        //Changes stick because we're in a before insert / before update context.
        so.Status__c = 'Some Status';
    }
}

However, you're querying records, and the records returned from the query are not part of the trigger scope, so the changes need an update operation so that the changes are written back to the object.

Putting the bulkifying of the trigger to move the query outside of the for loop AND the update statement all together, you get something like the following:

 

trigger UpdateSSSStatusToOnHold on SSS__c (before insert, before update) {
    
    //Generate a set of account ids to query instead of querying through each record's accounts.
    Set<Id> accountIdsToQuery = new Set<Id>();
    for(SSS__c so : Trigger.New){
        accountIdsToQuery.add(so.Customer_Account__c);
    }

    //Bulkify the trigger by moving the query outside of the for loop.
    List<SSS__c> openSO = [SELECT Id, Name, Customer_Account__c, Status__c FROM SSS__c WHERE Status__c = 'Open' AND Customer_Account__c in :accountIdsToQuery];
            
    for(SSS__c so : openSO){
        so.Status__c = 'Credit Hold';
    }

    //Have to call update (DML operation) for changes to "stick".
    update openSO;
}

Bam, there you have it: a bulkified and hopefully working trigger.  Note: there may be a few typos or incorrect field names in there you'll have to correct.

If the solution works, please go ahead and mark this as a best answer.

- James

All Answers

James LoghryJames Loghry
Yes, you can do this with either a Process calling a Flow, a Processing calling an @InvocableMethod, or an Apex Trigger on the SSS object.  Looks like you forgot to post the code that you were working on.  Could you please use the code formatting button < > and repost the code? 
BCDBSABCDBSA
@James, could you please talk more about Flow? I thought Flow is to build interface for end users to choose field values from...
 
trigger UpdateSSSStatusToOnHold on SSS__c (before insert, before update) {
    
    for(SSS__c SO : Trigger.New){
        List<SSS__c> openSO = [SELECT Id, Name, Account, Status__c FROM SSS__c WHERE Status__c = 'Open' AND Account =:SO.Account];
            
        for(SSS__c s: openSO){
            s.Status__c = 'Credit Hold';
        }
    }
}

There is no error for the trigger, but when one of the SSS fired, the other SSS with Open status do not change the value.
James LoghryJames Loghry

Jolie,

A flow with a screen added to it, such as the interface you're thinking of is referred to as a "Visual Flow" or "Visual Workflow".  Otherwise, the Flow is referred to as a "Headless flow" or a "Triggered flow" in some cases.  The terminology is confusing often. 

The only difference between them is the addition of the screen for allowing user input / output.

You can invoke flows via processes, urls, visualforce pages, and more.

If you're looking for a declarive solution then I'd suggest looking at tinkering with Flows.

Otherwise, your trigger needs just a bit of work.  For one, it's not bulkified (for every account you insert, you're querying records, which is a bad practice).  Furthermore, you query to bring in additional SSS records and you change the field, but you never call a DML update on the record(s). Let's dive into this real quick:

If you were to iterate over records in the trigger scope, and since you're using a before update, the change would stick.  An example of this is the following:

trigger UpdateSSSStatusToOnHold on SSS__c (before insert, before update) {
    
    for(SSS__c SO : Trigger.New){
        //Changes stick because we're in a before insert / before update context.
        so.Status__c = 'Some Status';
    }
}

However, you're querying records, and the records returned from the query are not part of the trigger scope, so the changes need an update operation so that the changes are written back to the object.

Putting the bulkifying of the trigger to move the query outside of the for loop AND the update statement all together, you get something like the following:

 

trigger UpdateSSSStatusToOnHold on SSS__c (before insert, before update) {
    
    //Generate a set of account ids to query instead of querying through each record's accounts.
    Set<Id> accountIdsToQuery = new Set<Id>();
    for(SSS__c so : Trigger.New){
        accountIdsToQuery.add(so.Customer_Account__c);
    }

    //Bulkify the trigger by moving the query outside of the for loop.
    List<SSS__c> openSO = [SELECT Id, Name, Customer_Account__c, Status__c FROM SSS__c WHERE Status__c = 'Open' AND Customer_Account__c in :accountIdsToQuery];
            
    for(SSS__c so : openSO){
        so.Status__c = 'Credit Hold';
    }

    //Have to call update (DML operation) for changes to "stick".
    update openSO;
}

Bam, there you have it: a bulkified and hopefully working trigger.  Note: there may be a few typos or incorrect field names in there you'll have to correct.

If the solution works, please go ahead and mark this as a best answer.

- James
This was selected as the best answer
BCDBSABCDBSA
@James
Thank you so much!! That has been too helpful!