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
ALAL 

Apex Class Contains Method

Hi, I have a class which loops through an account and then loops through all of the assets within that account to see if the assets have a certain status. I'm trying to use the contains method on the map of accounts but I'm getting the error message that the method doesn't exist or incorrect signature: void contains(boolean) from the type Map.Is there a way to search the status of the assets within an account to see if the status is present.? Thank you. 
 
public class AccountActiveProducts {

    
    public AccountActiveProducts(){
      List<Account> accountsToUpdate = new List<Account>();
      List<Account> oldAccountsToUpdate = new  List<Account>();
    }
   // public static void updateAccounts(List<SObject> assetLists, Map <Id, Account> AccountOldMap){   
  public static void updateAccounts(List<SObject> assetLists){
            List<Account> accountsToUpdate = new List<Account>();
            Set<String> setAssetsToRemove = new  Set<String>();
            List<String> listAssetsToRemove = new List<String>();
            Set<Id> ParentIds = new Set<Id>();
            for(Asset asset:(List<Asset>)assetLists){
                ParentIds.add(asset.AccountId); 
            }   
        
  //      for(Asset oldAsset:AccountOldMap){
            
  //      }
            Map<Id, Account> mapAccount = new Map<Id, Account>([Select Id, ProductsOwned__c,  (Select Id, ProductFamily__c, IsCompetitorProduct, Status from Assets Where  (Status != 'Retired' OR Status != 'Obsolete' OR Status != null)) From Account Where Id In: ParentIds]); 
          //  Map<Id, Account> mapAccountPurchased = new Map<Id, Account>([Select Id,  (Select Id, ProductFamily__c, Status from Assets Where  ( Status != null)) From Account Where Id In: ParentIds]);                                                   


       
            if(Trigger.isInsert || Trigger.isUpdate){ 
               for(Account ac : mapAccount.values()){
  
                   List<String> assetList = new List<String>();
                   Set<String> assetSet = new Set<String>();
                   Set<String> assetsPurchased = new Set<String>();
                   List<String> assetValues =  new List<String>();
                   for(Asset accountAsset: ac.assets){
                   if(accountAsset.Status != 'Retired' || accountAsset.Status != 'Obsolete'|| accountAsset.IsCompetitorProduct != true ){

                       assetSet.add(accountAsset.ProductFamily__c);
                       }
                       
                   
                       
                 //   if(accountAsset.Status == 'Retired' || accountAsset.Status == 'Obsolete' && (!ac.assets.contains(accountAsset.Status == 'Retired') || !ac.assets.contains(accountAsset.Status == 'Obsolete'))){
                 //    if(ac.assets.contains(accountAsset.status == 'Retired' || accountAsset.status == 'Obsolete' )
                       
              //         if(accountAsset.Status == 'Retired' || accountAsset.Status == 'Obsolete'|| accountAsset.IsCompetitorProduct == true){
                    
******* This is where I'm trying to search for the status. 

   if((accountAsset.Status == 'Retired' || accountAsset.Status == 'Obsolete'|| accountAsset.IsCompetitorProduct == true) &&  !(mapAccount.contains(accountAsset.Status == 'Installed' || accountAsset.Status == 'Registered' || accountAsset.Status == 'Shipped') )){
                          assetSet.remove(accountAsset.ProductFamily__c);
                       }
                       
                   }
                   assetList.addAll(assetSet);
                   assetList.sort();
                   String productFamily = string.join(assetList,', ' );
                   
                   if(ac.ProductsOwned__c != productFamily ){
                       ac.ProductsOwned__c = productFamily;
                       
                   accountsToUpdate.add(ac);
                   }
                   
               }
            
  
              //End of for loop above
              
          
               
               if(!accountsToUpdate.isEmpty()){
                   upsert accountsToUpdate;
               }
           }
            if(Trigger.isDelete){
                
                
            }
  
            }

}

 
Best Answer chosen by AL
Boss CoffeeBoss Coffee
Okay, I finally got around to actually checking this code in my console. I've moved around a few lines, formatted it, and removed the code that I wasn't using for this use case. I tested it out in a test org of mine and it seems to be working properly. Let me know if the below code works for you.

AssetPrimaryTrigger
trigger AssetPrimaryTrigger on Asset (before insert, before update, after insert, after update, before delete, after delete) { 
    
    AccountActiveProducts aap;
    if(Trigger.isAfter){
        if(Trigger.isInsert || Trigger.isUpdate ){
            AccountActiveProducts.updateAccounts(trigger.new); 
        } 
    } 
}
AccountActiveProducts
public class AccountActiveProducts {
    
    public static void updateAccounts(List<SObject> assetLists){
        List<Account> accountsToUpdate = new List<Account>();
        Set<String> setAssetsToRemove = new  Set<String>();
        List<String> listAssetsToRemove = new List<String>();
        Set<Id> ParentIds = new Set<Id>();
        for(Asset asset:(List<Asset>)assetLists){
            ParentIds.add(asset.AccountId); 
        }   
        
        Map<Id, Account> mapAccount = new Map<Id, Account>([
            Select Id, ProductsOwned__c, (Select Id, ProductFamily__c, IsCompetitorProduct, Status from Assets) 
            From Account Where Id In: ParentIds
        ]);           
        
        for(Account ac : mapAccount.values()) {     
            List<String> assetList = new List<String>();
            Set<String> assetSet = new Set<String>();
            Set<String> assetsPurchased = new Set<String>();
            List<String> assetValues =  new List<String>();
            
            for(Asset accountAsset: ac.assets){
                if(accountAsset.Status != 'Retired' && accountAsset.Status != 'Obsolete' && accountAsset.IsCompetitorProduct != true ){
                    assetSet.add(accountAsset.ProductFamily__c);
                }
            }
            
            assetList.addAll(assetSet);
            assetList.sort();
            String productFamily = string.join(assetList,', ');
            
            if(ac.ProductsOwned__c != productFamily ){
                ac.ProductsOwned__c = productFamily;
                accountsToUpdate.add(ac);
            }
        }
        
        if(!accountsToUpdate.isEmpty()){
            upsert accountsToUpdate;
        }
    }
}

All Answers

Boss CoffeeBoss Coffee
if((accountAsset.Status == 'Retired' || accountAsset.Status == 'Obsolete'|| accountAsset.IsCompetitorProduct == true) && !(mapAccount.contains(accountAsset.Status == 'Installed' || accountAsset.Status == 'Registered' || accountAsset.Status == 'Shipped'))) 
You're referring to the line above, correct? I don't believe there is a contains method for a Map.

From what I see, you're already iterating through each Account and each Asset belonging to a single Account. Is there a reason you want to check the map again?
ALAL
Hi, I was looking to check the map again because we had some account records in our system where we had assets with the same product family but one of the asset's status is 'Retired' and the other 'Shipped'. Because one of the statuses is shipped (i.e. add to the set, assetSet) then that asset's product family should roll up to the account's active products field. However, because the other asset's status is retired, the asset's product family is being removed from the account's active products field due to the set, assetsToRemove. 

So I was wondering if maybe using a trigger.oldMap would work in this case to scroll through all of the asset's in the account and take any assets whose status isn't retired or obsolete and roll that product family into the active products field. 
Boss CoffeeBoss Coffee
Correct me if my understanding is incorrect, but you'd like to prevent a product family that was added because of statuses such as 'Shipped' even if there was another asset that with 'Retired'?
From what I see, you're populating assetSet only when the asset has the status you want, so what is the use case of the assetSet.remove line?
ALAL
Sorry for the misunderstanding. I'm basically adding the product family to the account's active products field if the asset's status is shipped, installed, or registered. If the asset's status gets changed to Retired or Obsolete then I'd like to remove it's product family from the active products field. The only time where I wouldn't want to remove remove the product family with a status of retired or obsolete is if there is another asset on the same account with the same product name, but a status of installed, registered, or shipped. For example, I have an account with an existing asset, Asset A, with a status of 'Retired'. In this case, I'd like to remove Asset A's product family from the active products field. However if I add another asset, Asset B, to the account that has the same product family as Asset A, but a status of shipped, installed, or registered, then I'd like to add Asset B's product family to the active products field. Not sure if that helps a little bit. But thank you for taking the time to review.
Boss CoffeeBoss Coffee
Set does have a contains method. The assetSet is reinitialized for each account, so any product families added should have passsed your first check. If you come across an asset that is Retired or Obsolete, you can check the current iteration's assetSet to see if it had already been added from a previous check. Being in the assetSet means that it must have had a status of shipped, installed, or registered.
Deepali KulshresthaDeepali Kulshrestha
Hi,
Greetings to you!

- You were trying to give condition in contains method but it will take only 'Id' of 
- On line number 48, use the below line : - 
if((accountAsset.Status == 'Retired' || accountAsset.Status == 'Obsolete'|| accountAsset.Status == 'Installed' ||  accountAsset.Status == 'Registered' || accountAsset.Status == 'Shipped' || accountAsset.IsCompetitorProduct == true) &&  (!(mapAccount.contains(ac)))){
I hope you find the above solution helpful. If it does, please mark as Best Answer to help others too.

Thanks and Regards,
Deepali Kulshrestha.
ALAL
Hi thank you for your suggestion. I tried using (!(mapAccount.contains(ac), but I got an error message: Method does not exist or incorrect signature: void contains(Account) from Type map. I then tried using ac.Id, but I got a similar error. I'm wondering if there's a way I can use the contain method to show if the account (ac) contains any assets with a status of 'retired' or 'obsolete'? Thank you.
Boss CoffeeBoss Coffee
Map doesn't have a contains method, but it does have a containsKey method. However, that will not be that helpful in this scenario because the key is the Account ID and you already have access to the value, Account.
for(Asset accountAsset: ac.assets){

// IF A
                   if(accountAsset.Status != 'Retired' || accountAsset.Status != 'Obsolete'|| accountAsset.IsCompetitorProduct != true ){

                       assetSet.add(accountAsset.ProductFamily__c);
                       }

// IF B
   if((accountAsset.Status == 'Retired' || accountAsset.Status == 'Obsolete'|| accountAsset.IsCompetitorProduct == true) &&  !(mapAccount.contains(accountAsset.Status == 'Installed' || accountAsset.Status == 'Registered' || accountAsset.Status == 'Shipped') )){
                          assetSet.remove(accountAsset.ProductFamily__c);
                       }
                       
}
Could I get clarification on this loop through Account assets? If the assetSet is initialized to an empty set before going through an Account's assets, then the set should only include product families that are not Retired/Obsolete/etc, correct? I may not be understanding the use case of removing from the assetSet when it should only contain product families you want to add.
ALAL
The loop scrolls through all of the assets in the account. If the asset's status isn't retired or obsolete, then I'd like to add that asset's product family to the account's active products field. If the asset's status is retired or obsolete, then I would like to remove it from the active products field unless there is another asset on the account with the same product family and has an active status (i.e. registered, shipped, installed). Not sure if that helps a little bit. Thank you for your help.
Boss CoffeeBoss Coffee
I think that's where my confusion is coming from. assetSet is empty when it enters the loop through the Account assets, so even if it found an asset status of Retired or Obsolete, there shouldn't be anything to remove from the assetSet. It will only remove a product family from assetSet if you already added it from the first if (marked as IF A above), but that means you wouldn't want to remove it. Would removing the second If statement (the remove If) resolve your issue?
for(Account ac : mapAccount.values()){
                   List<String> assetList = new List<String>();
                   // ASSET SET LINE
                   // Will be a new, empty set each time before iterating through an account's assets
                   Set<String> assetSet = new Set<String>();
                   Set<String> assetsPurchased = new Set<String>();
                   List<String> assetValues =  new List<String>();

                   // BEGIN LOOPING THROUGH ACCOUNT ASSETS with assetSet being empty
                   for(Asset accountAsset: ac.assets){

                      // IF A
                      // Look at the current asset, add if desired
                      if(accountAsset.Status != 'Retired' || accountAsset.Status != 'Obsolete'|| accountAsset.IsCompetitorProduct != true ){
                         assetSet.add(accountAsset.ProductFamily__c);
                      }

                      // IF B
                      // Check if needing to remove
                      // But because we enter the asset loop with an empty set
                      // The only values in this set should ONLY be the ones you wanted to add from IF A
                      if((accountAsset.Status == 'Retired' || accountAsset.Status == 'Obsolete'|| accountAsset.IsCompetitorProduct == true)){
                         assetSet.remove(accountAsset.ProductFamily__c);
                      }
                    }
}

 
ALAL
Thanks I think I understand your point. We would still like to have the remove aspect, but maybe I can try adding the asset's from part B (with status of retired or obsolete) to a brand new set. Then if that set is not null, then I can remove those assets from the active products field?
Boss CoffeeBoss Coffee
For the active products field, is the following what you're referencing? If it is, then it should already 'remove' the product families because you're completely replacing the old String with the new String, with the new String only including the product families you wanted to add.
assetList.addAll(assetSet);
assetList.sort();
String productFamily = string.join(assetList,', ' );
                   
if(ac.ProductsOwned__c != productFamily ){
   ac.ProductsOwned__c = productFamily;
                       
   accountsToUpdate.add(ac);
}

 
ALAL
Thank you very much. It looks like what you suggested by just keeping part A works.
Boss CoffeeBoss Coffee
Good to hear!
ALAL
Hi, thank you again for your help. In doing some more testing, it looks like I may have to remove the older product families from the asset set. What I'm finding is that if I remove the assetRemove piece (part B) from the code, then even assets with a status of Retired or Obsolete rollup to the account. In some cases I have assets with the same product family, but some have an active status and others have retired statuses. When that's the case the product family should still rollup to the account because there are product familys with active status. Being that this is the case, would a trigger.oldMap help to scan all of the assets on the account?
Boss CoffeeBoss Coffee
Currently, your IF A logic only checks at least one condition. By this, I mean if it is 'Retired', then it passes the not Obsolete check, which allows it to be added. You need to change the logic so it checks all conditions.

In your IF A, change the || to &&.
// IF A
if(accountAsset.Status != 'Retired' && accountAsset.Status != 'Obsolete' && accountAsset.IsCompetitorProduct != true ){
  assetSet.add(accountAsset.ProductFamily__c);
}
ALAL
Thank you. For some reason even when I include the && instead of the || for the part A, the asset’s product family isn’t rolling up to the active products field. However that is for a product family that already is on the existing record. I’m thinking maybe of creating a count static variable and group each product family separately. So for example if there are two assets on the account where one has a status of installed and another has retired then I want to include the product family in the active products field. Not sure if that makes sense.
Boss CoffeeBoss Coffee
Could you clarify a bit on what isn't rolling up correctly? I don't quite understand what you mean by product family already on an existing record

In your example, an Account has two assets, first one installed and the second one retired, so what should be the result?
ALAL
Sorry about the confusion. So in the example the expected outcome is that the value of the product family field on the asset record should roll up to the active products field on the account if the asset is created or edited. Currently on one particular record we have assets of the same product family where some are retired and others are installed (I.e. should roll up to the account). If I edit one of these assets to installed then the expected outcome is that it should roll up to the active products field, but it’s not rolling up at all. I inserted a debug line statement and it’s not even registering a change on the account’s active products field.
Boss CoffeeBoss Coffee
Is the current code that was displayed the helper class for the trigger? Do you have the trigger class that redirects to this helper one?
ALAL
Yes, I have a trigger that references the helper class. The trigger is below. Thank you for your help. trigger AssetPrimaryTrigger on Asset (before insert, before update, after insert, after update, before delete, after delete) { //AccountActiveProducts aap; if(Trigger.isBefore){ if(Trigger.isInsert){ } if(Trigger.isUpdate){ } if(Trigger.isDelete){ } } if(Trigger.isAfter){ if(Trigger.isInsert || Trigger.isUpdate ){ AccountActiveProducts.updateAccounts(trigger.new); AccountProductsPurchased.updateAccounts(trigger.new); } if(Trigger.isDelete){ } } if(Trigger.isAfter){ if(Trigger.isInsert || Trigger.isUpdate){ AccountProductsPurchased.updateAccounts(trigger.new); } if(Trigger.isDelete){ } } }
Boss CoffeeBoss Coffee
So the issue is that you see no changes whatsoever from the trigger?

Try removing the if line in your helper class and see if it changes anything.
if(Trigger.isInsert || Trigger.isUpdate){
ALAL
I removed the line in the trigger and it didn't result in a change if I edited or added one of the product families (e.g. Product Family A) that was already on the account. If I added a different product family (e.g. Product Family B), then it would rollup to the active products field.
Boss CoffeeBoss Coffee
When you say you add an asset with the same product family, shouldn't it not change?

Is it a competitor product?
ALAL
The asset that I’m looking to add isn’t a competitor product. If the account’s active products field is null for example, and there are assets with the same product family but different status (e.g. one retired and one installed), then if I make an edit on the installed asset, it should roll up to the account.
Boss CoffeeBoss Coffee
Could you outline the exact scenario where it is not rolling up, such as an example Product Family field on the Account along with example assets?

Also, does it ever work if the active products field is null?
ALAL
The testing did work if the active products field is null, but that was if I was adding a brand new product family to an asset that didn't already exist on the account. A scenario that I'm looking at is the following. 1. Currently on the account, the active products field has a product family value of 'Product Family A'. 2. On the account I have three assets. A. Asset #1 - Has a status of 'Installed' and a Product Family of 'Product Family A' (which is currently in the accounts active products field). B. Asset #2 - Has a status of 'Retired' and a Product Family of 'Product Family B' C. Asset #3 - Has a status of 'Installed' and a Product Family of 'Product Family B'. If I were to make a minor edit to asset #3 and keep it's status, then asset #3's product family should rollup to the account's active products field, even though asset #2 has the same product family and is retired.
Boss CoffeeBoss Coffee
For clarification, is that the scenario that rollup is not happening? Asset #3's product family is not being added to the Account's product family value? The result should be a product family value of 'Product Family A, Product Family B' then, right?
ALAL
Correct. The rollup is not happening in the scenario and Asset #3 is not being added to the account's active products field. The result should be a value of Product Family A and Product B. Thank you.
Boss CoffeeBoss Coffee
Okay, I finally got around to actually checking this code in my console. I've moved around a few lines, formatted it, and removed the code that I wasn't using for this use case. I tested it out in a test org of mine and it seems to be working properly. Let me know if the below code works for you.

AssetPrimaryTrigger
trigger AssetPrimaryTrigger on Asset (before insert, before update, after insert, after update, before delete, after delete) { 
    
    AccountActiveProducts aap;
    if(Trigger.isAfter){
        if(Trigger.isInsert || Trigger.isUpdate ){
            AccountActiveProducts.updateAccounts(trigger.new); 
        } 
    } 
}
AccountActiveProducts
public class AccountActiveProducts {
    
    public static void updateAccounts(List<SObject> assetLists){
        List<Account> accountsToUpdate = new List<Account>();
        Set<String> setAssetsToRemove = new  Set<String>();
        List<String> listAssetsToRemove = new List<String>();
        Set<Id> ParentIds = new Set<Id>();
        for(Asset asset:(List<Asset>)assetLists){
            ParentIds.add(asset.AccountId); 
        }   
        
        Map<Id, Account> mapAccount = new Map<Id, Account>([
            Select Id, ProductsOwned__c, (Select Id, ProductFamily__c, IsCompetitorProduct, Status from Assets) 
            From Account Where Id In: ParentIds
        ]);           
        
        for(Account ac : mapAccount.values()) {     
            List<String> assetList = new List<String>();
            Set<String> assetSet = new Set<String>();
            Set<String> assetsPurchased = new Set<String>();
            List<String> assetValues =  new List<String>();
            
            for(Asset accountAsset: ac.assets){
                if(accountAsset.Status != 'Retired' && accountAsset.Status != 'Obsolete' && accountAsset.IsCompetitorProduct != true ){
                    assetSet.add(accountAsset.ProductFamily__c);
                }
            }
            
            assetList.addAll(assetSet);
            assetList.sort();
            String productFamily = string.join(assetList,', ');
            
            if(ac.ProductsOwned__c != productFamily ){
                ac.ProductsOwned__c = productFamily;
                accountsToUpdate.add(ac);
            }
        }
        
        if(!accountsToUpdate.isEmpty()){
            upsert accountsToUpdate;
        }
    }
}
This was selected as the best answer
ALAL
Thank you very much. It looks like removing the assetRemove set from the code work.
Boss CoffeeBoss Coffee
Glad to hear it's working! The biggest changes I made were to move the add to set line out of the inner for loop, and I moved the update list line outside of the outer for loop.