0

I have an object - myCustomObject__c that is has a Master-Detail relationship to Opportunity. On this object I also have a lookup to Product.

I want to throw a validation error if a user tries to populate the lookup to Product that does not already exist on an Opportunity. Something like this: "Product is not listed on the Opportunity and cannot be added to myCustomObject."

Am I overthinking this? I thought about maybe having a list of comma separated ProductIds on the Opportunity and checking the following in a validation rule:

myCustomObject__c.ProductIds.CONTAINS(Product__c)

But then I'm not sure what the best way to maintain that list outside of Apex would be... or if it is even feasible...

1
  • 1
    a validation rule on an object can't look at fields in children objects; only at fields on itself or lookup objects
    – cropredy
    Commented Apr 26, 2016 at 19:12

1 Answer 1

1

Pretty sure you need Apex for this, and I don't think storing the Id values in a separate field is worth the trouble. Using a collection based approach, you need to generate a Map<Id, Set<Id>>, where the key is the Id of the Opportunity, and the value is the collection of all related Product Id values.

public static void validateProducts(List<MyCustomObject__c> records)
{
    Map<Id, Set<Id>> opportunityToProducts = new Map<Id, Set<Id>>();
    for (MyCustomObject__c record : records)
        opportunityToProducts.put(record.Opportunity__c, new Set<Id>());
    // now you have a keyset with all Opportunity Ids

    for (OpportunityLineItem oli : [
        SELECT OpportunityId, PricebookEntry.Product2Id
        FROM OpportunityLineItem
        WHERE OpportunityId IN :opportunityToProducts.keySet()
    ])
        opportunityToProducts.get(oli.OpportunityId)
            .add(oli.PricebookEntry.Product2Id);
    // now for any individual Opportunity Id you can determine
    // which Product Ids have been added

    for (MyCustomObject__c record : records)
    {
        Set<Id> validProductIds = opportunityToProducts.get(record.Opportunity__c);
        if (!validProductIds.contains(record.Product__c))
            record.addError(Label.Missing_Product);
            // if you really do not want to use a label, you can use the below instead
            // record.addError('Some custom message');
    }
}

The above functionality can be called from a trigger on MyCustomObject__c. I recommend using a Custom Label to store the error message you want to use so it can be easily configured if needed.

You must log in to answer this question.

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