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'));

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 '17 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 '17 at 18:43
  • 1
    did you add <apex:pageMessages/> in visualforce? Jun 2 '17 at 18:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.