I have a VF page with a custom controller. The page is designed to provide an enhanced Opportunity Product search and add function. When the user clicks to add a Product to an Opp, the VF page gives them a search option and the ability to add products 1 by 1. This all works as expected, however, I need to enter 2 validations into my Save method of the controller. Essentially, I need the following:

1) If the Product with Product Code "PREM_PORTFOLIO" is included in the shopping cart, and there are no other products with the JN_Portfolio__c custom field (checkbox) checked in the cart, it should not allow save.

2) If there is at least 1 item in the cart with the JN_Portfolio__c custom field (checkbox) checked, but the Product with Product Code "PREM_PORTFOLIO" is not included in the shopping cart, it should not allow save.

I currently get an error on line 87 stating that my variable cannot be found. Can anyone help?


    public with sharing class opportunityProductEntryExtension {

        public Opportunity theOpp {get;set;}
        public String searchString {get;set;}
        public opportunityLineItem[] shoppingCart {get;set;}
        public priceBookEntry[] AvailableProducts {get;set;}
        public Pricebook2 theBook {get;set;}   

        public String toSelect {get; set;}
        public String toUnselect {get; set;}
        public Decimal Total {get;set;}

        public Boolean portfolio {get;set;}
        public Boolean portfolioChk {get;set;}
        public Boolean overLimit {get;set;}

        private Boolean forcePricebookSelection = false;

        private opportunityLineItem[] forDeletion = new opportunityLineItem[]{};

        public opportunityProductEntryExtension(ApexPages.StandardController controller) {

            theOpp = [select Id, Pricebook2Id, PriceBook2.Name from Opportunity where Id = :controller.getRecord().Id limit 1];

            // If products were previously selected need to put them in the "selected products" section to start with
            shoppingCart = [select Id, JN_Portfolio__c, JN_Portfolio_Rate__c, Image_Link__c, Includes_Model__c, Image_ID__c, Quantity, TotalPrice, UnitPrice, Description, PriceBookEntryId, PriceBookEntry.Name, PriceBookEntry.IsActive, PriceBookEntry.Product2Id, PriceBookEntry.Product2.Name, PriceBookEntry.PriceBook2Id from opportunityLineItem where OpportunityId=:theOpp.Id];

            theBook = theOpp.Pricebook2;


        public void updateAvailableList() {

            // We dynamically build a query string and exclude items already in the shopping cart
            String qString = 'select Id, Pricebook2Id, IsActive, Product2.Name, Product2.Family, Product2.IsActive, Product2.Description, UnitPrice from PricebookEntry where IsActive=true and Pricebook2Id = \'' + theBook.Id + '\'';

            // note that we are looking for the search string entered by the user in the name OR description
            // modify this to search other fields if desired
                qString+= ' and (Product2.Name like \'%' + searchString + '%\' or Product2.Description like \'%' + searchString + '%\')';

            Set<Id> selectedEntries = new Set<Id>();
            for(opportunityLineItem d:shoppingCart){
                if(d.PriceBookEntry.Product2.ProductCode == 'PREM_PORTFOLIO'){
                     portfolio = true;
                if(d.JN_Portfolio__c == true){
                     portfolioChk = true;

                String tempFilter = ' and Id not in (';
                for(Id i : selectedEntries){
                    tempFilter+= '\'' + (String)i + '\',';
                String extraFilter = tempFilter.substring(0,tempFilter.length()-1);
                extraFilter+= ')';

                qString+= extraFilter;

            qString+= ' order by Product2.Name';
            qString+= ' limit 101';

            system.debug('qString:' +qString);        
            AvailableProducts = database.query(qString);

            // We only display up to 100 results... if there are more than we let the user know (see vf page)
                overLimit = true;

        public void addToShoppingCart(){

            // This function runs when a user hits "select" button next to a product
            for(PricebookEntry d : AvailableProducts){
                    shoppingCart.add(new opportunityLineItem(OpportunityId=theOpp.Id, PriceBookEntry=d, PriceBookEntryId=d.Id, UnitPrice=d.UnitPrice));
                if(d.ProductCode == 'PREM_PORTFOLIO'){
                    portfolio = true;
                if(d.JN_PORTFOLIO__c == true){
                    portfolioChk = true;

        public PageReference onSave(){
System.debug('@@@@@@@@@@ portfolio: '+portfolio+'  ########## portfolioChk: '+portfolioChk);
            // If previously selected products are now removed, we need to delete them

            if(portfolio == true && (portfolioChk == false || portfolioChk == null)){
                    ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'You need to add the associated Products') );
            if((portfolio == false || portfolio == null) && portfolioChk == true){
                    ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'You need to add the Product') );

            // Previously selected products may have new quantities and amounts, and we may have new products listed, so we use upsert here
            catch(Exception e){
                return null;

            // After save return the user to the Opportunity
            return new PageReference('/' + ApexPages.currentPage().getParameters().get('Id'));

1 Answer 1


You are trying to access d.JN_PORTFOLIO__c which is coming from AvailableProducts, but in the following query you have not included.

That's why the error is.

String qString = 'select Id, Pricebook2Id, IsActive, 
Product2.Name, Product2.Family, Product2.IsActive, Product2.Description, UnitPrice 
from PricebookEntry where IsActive=true and Pricebook2Id = \'' + theBook.Id + '\'';

Also, I could think of JN_PORTFOLIO__c field is part of opportunityLineItem

So, you need to construct the query as well as check JN_PORTFOLIO__c field considering correct object.

Update based on Comments

To see error messages, add <apex:pageMessages/> in visualforce

  • Thanks. I added Product2.JN_Portfolio__c to that query and still get the same error. Jun 2, 2017 at 16:19
  • OK. I updated my code and it saves. I added lines 46-51, 101, and 106-111. I am trying to generate the validation error off my local variables set in 46-51. The debug statement in line 101 shows my criteria is correct, but the validations in 106-111 are not firing when the Save method is called. Any idea why? Jun 2, 2017 at 18:43
  • 1
    did you add <apex:pageMessages/> in visualforce? Jun 2, 2017 at 18:56

You must log in to answer this question.

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