• Gabe Rothman 8
  • NEWBIE
  • 60 Points
  • Member since 2015

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 9
    Questions
  • 14
    Replies

I have a visualforce page that we use to add products to opporttunities. Before inserting the line items I need to run an aggregateresult query to get the values of several fields in order to insert an additional support line-item and populate it's fields with the aggregated results from the query.  In order to accomplish this, I need to query the values that have been input in the Visualforce page before they are inserted into the database so that I can insert all of the line-items at once.  Thanks for your help!

Here is my relevant code snippet:

public PageReference onSave(){
        Decimal supportQty;  
        Decimal svcTerm;  
        Decimal sprice;
        List<Dynamic_Pricing__c> dplist = [SELECT Pricing_Coefficient__c, Pricing_Type__c FROM Dynamic_Pricing__c];
        Map<string, decimal> supportPricingMap = new Map<string, decimal>();                                                                    
        List<PriceBookEntry> supportSkus = [SELECT Id, Name, Pricebook2.Name, Pricebook2Id, IsActive, Product2.Name, Product2.Family, Product2.Type__c, Product2.IsActive, Product2.Description, UnitPrice, Product2.SKU__c, Disti_Transfer_Price__c, Product2.Product_Term_Years__c, Product2.SKU_Level_Discount__c FROM PriceBookEntry WHERE Pricebook2Id =: theBook.id AND Product2.Type__c =: 'Support'];
        Map<String,PricebookEntry> supportTypeMap = new Map<String, PricebookEntry>(); 
        // If previously selected products are now removed, we need to delete them
        if(forDeletion.size()>0)
            delete(forDeletion);
        for(Dynamic_Pricing__c dp : dplist){
            if(!supportPricingMap.containsKey(dp.Pricing_Type__c)){
                supportPricingMap.put(dp.Pricing_Type__c, dp.Pricing_Coefficient__c);
            }
        }
        for(PricebookEntry d : supportSkus){
            if(!supportTypeMap.containsKey(d.Product2.SKU__c)){
                supportTypeMap.put(d.Product2.SKU__c,d);
            }
        }
        AggregateResult[] groupedResults =[SELECT SUM(Quantity)sumQty, MAX(Service_Term_in_Months__c)svcTerm, SUM(UnitPrice)sprice FROM OpportunityLineItem WHERE Id in: shoppingCartProxy AND PriceBookEntry.Product2.Family =: 'MTP' AND PriceBookEntry.Product2.Type__c =: 'Subscription'];
        if(groupedResults.isempty()){
            ApexPages.addmessage(new ApexPages.message(ApexPages.severity.WARNING,'Please enter value'));
        }
        for(AggregateResult ar : groupedResults){
            supportQty = (Decimal)ar.get('sumQty');
            svcTerm = (Decimal)ar.get('svcTerm');
            sprice = (Decimal)ar.get('sprice');
        }       
        if(supportType!=null && supportType!='none'){
            shoppingCart.add(new opportunityLineItem(OpportunityId=theOpp.Id, PriceBookEntry=supportTypeMap.get(supportType), PriceBookEntryId=supportTypeMap.get(supportType).Id, Quantity=supportQty, Service_Term_in_Months__c = 12, UnitPrice=12)); //* supportPricingMap.get(supportType), Discount_off_list_manual__c = 0));
        }
    
        // Previously selected products may have new quantities and amounts, and we may have new products listed, so we use upsert here
        try{
            if(shoppingCart.size()>0)
                upsert(shoppingCart);
        }
        catch(Exception e){
            ApexPages.addMessages(e);
            return null;
        }  
           
        // After save return the user to the Opportunity
        return new PageReference('/' + ApexPages.currentPage().getParameters().get('Id'));
    }

And here is the entire controller:
public with sharing class opportunityProductEntryExtension {

    public Opportunity theOpp {get;set;} 
    public String searchString {get;set;}
    public String supportType {get;set;}
    public OpportunityLineItem[] shoppingCart {get;set;}
    public List<OpportunityLineItem> shoppingCartProxy {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 overLimit {get;set;}
    public Boolean multipleCurrencies {get; set;} 
    private Boolean forcePricebookSelection = false;
    private OpportunityLineItem[] forDeletion = new opportunityLineItem[]{};    
    private ApexPages.StandardController std;

    public opportunityProductEntryExtension(ApexPages.StandardController controller) {
        std=controller;
        // Need to know if org has multiple currencies enabled
        multipleCurrencies = UserInfo.isMultiCurrencyOrganization();

        // Get information about the Opportunity being worked on
        if(multipleCurrencies)
            theOpp = database.query('select Id, Pricebook2Id, Pricebook2.Name, CurrencyIsoCode from Opportunity where Id = \'' + controller.getRecord().Id + '\' limit 1');
        else
            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, Quantity, TotalPrice, UnitPrice, Description, List_Price__c, Disti_Transfer_Price2__c, Disti_Transfer_Price__c, PriceBookEntryId, PriceBookEntry.Name, PriceBookEntry.UnitPrice, PriceBookEntry.IsActive, PriceBookEntry.Product2Id, PriceBookEntry.Product2.Name, PriceBookEntry.Product2.Product_Term_Years__c, PriceBookEntry.PriceBook2Id, PriceBookEntry.Product2.SKU__c, PriceBookEntry.Product2.Family, PriceBookEntry.Product2.Type__c, Service_Term_in_Months__c, PriceBookEntry.Disti_Transfer_Price__c, Discount_off_list_manual__c from opportunityLineItem where OpportunityId=:theOpp.Id];
        shoppingCartProxy =[select Id, Quantity, TotalPrice, UnitPrice, Description, List_Price__c, Disti_Transfer_Price2__c, Disti_Transfer_Price__c, PriceBookEntryId, PriceBookEntry.Name, PriceBookEntry.UnitPrice, PriceBookEntry.IsActive, PriceBookEntry.Product2Id, PriceBookEntry.Product2.Name, PriceBookEntry.Product2.Product_Term_Years__c, PriceBookEntry.PriceBook2Id, PriceBookEntry.Product2.SKU__c, PriceBookEntry.Product2.Family, PriceBookEntry.Product2.Type__c, Service_Term_in_Months__c, PriceBookEntry.Disti_Transfer_Price__c, Discount_off_list_manual__c from OpportunityLineItem where OpportunityId=:std.getId()];
        // Check if Opp has a pricebook associated yet
        if(theOpp.Pricebook2Id == null){
            Pricebook2[] activepbs = [select Id, Name from Pricebook2 where isActive = true limit 2];
            if(activepbs.size() == 2){
                forcePricebookSelection = true;
                theBook = new Pricebook2();
            }
            else{
                theBook = activepbs[0];
            }
        }
        else{
            theBook = theOpp.Pricebook2;
        }
        
        if(!forcePricebookSelection)
            updateAvailableList();
    }
    
    // this is the 'action' method on the page
    public PageReference priceBookCheck(){
    
        // if the user needs to select a pricebook before we proceed we send them to standard pricebook selection screen
        if(forcePricebookSelection){        
            return changePricebook();
        }
        else{
        
            //if there is only one active pricebook we go with it and save the opp
            if(theOpp.pricebook2Id != theBook.Id){
                try{
                    theOpp.Pricebook2Id = theBook.Id;
                    update(theOpp);
                }
                catch(Exception e){
                    ApexPages.addMessages(e);
                }
            }
            
            return null;
        }
    }
       
    public String getChosenCurrency(){
    
        if(multipleCurrencies)
            return (String)theOpp.get('CurrencyIsoCode');
        else
            return '';
    }    

    public void updateAvailableList() {

        String supportstr = 'Support';
        // We dynamically build a query string and exclude items already in the shopping cart
        String qString = 'select Id, Name, Pricebook2.Name, Pricebook2Id, IsActive, Product2.Name, Product2.Family, Product2.Type__c, Product2.IsActive, Product2.Description, UnitPrice, Product2.SKU__c, Disti_Transfer_Price__c, Product2.Product_Term_Years__c, Product2.SKU_Level_Discount__c from PricebookEntry where IsActive=true AND Pricebook2Id = \'' + theBook.Id + '\'';
        if(multipleCurrencies)
            qstring += ' and CurrencyIsoCode = \'' + theOpp.get('currencyIsoCode') + '\'';
        
        // 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
        if(searchString!=null){
            qString+= ' and (Product2.Name like \'%' + searchString + '%\' or Product2.Description like \'%' + searchString + '%\')';
        }
        
        Set<Id> selectedEntries = new Set<Id>();
        for(opportunityLineItem d:shoppingCart){
            selectedEntries.add(d.PricebookEntryId);
        }
        
        if(selectedEntries.size()>0){
            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+= ' AND Product2.Type__c != \'' + supportstr + '\'';
        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)
        if(AvailableProducts.size()==101){
            AvailableProducts.remove(100);
            overLimit = true;
        }
        else{
            overLimit=false;
        }
    }

    public void addToShoppingCart(){
        list<Price_Book_Discounts__c> discounts = [SELECT Discount__c, Name
                                                   FROM Price_Book_Discounts__c 
                                                   WHERE Name =: theBook.Name];
        list<SKU_Discounts__c> skus = [SELECT Discount__c, SKU__c, Price_Book_Name__c
                                           FROM SKU_Discounts__c 
                                           WHERE Price_Book_Name__c =: theBook.Name];
        list<Product2> products = [SELECT Product_Term_Years__c, Name FROM Product2];                                                                           
        Map<String, Decimal> pbNameToDiscountMap =  new Map<String, Decimal>();
        Map<String, Decimal> skuToDiscountMap = new Map<String, Decimal>();
        Map<Decimal, Decimal> yearsToMonthsMap = new Map<Decimal, Decimal>();            
        // This function runs when a user hits "select" button next to a product
        for(Price_Book_Discounts__c discount : discounts){
            pbNameToDiscountMap.put(discount.Name, discount.Discount__c);
        }
        for(SKU_Discounts__c sku : skus){
            if (!SkuToDiscountMap.containsKey(sku.SKU__c)) {
                SkuToDiscountMap.put(sku.SKU__c, sku.Discount__c);
            } 
        }
        for(Product2 prod : products){
            if(!yearsToMonthsMap.containsKey(prod.Product_Term_Years__c)){
                if(prod.Product_Term_Years__c == null){
                    yearsToMonthsMap.put(prod.Product_Term_Years__c, 12);
                }
                if(prod.Product_Term_Years__c == 1){
                    yearsToMonthsMap.put(prod.Product_Term_Years__c, 12);
                }
                if(prod.Product_Term_Years__c == 3){
                    yearsToMonthsMap.put(prod.Product_Term_Years__c, 36);
                }
            }
        } 
        for(PricebookEntry d : AvailableProducts){             
            if((String)d.Id==toSelect && d.Product2.Type__c!='Non-Revenue' && d.Product2.Type__c!='Support'){
                if(d.Product2.SKU_Level_Discount__c == false){
                    shoppingCart.add(new opportunityLineItem(OpportunityId=theOpp.Id, PriceBookEntry=d, PriceBookEntryId=d.Id, Quantity=0, Service_Term_in_Months__c = yearsToMonthsMap.get(d.Product2.Product_Term_Years__c), UnitPrice=d.UnitPrice, Discount_off_list_manual__c = pbNameToDiscountMap.get(theBook.Name)));
                    break;                    
                }
                if(d.Product2.SKU_Level_Discount__c == true){
                    shoppingCart.add(new opportunityLineItem(OpportunityId=theOpp.Id, PriceBookEntry=d, PriceBookEntryId=d.Id, Quantity=0, Service_Term_in_Months__c = yearsToMonthsMap.get(d.Product2.Product_Term_Years__c), UnitPrice=d.UnitPrice, Discount_off_list_manual__c = SkuToDiscountMap.get(d.Product2.SKU__c)));
                    break;                    
                }                
            }     
            if((String)d.Id==toSelect && d.Product2.Type__c=='Non-Revenue' && d.Product2.Type__c=='Support'){
                if(d.Product2.Type__c=='Non-Revenue'){
                    shoppingCart.add(new opportunityLineItem(OpportunityId=theOpp.Id, PriceBookEntry=d, PriceBookEntryId=d.Id, Quantity=0, Service_Term_in_Months__c = 2, UnitPrice=d.UnitPrice, Discount_off_list_manual__c = 0));
                    break;
                }else{
                    shoppingCart.add(new opportunityLineItem(OpportunityId=theOpp.Id, PriceBookEntry=d, PriceBookEntryId=d.Id, Quantity=0, Service_Term_in_Months__c = yearsToMonthsMap.get(d.Product2.Product_Term_Years__c), UnitPrice=d.UnitPrice, Discount_off_list_manual__c = 0));
                    break;
                }       

            }            
        }
        
        updateAvailableList();    
    }

    public PageReference removeFromShoppingCart(){
    
        // This function runs when a user hits "remove" on an item in the "Selected Products" section
    
        Integer count = 0;
    
        for(opportunityLineItem d : shoppingCart){
            if((String)d.PriceBookEntryId==toUnselect){
            
                if(d.Id!=null)
                    forDeletion.add(d);
            
                shoppingCart.remove(count);
                break;
            }
            count++;
        }
        
        updateAvailableList();
        
        return null;
    } 
    
    public PageReference onSave(){
        Decimal supportQty;  
        Decimal svcTerm;  
        Decimal sprice;
        List<Dynamic_Pricing__c> dplist = [SELECT Pricing_Coefficient__c, Pricing_Type__c FROM Dynamic_Pricing__c];
        Map<string, decimal> supportPricingMap = new Map<string, decimal>();                                                                    
        List<PriceBookEntry> supportSkus = [SELECT Id, Name, Pricebook2.Name, Pricebook2Id, IsActive, Product2.Name, Product2.Family, Product2.Type__c, Product2.IsActive, Product2.Description, UnitPrice, Product2.SKU__c, Disti_Transfer_Price__c, Product2.Product_Term_Years__c, Product2.SKU_Level_Discount__c FROM PriceBookEntry WHERE Pricebook2Id =: theBook.id AND Product2.Type__c =: 'Support'];
        Map<String,PricebookEntry> supportTypeMap = new Map<String, PricebookEntry>(); 
        // If previously selected products are now removed, we need to delete them
        if(forDeletion.size()>0)
            delete(forDeletion);
        for(Dynamic_Pricing__c dp : dplist){
            if(!supportPricingMap.containsKey(dp.Pricing_Type__c)){
                supportPricingMap.put(dp.Pricing_Type__c, dp.Pricing_Coefficient__c);
            }
        }
        for(PricebookEntry d : supportSkus){
            if(!supportTypeMap.containsKey(d.Product2.SKU__c)){
                supportTypeMap.put(d.Product2.SKU__c,d);
            }
        }
        AggregateResult[] groupedResults =[SELECT SUM(Quantity)sumQty, MAX(Service_Term_in_Months__c)svcTerm, SUM(UnitPrice)sprice FROM OpportunityLineItem WHERE Id in: shoppingCartProxy AND PriceBookEntry.Product2.Family =: 'MTP' AND PriceBookEntry.Product2.Type__c =: 'Subscription'];
        if(groupedResults.isempty()){
            ApexPages.addmessage(new ApexPages.message(ApexPages.severity.WARNING,'Please enter value'));
        }
        for(AggregateResult ar : groupedResults){
            supportQty = (Decimal)ar.get('sumQty');
            svcTerm = (Decimal)ar.get('svcTerm');
            sprice = (Decimal)ar.get('sprice');
        }       
        if(supportType!=null && supportType!='none'){
            shoppingCart.add(new opportunityLineItem(OpportunityId=theOpp.Id, PriceBookEntry=supportTypeMap.get(supportType), PriceBookEntryId=supportTypeMap.get(supportType).Id, Quantity=supportQty, Service_Term_in_Months__c = 12, UnitPrice=12)); //* supportPricingMap.get(supportType), Discount_off_list_manual__c = 0));
        }
    
        // Previously selected products may have new quantities and amounts, and we may have new products listed, so we use upsert here
        try{
            if(shoppingCart.size()>0)
                upsert(shoppingCart);
        }
        catch(Exception e){
            ApexPages.addMessages(e);
            return null;
        }  
           
        // After save return the user to the Opportunity
        return new PageReference('/' + ApexPages.currentPage().getParameters().get('Id'));
    }
    
    public PageReference onCancel(){
 
        // If user hits cancel we commit no changes and return them to the Opportunity   
        return new PageReference('/' + ApexPages.currentPage().getParameters().get('Id'));
    }
    
    public PageReference changePricebook(){
    
        // This simply returns a PageReference to the standard Pricebook selection screen
        // Note that is uses retURL parameter to make sure the user is sent back after they choose
    
        PageReference ref = new PageReference('/oppitm/choosepricebook.jsp');
        ref.getParameters().put('id',theOpp.Id);
        ref.getParameters().put('retURL','/apex/opportunityProductEntry?id=' + theOpp.Id);
        
        return ref;
    }
}

 
I have a VF page that our sales people use to add and configure products to their Opportunities. I've added some Javascript to allow them to run pricing scenarios in real-time without having to save to the database. This is working perfectly.  In addition, we have a requirement that any time someone adds a "Support" product to an Opportunity, the Quantity is automatically calculated by totaling the Quantity of any Products from the Product Family called "MTP."  

To accomplish this, I added a method to my controller and used an apex:actionsupport tag to refresh the quantity when an MTP product Quantity is set or updated. It's almost working correctly, but it seems to be double-counting the quantity from the MTP Products, and I can't figure out why. Any suggestions would be very much appreciated. Cheers!

Screen Shot:
User-added image

Relevant Controller Method:
public PageReference calculateSupport(){
        Decimal supportQuantity;
        supportQuantity = 0;
        for(OpportunityLineItem soli : supportShoppingCart){
            if(supportQuantity!=null){
                supportQuantity+=soli.Quantity;
            }
        }
        for(OpportunityLineItem oli : shoppingCart){
            if(oli.PriceBookEntry.Product2.Type__c=='Support'){
                oli.Quantity=supportQuantity;
            }
        }
        return null;        
    }

Relevant VF Code:
<!--********** Quantity **********-->
                    <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.Quantity.Label}">
                        <apex:inputField value="{!s.Quantity}" id="quant" style="width:70px" required="true" rendered="{!IF(s.PriceBookEntry.Product2.Type__c == 'Support',False, True)}">
                            <apex:actionSupport event="onchange" reRender="tot"/>
                            <apex:actionSupport event="onchange" action="{!calculateSupport}"/>
                        </apex:inputField>
                        <apex:outputText id="quantreadonly" value="{!s.Quantity}" rendered="{!IF(s.PriceBookEntry.Product2.Type__c == 'Support',True, False)}"/>
                    </apex:column>

Entire Controller:
public with sharing class opportunityProductEntryExtension {

    public Opportunity theOpp {get;set;} 
    public String searchString {get;set;}
    public OpportunityLineItem[] shoppingCart {get;set;}
    public OpportunityLineItem[] supportShoppingCart {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 overLimit {get;set;}
    public Boolean multipleCurrencies {get; set;} 
    private Boolean forcePricebookSelection = false;
    
    private opportunityLineItem[] forDeletion = new opportunityLineItem[]{};


    public opportunityProductEntryExtension(ApexPages.StandardController controller) {

        // Need to know if org has multiple currencies enabled
        multipleCurrencies = UserInfo.isMultiCurrencyOrganization();

        // Get information about the Opportunity being worked on
        if(multipleCurrencies)
            theOpp = database.query('select Id, Pricebook2Id, Pricebook2.Name, CurrencyIsoCode from Opportunity where Id = \'' + controller.getRecord().Id + '\' limit 1');
        else
            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, Quantity, TotalPrice, UnitPrice, Description, List_Price__c, Disti_Transfer_Price2__c, Disti_Transfer_Price__c, PriceBookEntryId, PriceBookEntry.Name, PriceBookEntry.UnitPrice, PriceBookEntry.IsActive, PriceBookEntry.Product2Id, PriceBookEntry.Product2.Name, PriceBookEntry.Product2.Product_Term_Years__c, PriceBookEntry.PriceBook2Id, PriceBookEntry.Product2.SKU__c, PriceBookEntry.Product2.Family, PriceBookEntry.Product2.Type__c, Service_Term_in_Months__c, PriceBookEntry.Disti_Transfer_Price__c, Discount_off_list_manual__c from opportunityLineItem where OpportunityId=:theOpp.Id];
        supportShoppingCart = [select Id, Quantity, TotalPrice, UnitPrice, Description, List_Price__c, Disti_Transfer_Price2__c, Disti_Transfer_Price__c, PriceBookEntryId, PriceBookEntry.Name, PriceBookEntry.UnitPrice, PriceBookEntry.IsActive, PriceBookEntry.Product2Id, PriceBookEntry.Product2.Name, PriceBookEntry.Product2.Product_Term_Years__c, PriceBookEntry.PriceBook2Id, PriceBookEntry.Product2.SKU__c, PriceBookEntry.Product2.Family, PriceBookEntry.Product2.Type__c, Service_Term_in_Months__c, PriceBookEntry.Disti_Transfer_Price__c, Discount_off_list_manual__c 
                                from opportunityLineItem 
                                where OpportunityId=:theOpp.Id AND PriceBookEntry.Product2.Family=:'MTP' AND PricebookEntry.Product2.Type__c=:'Subscription'];        
        // Check if Opp has a pricebook associated yet
        if(theOpp.Pricebook2Id == null){
            Pricebook2[] activepbs = [select Id, Name from Pricebook2 where isActive = true limit 2];
            if(activepbs.size() == 2){
                forcePricebookSelection = true;
                theBook = new Pricebook2();
            }
            else{
                theBook = activepbs[0];
            }
        }
        else{
            theBook = theOpp.Pricebook2;
        }
        
        if(!forcePricebookSelection)
            updateAvailableList();
    }
    
    // this is the 'action' method on the page
    public PageReference priceBookCheck(){
    
        // if the user needs to select a pricebook before we proceed we send them to standard pricebook selection screen
        if(forcePricebookSelection){        
            return changePricebook();
        }
        else{
        
            //if there is only one active pricebook we go with it and save the opp
            if(theOpp.pricebook2Id != theBook.Id){
                try{
                    theOpp.Pricebook2Id = theBook.Id;
                    update(theOpp);
                }
                catch(Exception e){
                    ApexPages.addMessages(e);
                }
            }
            
            return null;
        }
    }
       
    public String getChosenCurrency(){
    
        if(multipleCurrencies)
            return (String)theOpp.get('CurrencyIsoCode');
        else
            return '';
    }

    public void updateAvailableList() {
    
        // We dynamically build a query string and exclude items already in the shopping cart
        String qString = 'select Id, Name, Pricebook2.Name, Pricebook2Id, IsActive, Product2.Name, Product2.Family, Product2.Type__c, Product2.IsActive, Product2.Description, UnitPrice, Product2.SKU__c, Disti_Transfer_Price__c, Product2.Product_Term_Years__c, Product2.SKU_Level_Discount__c from PricebookEntry where IsActive=true and Pricebook2Id = \'' + theBook.Id + '\'';
        if(multipleCurrencies)
            qstring += ' and CurrencyIsoCode = \'' + theOpp.get('currencyIsoCode') + '\'';
        
        // 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
        if(searchString!=null){
            qString+= ' and (Product2.Name like \'%' + searchString + '%\' or Product2.Description like \'%' + searchString + '%\')';
        }
        
        Set<Id> selectedEntries = new Set<Id>();
        for(opportunityLineItem d:shoppingCart){
            selectedEntries.add(d.PricebookEntryId);
        }
        
        if(selectedEntries.size()>0){
            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)
        if(AvailableProducts.size()==101){
            AvailableProducts.remove(100);
            overLimit = true;
        }
        else{
            overLimit=false;
        }
    }
    
    public void addToShoppingCart(){
    
        // This function runs when a user hits "select" button next to a product
        list<Price_Book_Discounts__c> discounts = [SELECT Discount__c, Name
                                                   FROM Price_Book_Discounts__c 
                                                   WHERE Name =: theBook.Name];
        list<SKU_Discounts__c> skus = [SELECT Discount__c, SKU__c, Price_Book_Name__c
                                           FROM SKU_Discounts__c 
                                           WHERE Price_Book_Name__c =: theBook.Name];
        list<Product2> products = [SELECT Product_Term_Years__c, Name FROM Product2];                                                                           
        Map<String, Decimal> pbNameToDiscountMap =  new Map<String, Decimal>();
		Map<String, Decimal> skuToDiscountMap = new Map<String, Decimal>();
        Map<Decimal, Decimal> yearsToMonthsMap = new Map<Decimal, Decimal>();
        for(Price_Book_Discounts__c discount : discounts){
            pbNameToDiscountMap.put(discount.Name, discount.Discount__c);
        }
        for(SKU_Discounts__c sku : skus){
            if (!SkuToDiscountMap.containsKey(sku.SKU__c)) {
                SkuToDiscountMap.put(sku.SKU__c, sku.Discount__c);
            } 
        }
        for(Product2 prod : products){
            if(!yearsToMonthsMap.containsKey(prod.Product_Term_Years__c)){
                if(prod.Product_Term_Years__c == null){
                    yearsToMonthsMap.put(prod.Product_Term_Years__c, 12);
                }
                if(prod.Product_Term_Years__c == 1){
                    yearsToMonthsMap.put(prod.Product_Term_Years__c, 12);
                }
                if(prod.Product_Term_Years__c == 3){
                    yearsToMonthsMap.put(prod.Product_Term_Years__c, 36);
                }
            }
        } 
        for(PricebookEntry d : AvailableProducts){             
            if((String)d.Id==toSelect && d.Product2.Name.contains('Support')){
                shoppingCart.add(new opportunityLineItem(OpportunityId=theOpp.Id, PriceBookEntry=d, PriceBookEntryId=d.Id, Quantity=0, Service_Term_in_Months__c = yearsToMonthsMap.get(d.Product2.Product_Term_Years__c), UnitPrice=d.UnitPrice, Discount_off_list_manual__c = 12));
                break;
            }
            if((String)d.Id==toSelect && d.UnitPrice<>0 && !d.Product2.Name.contains('Support')){
                if(d.Product2.SKU_Level_Discount__c == false){
                    shoppingCart.add(new opportunityLineItem(OpportunityId=theOpp.Id, PriceBookEntry=d, PriceBookEntryId=d.Id, Quantity=0, Service_Term_in_Months__c = yearsToMonthsMap.get(d.Product2.Product_Term_Years__c), UnitPrice=d.UnitPrice, Discount_off_list_manual__c = pbNameToDiscountMap.get(theBook.Name)));
                    break;                    
                }
                if(d.Product2.SKU_Level_Discount__c == true){
                    shoppingCart.add(new opportunityLineItem(OpportunityId=theOpp.Id, PriceBookEntry=d, PriceBookEntryId=d.Id, Quantity=0, Service_Term_in_Months__c = yearsToMonthsMap.get(d.Product2.Product_Term_Years__c), UnitPrice=d.UnitPrice, Discount_off_list_manual__c = SkuToDiscountMap.get(d.Product2.SKU__c)));
                    break;                    
                }                
            }     
            if((String)d.Id==toSelect && d.UnitPrice==0){
                if(d.Product2.Name.contains('Evaluation')){
                    shoppingCart.add(new opportunityLineItem(OpportunityId=theOpp.Id, PriceBookEntry=d, PriceBookEntryId=d.Id, Quantity=0, Service_Term_in_Months__c = 2, UnitPrice=d.UnitPrice, Discount_off_list_manual__c = 0));
                    break;
                }else{
                    shoppingCart.add(new opportunityLineItem(OpportunityId=theOpp.Id, PriceBookEntry=d, PriceBookEntryId=d.Id, Quantity=0, Service_Term_in_Months__c = yearsToMonthsMap.get(d.Product2.Product_Term_Years__c), UnitPrice=d.UnitPrice, Discount_off_list_manual__c = 0));
                    break;
                }
            }            
        }
        for(OpportunityLineItem soli : shoppingCart){
            if(soli.PriceBookEntry.Product2.Type__c=='Subscription' && soli.PriceBookEntry.Product2.Family=='MTP'){       
                supportShoppingCart.add(soli);
            }
        }
        updateAvailableList();    
    }

    public PageReference calculateSupport(){
        Decimal supportQuantity;
        supportQuantity = 0;
        for(OpportunityLineItem soli : supportShoppingCart){
            if(supportQuantity!=null){
                supportQuantity+=soli.Quantity;
            }
        }
        for(OpportunityLineItem oli : shoppingCart){
            if(oli.PriceBookEntry.Product2.Type__c=='Support'){
                oli.Quantity=supportQuantity;
            }
        }
        return null;        
    }

    public PageReference removeFromShoppingCart(){
    
        // This function runs when a user hits "remove" on an item in the "Selected Products" section
    
        Integer count = 0;
    
        for(opportunityLineItem d : shoppingCart){
            if((String)d.PriceBookEntryId==toUnselect){
            
                if(d.Id!=null)
                    forDeletion.add(d);
            
                shoppingCart.remove(count);
                break;
            }
            count++;
        }
        
        updateAvailableList();
        
        return null;
    }
    
    public PageReference onSave(){
    
        // If previously selected products are now removed, we need to delete them
        if(forDeletion.size()>0)
            delete(forDeletion);
    
        // Previously selected products may have new quantities and amounts, and we may have new products listed, so we use upsert here
        try{
            if(shoppingCart.size()>0)
                upsert(shoppingCart);
        }
        catch(Exception e){
            ApexPages.addMessages(e);
            return null;
        }  
           
        // After save return the user to the Opportunity
        return new PageReference('/' + ApexPages.currentPage().getParameters().get('Id'));
    }
    
    public PageReference onCancel(){
 
        // If user hits cancel we commit no changes and return them to the Opportunity   
        return new PageReference('/' + ApexPages.currentPage().getParameters().get('Id'));
    }
    
    public PageReference changePricebook(){
    
        // This simply returns a PageReference to the standard Pricebook selection screen
        // Note that is uses retURL parameter to make sure the user is sent back after they choose
    
        PageReference ref = new PageReference('/oppitm/choosepricebook.jsp');
        ref.getParameters().put('id',theOpp.Id);
        ref.getParameters().put('retURL','/apex/opportunityProductEntry?id=' + theOpp.Id);
        
        return ref;
    }
}

Hey folks, I have a somewhat complicated use-case I'm trying to solve.  I have a visualforce page that we use to configure products. What I'm trying to do is derive the quantity of one particular type of product based on the quantity or quantities of another type of products and I want to do this within the browser and then insert the derived value into the database on Save. Specifically we have a product called "MTP" and another generic "Support" product.  Whenever MTP product quantities are added or updated to the product "shopping-cart" visualforce page, I want ONLY the total of all MTP line-items to be automatically populated in the quantity field of the support product. See my example below:

User-added image
Here's my current code:
Controller:

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 overLimit {get;set;}
    public Boolean multipleCurrencies {get; set;} 
    private Boolean forcePricebookSelection = false;
    
    private opportunityLineItem[] forDeletion = new opportunityLineItem[]{};


    public opportunityProductEntryExtension(ApexPages.StandardController controller) {

        // Need to know if org has multiple currencies enabled
        multipleCurrencies = UserInfo.isMultiCurrencyOrganization();

        // Get information about the Opportunity being worked on
        if(multipleCurrencies)
            theOpp = database.query('select Id, Pricebook2Id, Pricebook2.Name, CurrencyIsoCode from Opportunity where Id = \'' + controller.getRecord().Id + '\' limit 1');
        else
            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, Quantity, TotalPrice, UnitPrice, Description, List_Price__c, Disti_Transfer_Price2__c, Disti_Transfer_Price__c, PriceBookEntryId, PriceBookEntry.Name, PriceBookEntry.UnitPrice, PriceBookEntry.IsActive, PriceBookEntry.Product2Id, PriceBookEntry.Product2.Name, PriceBookEntry.Product2.Product_Term_Years__c, PriceBookEntry.PriceBook2Id, PriceBookEntry.Product2.SKU__c, PriceBookEntry.Product2.Family, PriceBookEntry.Product2.Type__c, Service_Term_in_Months__c, PriceBookEntry.Disti_Transfer_Price__c, Discount_off_list_manual__c from opportunityLineItem where OpportunityId=:theOpp.Id];

        // Check if Opp has a pricebook associated yet
        if(theOpp.Pricebook2Id == null){
            Pricebook2[] activepbs = [select Id, Name from Pricebook2 where isActive = true limit 2];
            if(activepbs.size() == 2){
                forcePricebookSelection = true;
                theBook = new Pricebook2();
            }
            else{
                theBook = activepbs[0];
            }
        }
        else{
            theBook = theOpp.Pricebook2;
        }
        
        if(!forcePricebookSelection)
            updateAvailableList();
    }
    
    // this is the 'action' method on the page
    public PageReference priceBookCheck(){
    
        // if the user needs to select a pricebook before we proceed we send them to standard pricebook selection screen
        if(forcePricebookSelection){        
            return changePricebook();
        }
        else{
        
            //if there is only one active pricebook we go with it and save the opp
            if(theOpp.pricebook2Id != theBook.Id){
                try{
                    theOpp.Pricebook2Id = theBook.Id;
                    update(theOpp);
                }
                catch(Exception e){
                    ApexPages.addMessages(e);
                }
            }
            
            return null;
        }
    }
       
    public String getChosenCurrency(){
    
        if(multipleCurrencies)
            return (String)theOpp.get('CurrencyIsoCode');
        else
            return '';
    }

    public void updateAvailableList() {
    
        // We dynamically build a query string and exclude items already in the shopping cart
        String qString = 'select Id, Name, Pricebook2.Name, Pricebook2Id, IsActive, Product2.Name, Product2.Family, Product2.Type__c, Product2.IsActive, Product2.Description, UnitPrice, Product2.SKU__c, Disti_Transfer_Price__c, Product2.Product_Term_Years__c, Product2.SKU_Level_Discount__c from PricebookEntry where IsActive=true and Pricebook2Id = \'' + theBook.Id + '\'';
        if(multipleCurrencies)
            qstring += ' and CurrencyIsoCode = \'' + theOpp.get('currencyIsoCode') + '\'';
        
        // 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
        if(searchString!=null){
            qString+= ' and (Product2.Name like \'%' + searchString + '%\' or Product2.Description like \'%' + searchString + '%\')';
        }
        
        Set<Id> selectedEntries = new Set<Id>();
        for(opportunityLineItem d:shoppingCart){
            selectedEntries.add(d.PricebookEntryId);
        }
        
        if(selectedEntries.size()>0){
            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)
        if(AvailableProducts.size()==101){
            AvailableProducts.remove(100);
            overLimit = true;
        }
        else{
            overLimit=false;
        }
    }
    
    public void addToShoppingCart(){
    
        // This function runs when a user hits "select" button next to a product
        list<Price_Book_Discounts__c> discounts = [SELECT Discount__c, Name
                                                   FROM Price_Book_Discounts__c 
                                                   WHERE Name =: theBook.Name];
        list<SKU_Discounts__c> skus = [SELECT Discount__c, SKU__c, Price_Book_Name__c
                                           FROM SKU_Discounts__c 
                                           WHERE Price_Book_Name__c =: theBook.Name];                
        Map<String, Decimal> pbNameToDiscountMap =  new Map<String, Decimal>();
		Map<String, Decimal> SkuToDiscountMap = new Map<String, Decimal>();
        for(Price_Book_Discounts__c discount : discounts){
            pbNameToDiscountMap.put(discount.Name, discount.Discount__c);
        }
        for(SKU_Discounts__c sku : skus){
            if (!SkuToDiscountMap.containsKey(sku.SKU__c)) {
                SkuToDiscountMap.put(sku.SKU__c, sku.Discount__c);
            } 
        } 
        for(PricebookEntry d : AvailableProducts){            
            if((String)d.Id==toSelect && d.Product2.Type__c == 'Support'){
                shoppingCart.add(new opportunityLineItem(OpportunityId = theOpp.Id, 
                                                        PriceBookEntry = d, 
                                                        PriceBookEntryId = d.Id
                                                        ));
                break;
            }
            if((String)d.Id==toSelect && d.Product2.Type__c == 'Non-Revenue'){
                shoppingCart.add(new opportunityLineItem(OpportunityId = theOpp.Id, 
                                                        PriceBookEntry = d, 
                                                        PriceBookEntryId = d.Id,
                                                        Service_Term_in_Months__c = 2,
                                                        Quantity = 100
                                                        ));
                break;
            }
            if((String)d.Id==toSelect && d.Product2.Type__c == 'Subscription'){
                if(SkuToDiscountMap.get(d.Product2.SKU__c)!=null){
                    shoppingCart.add(new opportunityLineItem(OpportunityId=theOpp.Id, PriceBookEntry=d, PriceBookEntryId=d.Id, UnitPrice=d.Disti_Transfer_Price__c, Disti_Transfer_Price2__c = d.Disti_Transfer_Price__c, List_Price__c = d.UnitPrice, Discount_off_list_manual__c = SkuToDiscountMap.get(d.Product2.SKU__c)));
                    break;
                }
                if(SkuToDiscountMap.get(d.Product2.SKU__c)==null){
                    shoppingCart.add(new opportunityLineItem(OpportunityId=theOpp.Id, PriceBookEntry=d, PriceBookEntryId=d.Id, UnitPrice=d.Disti_Transfer_Price__c, Disti_Transfer_Price2__c = d.Disti_Transfer_Price__c, List_Price__c = d.UnitPrice, Discount_off_list_manual__c = pbNameToDiscountMap.get(theBook.Name)));
                    break;
                }
            }            
        }
        
        updateAvailableList();  
    }  

    public PageReference calculateSupport(){
        List<Id> parents = new list<Id>();
        for(opportunityLineItem d : shoppingCart){
            parents.add(d.OpportunityId);
        }
        List<OpportunityLineItem> olis = [SELECT Quantity, PriceBookEntry.Product2.Family FROM OpportunityLineItem WHERE Id in: parents AND PriceBookEntry.Product2.Family =: 'MTP'];
        double suppQuant = 0;    
        for(OpportunityLineItem mtpOli : olis){
            suppQuant += mtpOli.Quantity;
        }             
        for(opportunityLineItem d : shoppingCart){
            if(d.PriceBookEntry.Product2.Type__c == 'Support'){
                d.Quantity = suppQuant;
            }else{
                d.Quantity = d.Quantity;
            }
        }
        
        return null;
    }

    public PageReference calculateSalesPrice(){
        
        for(opportunityLineItem d : shoppingCart){
            decimal price = d.PriceBookEntry.UnitPrice - (d.PriceBookEntry.UnitPrice * (d.Discount_off_list_manual__c/100));
            d.UnitPrice = price.setscale(2);
        }
        
        return null;
    }    

    public PageReference calculateDiscount(){
        
        for(opportunityLineItem d : shoppingCart){
            decimal discount = ((d.PriceBookEntry.UnitPrice - d.UnitPrice)/d.PriceBookEntry.UnitPrice)*100;            
            d.Discount_off_list_manual__c = discount.setscale(2);
        }
        
        return null;
    }        

    public PageReference removeFromShoppingCart(){
    
        // This function runs when a user hits "remove" on an item in the "Selected Products" section
    
        Integer count = 0;
    
        for(opportunityLineItem d : shoppingCart){
            if((String)d.PriceBookEntryId==toUnselect){
            
                if(d.Id!=null)
                    forDeletion.add(d);
            
                shoppingCart.remove(count);
                break;
            }
            count++;
        }
        
        updateAvailableList();
        
        return null;
    }
    
    public PageReference onSave(){
    
        // If previously selected products are now removed, we need to delete them
        if(forDeletion.size()>0)
            delete(forDeletion);
    
        // Previously selected products may have new quantities and amounts, and we may have new products listed, so we use upsert here
        try{
            if(shoppingCart.size()>0)
                upsert(shoppingCart);
        }
        catch(Exception e){
            ApexPages.addMessages(e);
            return null;
        }  
           
        // After save return the user to the Opportunity
        return new PageReference('/' + ApexPages.currentPage().getParameters().get('Id'));
    }
    
    public PageReference onCancel(){
 
        // If user hits cancel we commit no changes and return them to the Opportunity   
        return new PageReference('/' + ApexPages.currentPage().getParameters().get('Id'));
    }
    
    public PageReference changePricebook(){
    
        // This simply returns a PageReference to the standard Pricebook selection screen
        // Note that is uses retURL parameter to make sure the user is sent back after they choose
    
        PageReference ref = new PageReference('/oppitm/choosepricebook.jsp');
        ref.getParameters().put('id',theOpp.Id);
        ref.getParameters().put('retURL','/apex/opportunityProductEntry?id=' + theOpp.Id);
        
        return ref;
    }
}
Visualforce Page:
<apex:page standardController="Opportunity" extensions="opportunityProductEntryExtension" action="{!priceBookCheck}" >

    <apex:sectionHeader Title="Manage {!$ObjectType.Product2.LabelPlural}" subtitle="{!opportunity.Name}"/>
    <apex:messages style="color:red"/>

    <style>
        .search{
            font-size:14pt;
            margin-right: 20px;    
        }
        .fyi{
            color:red;
            font-style:italic;
        }
        .label{
            margin-right:10px;
            font-weight:bold;
            vertical-align: text-bottom;
        }
       .pbTitle {
            white-space: nowrap;
            
        }            

    </style>
    
    <script type='text/javascript'>
    
        // This script assists the search bar functionality
        // It will execute a search only after the user has stopped typing for more than 1 second
        // To raise the time between when the user stops typing and the search, edit the following variable:
        
        var waitTime = 0.1;
        
    
        var countDown = waitTime+1;
        var started = false;
        
        function resetTimer(){
        
            countDown=waitTime+0.1;
            
            if(started==false){
                started=true;
                runCountDown();
            }
        }
        
        function runCountDown(){
        
            countDown--;
            
            if(countDown<=0){
                fetchResults();
                started=false;
            }
            else{
                window.setTimeout(runCountDown,1000);
            }
        }    
    </script>
   
  
    <apex:form >
        <div id="InternalDiv" styleClass="pbTitle" style="width:600px; float:right; margin-top:-60px; font-size:9px;">     

         </div>
             <apex:outputPanel id="mainBody">
                <div id="pbName" styleClass="pbName" style="margin-top:0px;">
                    <apex:outputLabel styleClass="label">PriceBook: </apex:outputLabel>
                    <apex:outputText value="{!theBook.Name}"/>&nbsp;
                    <apex:commandLink action="{!changePricebook}" value="change" immediate="true"/>
                </div>                  
                    <br/>
                    <!-- not everyone is using multi-currency, so this section may or may not show -->
                    <apex:outputPanel rendered="{!multipleCurrencies}">
                        <apex:outputLabel styleClass="label">Currency: </apex:outputLabel>
                        <apex:outputText value="{!chosenCurrency}"/>
                        <br/>
                    </apex:outputPanel>
                <br/>
         
            
<!-- this is the upper table... a.k.a. the "Shopping Cart"-->

            <!-- notice we use a lot of $ObjectType merge fields... I did that because if you have changed the labels of fields or objects it will reflect your own lingo -->
            <apex:pageBlock title="Selected {!$ObjectType.Product2.LabelPlural}" id="selected">
                       
                <apex:pageblockTable value="{!shoppingCart}" var="s">
                    
                    <apex:column >
                        <apex:commandLink value="Remove" action="{!removeFromShoppingCart}" reRender="selected,searchResults" immediate="true">
                            <!-- this param is how we send an argument to the controller, so it knows which row we clicked 'remove' on -->
                            <apex:param value="{!s.PriceBookEntryId}" assignTo="{!toUnselect}" name="toUnselect"/>
                        </apex:commandLink>
                    </apex:column>

                    <!--********** Product Name **********-->
                    <apex:column headerValue="{!$ObjectType.Product2.LabelPlural}" value="{!s.PriceBookEntry.Product2.Name}"/>

                    <!--********** Product SKU **********-->
                    <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.SKU__c.Label}" value="{!s.PriceBookEntry.Product2.SKU__c}"/> 

                    <!--********** Annual Product Term **********-->
                    <apex:column headerValue="Annual Term" id="pt" rendered="false" value="{!s.PriceBookEntry.Product2.Product_Term_Years__c}"/>                         
                    
                    <!--********** Quantity **********-->
                    <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.Quantity.Label}">
                        <apex:inputField value="{!s.Quantity}" id="quant" style="width:70px" required="true" rendered="{!IF(s.PriceBookEntry.Product2.Type__c == 'Support', false, true)}">
                            <apex:actionSupport event="onkeyup" reRender="tot"/>
                            <apex:actionSupport event="onchange" action="{!calculateSupport}"/>
                        </apex:inputField>
                        <apex:outputText id="quants" value="{0, number, ###,###,###,##0.00}" rendered="{!IF(s.PriceBookEntry.Product2.Type__c == 'Support', true, false)}">
                            <apex:param value="{!s.Quantity}"/>
                        </apex:outputText> 
                    </apex:column>
                  

                    <!--********** Service Term in Months **********-->
                    <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.Service_Term_in_Months__c.Label}">
                        <apex:inputField value="{!s.Service_Term_in_Months__c}" id="svc" style="width:70px" required="true" rendered="{!IF(s.PriceBookEntry.Product2.Type__c == 'Support', false, true)}">
                            <apex:actionSupport event="onkeyup" reRender="tot"/>
                        </apex:inputField>
                        <apex:outputText id="svcs" value="${0, number, ###,###,###,##0.00}" rendered="{!IF(s.PriceBookEntry.Product2.Type__c == 'Support', true, false)}">
                            <apex:param value="{!s.PriceBookEntry.UnitPrice}"/>
                        </apex:outputText> 
                    </apex:column>                                        

                    <!--********** Discount (Manual) **********-->
                    <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.Discount_off_list_manual__c.Label}">
                        <apex:inputField value="{!s.Discount_off_list_manual__c}" id="disc" style="width:70px" required="True" rendered="{!IF(s.PriceBookEntry.Product2.Type__c == 'Support', false, true)}">
                            <apex:actionSupport event="onchange" reRender="tot"/>
                             <apex:actionSupport event="onkeyup" action="{!calculateSalesPrice}"/>
                        </apex:inputField>
                        <apex:outputText id="discs" value="${0, number, ###,###,###,##0.00}" rendered="{!IF(s.PriceBookEntry.Product2.Type__c == 'Support', true, false)}">
                            <apex:param value="{!s.PriceBookEntry.UnitPrice}"/>
                        </apex:outputText> 
                    </apex:column>                    
                    
                    <!--********** Sales Price **********-->
                    <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.UnitPrice.Label}">
                        <apex:inputField value="{!s.UnitPrice}" id="sp" style="width:70px" required="true" rendered="{!IF(s.PriceBookEntry.Product2.Type__c == 'Support', false, true)}">
                            <apex:actionSupport event="onchange" reRender="tot"/>
                            <apex:actionSupport event="onkeyup" action="{!calculateDiscount}"/>
                        </apex:inputField>                    
                        <apex:outputText id="sps" value="${0, number, ###,###,###,##0.00}" rendered="{!IF(s.PriceBookEntry.Product2.Type__c == 'Support', true, false)}">
                            <apex:param value="{!s.PriceBookEntry.UnitPrice}"/>
                        </apex:outputText> 
                    </apex:column>                    

                    <!--********** Disti Transfer Price (Custom) **********-->
                    <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.Disti_Transfer_Price2__c.Label}">
                        <apex:outputText id="dpc" value="${0, number, ###,###,###,##0.00}">
                            <apex:param value="{!s.PriceBookEntry.Disti_Transfer_Price__c}"/>
                        </apex:outputText> 
                    </apex:column>

                    <!--********** List Price (Custom) **********-->
                    <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.List_Price__c.Label}">
                        <apex:outputText id="lpc" value="${0, number, ###,###,###,##0.00}">
                            <apex:param value="{!s.PriceBookEntry.UnitPrice}"/>
                        </apex:outputText> 
                    </apex:column>

                    <!--********** Disti Transfer Price (Standard) Hidden **********-->
                    <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.Disti_Transfer_Price__c.Label}" value="{!s.PriceBookEntry.Disti_Transfer_Price__c}" id="dp" rendered="false"/>

                    <!--********** List Price (Standard) Hidden **********-->
                    <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.ListPrice.Label}" id="lp" value="{!s.PriceBookEntry.UnitPrice}" rendered="false"/>
                    
                    <!--********** Total Price (display only field) **********-->
                    <apex:column headerValue="Total Price">
                        <apex:outputText id="tot" value="${0, number, ###,###,###,##0.00}">
                            <apex:param value="{!IF(s.PriceBookEntry.Product2.Product_Term_Years__c != null,(s.Quantity * s.Service_Term_in_Months__c * s.UnitPrice)/(s.PriceBookEntry.Product2.Product_Term_Years__c*12),(s.Quantity * s.UnitPrice)) }"/>
                        </apex:outputText> 
                    </apex:column>                                   
                    
                </apex:pageblockTable>
            
            
                <apex:pageBlockButtons >
                    <apex:commandButton action="{!onSave}" value="Save"/>
                    <apex:commandButton action="{!onCancel}" value="Cancel" immediate="true"/>
                </apex:pageBlockButtons>
            
            </apex:pageBlock>
    
<!-- this is the lower table: search bar and search results -->
    
            <apex:pageBlock >
            
                <apex:outputPanel styleClass="search">
                    Search for {!$ObjectType.Product2.LabelPlural}:
                </apex:outputPanel>

                <apex:actionRegion renderRegionOnly="false" immediate="true">
                
                    <apex:actionFunction name="fetchResults" action="{!updateAvailableList}" reRender="searchResults" status="searchStatus"/>
                    
                    <!-- here we invoke the scripting to get out fancy 'no button' search bar to work -->
                    <apex:inputText value="{!searchString}" onkeydown="if(event.keyCode==13){this.blur();}else{resetTimer();}" style="width:300px"/>
                    &nbsp;&nbsp;
                    <i>
                        <!-- actionStatus component makes it easy to let the user know when a search is underway -->
                        <apex:actionStatus id="searchStatus" startText="searching..." stopText=" "/>
                    </i>
                    
                </apex:actionRegion>
            
                <br/>
                <br/>
            
                <apex:outputPanel id="searchResults">
                
                    <apex:pageBlockTable value="{!AvailableProducts}" var="a">
                    
                        <apex:column headerValue="{!$ObjectType.Product2.Fields.Name.Label}" value="{!a.Product2.Name}" />
                        
                        <apex:column headerValue="{!$ObjectType.Product2.Fields.SKU__c.Label}" value="{!a.Product2.SKU__c}"/>
                        
                        <apex:column headerValue="{!$ObjectType.Product2.Fields.Description.Label}" value="{!a.Product2.Description}"/>
                        
                        <apex:column >
                            <!-- command button in a column... neato -->
                            <apex:commandButton value="Select" action="{!addToShoppingCart}" reRender="selected,searchResults" immediate="true">
                                <!-- again we use apex:param to be able to tell the controller which row we are working with -->
                                <apex:param value="{!a.Id}" assignTo="{!toSelect}" name="toSelect"/>
                            </apex:commandButton>
                        </apex:column>
                        
                    </apex:pageBlockTable>
                    
                    <!-- We put up a warning if results exceed 100 rows -->
                    <apex:outputPanel styleClass="fyi" rendered="{!overLimit}">
                        <br/>
                        Your search returned over 100 results, use a more specific search string if you do not see the desired {!$ObjectType.Product2.Label}.
                        <br/>
                    </apex:outputPanel>
                    
                </apex:outputPanel>
            
            </apex:pageBlock>
            
        </apex:outputPanel>

    </apex:form>

</apex:page>

 
Hey folks, I know I'm gonna feel stupid when I get the answer here, but I just can't seem to get this right.  I'm trying to create a visualforce page that populates other visualforce pages within an iframe based on a picklist selection, btu I can't seem to figure out how to pass the selected picklist value into the src parameter of my iframe component. I've deleted a bunch of the broken code that hasn't worked so the code is pretty simple at this point.

Can someone help me sort it out?  Thanks!

Controller:
public class domoDashboardController {
    
    public List<String> pagename {
        get {
            if (pagename == null) {
                pagename = new List<String>();
                list<ApexPage> pages = [SELECT Name FROM ApexPage WHERE Name != 'domoDashBoardViewer' AND Name LIKE 'DOMO_%' ORDER BY Name ASC];
                for (ApexPage page : pages){
        			pagename.add(page.Name);
        		}
      		}
      		return pagename;          
    	}
    	set;
  	}
    
}

VF Page:
<apex:page controller="domoDashboardController">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <apex:pageBlock title="DOMO Dashboard Viewer" mode="edit">
        
        <apex:form>
            <table width="100%" border="0">
                <tr>
                    <td style="font-weight:bold; padding-left: 5px; padding-top:10px; width: 125px;">                    
                        Select Dashboard:
                    </td>                
                    <td style="font-weight:bold; padding-top:8px;">
    					<select id="pagename">
                        	<option value=""></option>
                            <apex:repeat value="{!pagename}" var="pag">
                            	<option value="{!pag}">{!pag}</option>
                            </apex:repeat>
                        </select>     
                    </td>     
                </tr>
            </table>
            <apex:pageBlock>    
                <table width="100%" border="0">
                    <tr>
                        <apex:page id="thePage">
							<apex:iframe src="" scrolling="true" id="theIframe"/>
                        </apex:page>
                    </tr>
                </table>
            </apex:pageBlock>
		</Apex:form>
    </apex:pageBlock> 
    
</apex:page>

 
I'm trying to do a data-load of 3000 records, but it's failing because I'm hitting my query limit. I've had to limit my batch size to 1 record at a time in order to successfully allow Lexi Loader to work. The offending class is pasted below, can anyone help me bulkify it? Thanks!
 
public with sharing class setAccountGeoFromCountryService {
 
    public static void updateGeo(List<Account> Accounts) {
        List<String> listCountries = new List<String>();
        List<String> listStates = new List<String>(); 
        List<String> listZips = new List<String>(); 
        
        for (Account a : Accounts) {
            if(a.BillingCountry == null){
                return;
            }
            if(a.BillingCountry != null){
                listCountries.add(a.BillingCountry );
                if(a.BillingCountry  != 'US'){
					listStates.add('NULL');
                    listZips.add('NULL');
                }                
                if(a.BillingCountry  == 'US'){
                    listStates.add(a.BillingState );
                    if(a.BillingState  == 'CA' || a.BillingState  == 'California'){
                        listZips.add(a.BillingPostalCode);
                    }
                    if(a.BillingState  != 'CA' && a.BillingState  != 'California'){
                        listZips.add('NULL');
                    }
                }
            }
        }
        try{
            Territories__c territory = [SELECT Country_Code__c, Region__c, Theater__c, Country__c, State__c, State_Code__c, Postal_Code__c
                                            FROM Territories__c 
                                            WHERE Country_Code__c IN: listCountries 
                                        			AND (State__c =: listStates OR State_Code__c =: listStates)
                                       				AND Postal_Code__c =: listZips];
     system.debug(territory);
            for (Account a2: Accounts){
            	if(a2.Owner_is_Federal__c==true){
            		 a2.Geography__c = 'Federal';
            		 a2.Country2__c = territory.Country__c;
                     a2.Region__c = territory.Region__c;
            	}    
		     	if(a2.Owner_is_Federal__c==false){            	
	                 a2.Geography__c = territory.Theater__c;
	                 a2.Country2__c = territory.Country__c;
                     a2.Region__c = territory.Region__c;
		     	}                 
            }
        }catch(QueryException e){}
    }
}

 
I've been trying to do a bulk update of records using the data loader and I keep getting the following error:
"rfp: execution of BeforeInsert
caused by: System.QueryException: List has more than 1 row for assignment to SObject
Class.setRfpOwner.setOwners: line 15, column 1
Trigger.rfp: line 4, column 1 "

After looking at my code and the records I'm querying, I the query in line 15 of my service class should only yield one result, which leads me to believe that my service class is somehow not bulk safe. Can anyone point me in the right direction:

Trigger:
trigger rfp on RFP_Response__c (before insert, before update) {

    if(trigger.isBefore && trigger.isInsert){
        setRfpOwner.setOwners(trigger.new);
        rfpKwBuilder.buildKeyWords(Trigger.new);
    }
    if(trigger.isBefore && trigger.isUpdate){
        if(checkRecursive.flag == true){
            rfpKwBuilder.buildKeyWords(Trigger.new);
            for(RFP_Response__c rfp : Trigger.new){
                RFP_Response__c oldRfp = Trigger.oldMap.get(rfp.Id);
                if(oldRfp.Response__c != rfp.Response__c){
                    setResponseToggle.toggleResponse(trigger.new);      
                }                              
            }
            for(RFP_Response__c rfp : Trigger.new){
                RFP_Response__c oldRfp = Trigger.oldMap.get(rfp.Id);
                if(oldRfp.Category__c != rfp.Category__c){
                    setRfpOwner.setOwners(trigger.new);
                }                              
            }            
            
        } 
        checkRecursive.flag = false;
    }    
    
}

Class:
public class setRfpOwner {

    public static void setOwners(list<RFP_Response__c> rfpUpdateList){
        List<String> listCategories = new List<String>();

        for (RFP_Response__c rfp : rfpUpdateList) {
            if(rfp.Category__c == null){
                return;
            }
            if(rfp.Category__c != null){
                listCategories.add(rfp.Category__c);              
            }
        }
            RFP_Owner_Mappings__c mapping = [SELECT Name, RFP_Category_Owner__c, RFP_Category_Backup_Owner__c,RFP_Category_Owner__r.Email__c,RFP_Category_Backup_Owner__r.Email__c 
                                            FROM RFP_Owner_Mappings__c  
                                            WHERE Name IN :listCategories];
            for (RFP_Response__c rfp2 : rfpUpdateList){
                if(rfp2.Category__c == mapping.Name ){
                    rfp2.RFP_Category_Owner__c = mapping.RFP_Category_Owner__c;
                    rfp2.RFP_Category_Backup_Owner__c  = mapping.RFP_Category_Backup_Owner__c ;
                    rfp2.Category_Owner_Email__c = mapping.RFP_Category_Owner__r.Email__c;
                    rfp2.Category_Backup_Owner_Email__c  = mapping.RFP_Category_Backup_Owner__r.Email__c ;                    
                }          
            }
        
    }
    
}



 
I have been trying to do some mass account owner updates (approx 2000 records) and I'm running into processing time-limit errors.  I'm pretty sure the following class is the prime offender, but as someone who is not a full-time developer, I'm not certain where I can optimize it.  Thanks in advance for help!
public class syncContactOwnerWithAccount {

    public static list<Account> filterAcc(map<id, Account> oldMap, list<Account> newList) {
        list<Account> temp=new list<Account>();
        for (Account acc : newList){
            if (oldMap.get(acc.id).OwnerId != acc.OwnerId){
                temp.add(acc);
            }
        }
        return temp;
    }
    public static void updateContacts(List<Account> Accounts) {
    	list<Account> alist = new list <Account>();
        for (Account a2 : Accounts){
            alist.add(a2);
        }
        list<Contact> clist = [SELECT AccountId, Account.OwnerId
                               FROM Contact
                               WHERE AccountId in: alist];
        list<Contact> updatelist = new list<Contact>();      
        for(Contact c : clist){
            c.OwnerId = c.Account.OwnerId;
            updatelist.add(c);
        }
        update updatelist;
    }        
    
}

 
Hey all, I have two custom objects: Feature__c and Feature_Request__c.  Feature__c is the parent object in a master-detail relationship with Feature_Request__c.  When a Feature__c's status is update to "Accepted" I need to update two lookups on all of the Feature__c's child Feature_Request__c's. First I need to clear out the the Proposed_Feature__c lookup and then I need to populate the Feature__c master-detail with the id of the record that was previously populated in the Proposed_Feature__c lookup. As far as I can tell my code should work, but I keep getting a "list has no rows for assignment" error despite the debug log saying that all of my lists are populated. I've posted the code and the debug log below.  Any help would be greatly appreciated.

Trigger:
trigger Feature on Feature__c (after update) {

    if(trigger.isAfter && trigger.isUpdate){
        for(Feature__c f : trigger.new){
            if(f.Status__c == 'Accepted'){
	   updateFrsFromApprovedFeature.updateFeatureRequests(updateFrsFromApprovedFeature.filterFeature(trigger.oldmap,trigger.new));                
            }
        } 
    }
    
}

Helper Class:
public class updateFrsFromApprovedFeature {

    public static list<Feature__c> filterFeature(map<id, Feature__c> oldMap, list<Feature__c> newList) {
        list<Feature__c> temp=new list<Feature__c>();
        for (Feature__c newFeat : newList)    {
            if (oldMap.get(newFeat.id).Status__c != newFeat.Status__c && newFeat.Status__c == 'Accepted'){
                temp.add(newFeat);
            }
        }
        return temp;
    }

    public static void updateFeatureRequests(list<Feature__c> frUpdateList) {
        Feature__c featproxy = [SELECT Id, Status__c
                                FROM Feature__c
                                WHERE Id in: frUpdateList];
system.debug(featproxy);
        List<Feature_Request__c> frs = [SELECT Feature__c, Proposed_Feature__c
                                        FROM Feature_Request__c
                                        WHERE Proposed_Feature__c =: featproxy.id];
system.debug(frs);        
        List<Feature_Request__c> updateFrs = new list<Feature_Request__c>();
        for(Feature_Request__c updatefr : frs){
            updatefr.Feature__c = featproxy.Id;
            updatefr.Proposed_Feature__c = null;
            updateFrs.add(updatefr);
        }
system.debug(updateFrs);        
        If(updateFrs.size()>0){
	        update updateFrs;               
        } 
    }
    	
}

Debug Statements:
09:10:30:109 USER_DEBUG [17]|DEBUG|Feature__c:{Id=a11i000000CcIJYAA3}
09:10:30:114 USER_DEBUG [21]|DEBUG|(Feature_Request__c:{Feature__c=a11i000000CdxuPAAR, Proposed_Feature__c=a11i000000CcIJYAA3, Id=a10e0000002L7K4AAK}, Feature_Request__c:{Feature__c=a11i000000CdxuPAAR, Proposed_Feature__c=a11i000000CcIJYAA3, Id=a10e0000002L7K9AAK})
09:10:30:115 USER_DEBUG [28]|DEBUG|(Feature_Request__c:{Feature__c=a11i000000CcIJYAA3, Proposed_Feature__c=null, Id=a10e0000002L7K4AAK}, Feature_Request__c:{Feature__c=a11i000000CcIJYAA3, Proposed_Feature__c=null, Id=a10e0000002L7K9AAK})

Link to Complete Debug Log: https://docs.google.com/document/d/1S7n2LWqWfG7NU97sJ9E1ZAooIwDdiHiTpgEyWShzHXg/edit?usp=sharing

 
Hey all, 
I'm working a bit of code to automatically re-add products to an opportunity if they get deleted as a result of the user changing the pricebook.  I experimented with trying to clone the OLIs in a beforeDelete trigger, but couldn't get that work, I assume becuase updating the pricebook deleted the newly created clones in addition to the old products.

Instead I've built a custom object called OLI_Clone__c for which records are inserted every time a new OLI is added to an oppty and then deleted later when the oppty goes to closed won or closed lost.  Basically, when the pricebook updates on the oppty, the code queries back to the OLI_Clone__c records associated with the oppty and then uses the data stored there to recreate the OLIs.  The biggest challenge is that I can't create a lookup to ProcebookEntry on a custom object so I had to create a lookup to Product and then use a combination of the Opportunity's new Pricebook Id and the OLI_Clone__c's product Id to query for the correct PricebookEntry.  

I've been able to get a list of PricebookEntryIds, but I can't figure out how get the correct PricebookEntryId for each OLI_Clone__c without querying for it inside of my for loop, which is obviously a big no no.  I do know that I should be using a map, but I am relatively novice coder, and I just can't seem to get the syntax right.

Thanks in advance for your help!

I've pasted my service class below with a few comments:
public with sharing class autoAddProductsAfterPBChange {

//create a filter to listen for a change in the pricebook below
      public static list<opportunity> filterOpp(map<id, opportunity> oldMap, list<opportunity> newList) {
        list<opportunity> temp=new list<opportunity>();
        for (opportunity newOpp : newList){
            if (oldMap.get(newOpp.id).PriceBook2Id != newOpp.PriceBook2Id){
                temp.add(newOpp);
            }
        }
        return temp;
    }        

//find the pricebook entries and recreate the OLIs   
    public static void autoAdd(list<Opportunity> opps){
        Opportunity opp = new Opportunity(); 
        Pricebook2 pb = new Pricebook2();    
        for(Opportunity opp2 : opps){
            opp.id = opp2.Id;
            pb.id = opp2.Pricebook2Id;
        }
        list<OLI_Clone__c> olics = [SELECT Quantity__c, Additional_Discount_off_List__c, Manual_Discount__c, Opportunity__c, Product__c, Sales_Price__c, Service_Term_in_Months__c
                                                     FROM OLI_Clone__c
                                                     WHERE Opportunity__c =: opp.id];
        list<Id> prodids = new list<Id>();
        for(OLI_Clone__c olicprod : olics){
            prodids.add(olicprod.Product__c);
        }
        List<PricebookEntry>pbeids = [SELECT Id, Product2Id
                           			         FROM PricebookEntry
                                                         WHERE Product2Id in: prodids AND Pricebook2Id =: pb.id];
 		Map<Id, PricebookEntry> pbeMap = new Map<Id, PricebookEntry>(pbeids);  // Is this map correct? 
 		list<OpportunityLineItem>toInsert = new list<OpportunityLineItem>();
        for(OLI_Clone__c olic : olics){
            if(pbeMap.containsKey(olic.Product__c)){
                OpportunityLineItem oli = new OpportunityLineItem();
                PricebookEntry pbe = pbeMap.get(); // I know I need to be "getting" something here but I'm not sure how to structure the syntax, and I'm not sure that my map above is configured correctly either.  Basically I need to get the correct PricebookEntryId based on the Product__c field on the OLI_Clone__c in this loop and the parent Opportunity's pricebook.
                oli.Quantity = olic.Quantity__c;
                oli.UnitPrice = olic.Sales_Price__c;
                toInsert.add(oli);
            }
        }
        insert toInsert;
	}

}




 

Hey folks, I have a somewhat complicated use-case I'm trying to solve.  I have a visualforce page that we use to configure products. What I'm trying to do is derive the quantity of one particular type of product based on the quantity or quantities of another type of products and I want to do this within the browser and then insert the derived value into the database on Save. Specifically we have a product called "MTP" and another generic "Support" product.  Whenever MTP product quantities are added or updated to the product "shopping-cart" visualforce page, I want ONLY the total of all MTP line-items to be automatically populated in the quantity field of the support product. See my example below:

User-added image
Here's my current code:
Controller:

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 overLimit {get;set;}
    public Boolean multipleCurrencies {get; set;} 
    private Boolean forcePricebookSelection = false;
    
    private opportunityLineItem[] forDeletion = new opportunityLineItem[]{};


    public opportunityProductEntryExtension(ApexPages.StandardController controller) {

        // Need to know if org has multiple currencies enabled
        multipleCurrencies = UserInfo.isMultiCurrencyOrganization();

        // Get information about the Opportunity being worked on
        if(multipleCurrencies)
            theOpp = database.query('select Id, Pricebook2Id, Pricebook2.Name, CurrencyIsoCode from Opportunity where Id = \'' + controller.getRecord().Id + '\' limit 1');
        else
            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, Quantity, TotalPrice, UnitPrice, Description, List_Price__c, Disti_Transfer_Price2__c, Disti_Transfer_Price__c, PriceBookEntryId, PriceBookEntry.Name, PriceBookEntry.UnitPrice, PriceBookEntry.IsActive, PriceBookEntry.Product2Id, PriceBookEntry.Product2.Name, PriceBookEntry.Product2.Product_Term_Years__c, PriceBookEntry.PriceBook2Id, PriceBookEntry.Product2.SKU__c, PriceBookEntry.Product2.Family, PriceBookEntry.Product2.Type__c, Service_Term_in_Months__c, PriceBookEntry.Disti_Transfer_Price__c, Discount_off_list_manual__c from opportunityLineItem where OpportunityId=:theOpp.Id];

        // Check if Opp has a pricebook associated yet
        if(theOpp.Pricebook2Id == null){
            Pricebook2[] activepbs = [select Id, Name from Pricebook2 where isActive = true limit 2];
            if(activepbs.size() == 2){
                forcePricebookSelection = true;
                theBook = new Pricebook2();
            }
            else{
                theBook = activepbs[0];
            }
        }
        else{
            theBook = theOpp.Pricebook2;
        }
        
        if(!forcePricebookSelection)
            updateAvailableList();
    }
    
    // this is the 'action' method on the page
    public PageReference priceBookCheck(){
    
        // if the user needs to select a pricebook before we proceed we send them to standard pricebook selection screen
        if(forcePricebookSelection){        
            return changePricebook();
        }
        else{
        
            //if there is only one active pricebook we go with it and save the opp
            if(theOpp.pricebook2Id != theBook.Id){
                try{
                    theOpp.Pricebook2Id = theBook.Id;
                    update(theOpp);
                }
                catch(Exception e){
                    ApexPages.addMessages(e);
                }
            }
            
            return null;
        }
    }
       
    public String getChosenCurrency(){
    
        if(multipleCurrencies)
            return (String)theOpp.get('CurrencyIsoCode');
        else
            return '';
    }

    public void updateAvailableList() {
    
        // We dynamically build a query string and exclude items already in the shopping cart
        String qString = 'select Id, Name, Pricebook2.Name, Pricebook2Id, IsActive, Product2.Name, Product2.Family, Product2.Type__c, Product2.IsActive, Product2.Description, UnitPrice, Product2.SKU__c, Disti_Transfer_Price__c, Product2.Product_Term_Years__c, Product2.SKU_Level_Discount__c from PricebookEntry where IsActive=true and Pricebook2Id = \'' + theBook.Id + '\'';
        if(multipleCurrencies)
            qstring += ' and CurrencyIsoCode = \'' + theOpp.get('currencyIsoCode') + '\'';
        
        // 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
        if(searchString!=null){
            qString+= ' and (Product2.Name like \'%' + searchString + '%\' or Product2.Description like \'%' + searchString + '%\')';
        }
        
        Set<Id> selectedEntries = new Set<Id>();
        for(opportunityLineItem d:shoppingCart){
            selectedEntries.add(d.PricebookEntryId);
        }
        
        if(selectedEntries.size()>0){
            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)
        if(AvailableProducts.size()==101){
            AvailableProducts.remove(100);
            overLimit = true;
        }
        else{
            overLimit=false;
        }
    }
    
    public void addToShoppingCart(){
    
        // This function runs when a user hits "select" button next to a product
        list<Price_Book_Discounts__c> discounts = [SELECT Discount__c, Name
                                                   FROM Price_Book_Discounts__c 
                                                   WHERE Name =: theBook.Name];
        list<SKU_Discounts__c> skus = [SELECT Discount__c, SKU__c, Price_Book_Name__c
                                           FROM SKU_Discounts__c 
                                           WHERE Price_Book_Name__c =: theBook.Name];                
        Map<String, Decimal> pbNameToDiscountMap =  new Map<String, Decimal>();
		Map<String, Decimal> SkuToDiscountMap = new Map<String, Decimal>();
        for(Price_Book_Discounts__c discount : discounts){
            pbNameToDiscountMap.put(discount.Name, discount.Discount__c);
        }
        for(SKU_Discounts__c sku : skus){
            if (!SkuToDiscountMap.containsKey(sku.SKU__c)) {
                SkuToDiscountMap.put(sku.SKU__c, sku.Discount__c);
            } 
        } 
        for(PricebookEntry d : AvailableProducts){            
            if((String)d.Id==toSelect && d.Product2.Type__c == 'Support'){
                shoppingCart.add(new opportunityLineItem(OpportunityId = theOpp.Id, 
                                                        PriceBookEntry = d, 
                                                        PriceBookEntryId = d.Id
                                                        ));
                break;
            }
            if((String)d.Id==toSelect && d.Product2.Type__c == 'Non-Revenue'){
                shoppingCart.add(new opportunityLineItem(OpportunityId = theOpp.Id, 
                                                        PriceBookEntry = d, 
                                                        PriceBookEntryId = d.Id,
                                                        Service_Term_in_Months__c = 2,
                                                        Quantity = 100
                                                        ));
                break;
            }
            if((String)d.Id==toSelect && d.Product2.Type__c == 'Subscription'){
                if(SkuToDiscountMap.get(d.Product2.SKU__c)!=null){
                    shoppingCart.add(new opportunityLineItem(OpportunityId=theOpp.Id, PriceBookEntry=d, PriceBookEntryId=d.Id, UnitPrice=d.Disti_Transfer_Price__c, Disti_Transfer_Price2__c = d.Disti_Transfer_Price__c, List_Price__c = d.UnitPrice, Discount_off_list_manual__c = SkuToDiscountMap.get(d.Product2.SKU__c)));
                    break;
                }
                if(SkuToDiscountMap.get(d.Product2.SKU__c)==null){
                    shoppingCart.add(new opportunityLineItem(OpportunityId=theOpp.Id, PriceBookEntry=d, PriceBookEntryId=d.Id, UnitPrice=d.Disti_Transfer_Price__c, Disti_Transfer_Price2__c = d.Disti_Transfer_Price__c, List_Price__c = d.UnitPrice, Discount_off_list_manual__c = pbNameToDiscountMap.get(theBook.Name)));
                    break;
                }
            }            
        }
        
        updateAvailableList();  
    }  

    public PageReference calculateSupport(){
        List<Id> parents = new list<Id>();
        for(opportunityLineItem d : shoppingCart){
            parents.add(d.OpportunityId);
        }
        List<OpportunityLineItem> olis = [SELECT Quantity, PriceBookEntry.Product2.Family FROM OpportunityLineItem WHERE Id in: parents AND PriceBookEntry.Product2.Family =: 'MTP'];
        double suppQuant = 0;    
        for(OpportunityLineItem mtpOli : olis){
            suppQuant += mtpOli.Quantity;
        }             
        for(opportunityLineItem d : shoppingCart){
            if(d.PriceBookEntry.Product2.Type__c == 'Support'){
                d.Quantity = suppQuant;
            }else{
                d.Quantity = d.Quantity;
            }
        }
        
        return null;
    }

    public PageReference calculateSalesPrice(){
        
        for(opportunityLineItem d : shoppingCart){
            decimal price = d.PriceBookEntry.UnitPrice - (d.PriceBookEntry.UnitPrice * (d.Discount_off_list_manual__c/100));
            d.UnitPrice = price.setscale(2);
        }
        
        return null;
    }    

    public PageReference calculateDiscount(){
        
        for(opportunityLineItem d : shoppingCart){
            decimal discount = ((d.PriceBookEntry.UnitPrice - d.UnitPrice)/d.PriceBookEntry.UnitPrice)*100;            
            d.Discount_off_list_manual__c = discount.setscale(2);
        }
        
        return null;
    }        

    public PageReference removeFromShoppingCart(){
    
        // This function runs when a user hits "remove" on an item in the "Selected Products" section
    
        Integer count = 0;
    
        for(opportunityLineItem d : shoppingCart){
            if((String)d.PriceBookEntryId==toUnselect){
            
                if(d.Id!=null)
                    forDeletion.add(d);
            
                shoppingCart.remove(count);
                break;
            }
            count++;
        }
        
        updateAvailableList();
        
        return null;
    }
    
    public PageReference onSave(){
    
        // If previously selected products are now removed, we need to delete them
        if(forDeletion.size()>0)
            delete(forDeletion);
    
        // Previously selected products may have new quantities and amounts, and we may have new products listed, so we use upsert here
        try{
            if(shoppingCart.size()>0)
                upsert(shoppingCart);
        }
        catch(Exception e){
            ApexPages.addMessages(e);
            return null;
        }  
           
        // After save return the user to the Opportunity
        return new PageReference('/' + ApexPages.currentPage().getParameters().get('Id'));
    }
    
    public PageReference onCancel(){
 
        // If user hits cancel we commit no changes and return them to the Opportunity   
        return new PageReference('/' + ApexPages.currentPage().getParameters().get('Id'));
    }
    
    public PageReference changePricebook(){
    
        // This simply returns a PageReference to the standard Pricebook selection screen
        // Note that is uses retURL parameter to make sure the user is sent back after they choose
    
        PageReference ref = new PageReference('/oppitm/choosepricebook.jsp');
        ref.getParameters().put('id',theOpp.Id);
        ref.getParameters().put('retURL','/apex/opportunityProductEntry?id=' + theOpp.Id);
        
        return ref;
    }
}
Visualforce Page:
<apex:page standardController="Opportunity" extensions="opportunityProductEntryExtension" action="{!priceBookCheck}" >

    <apex:sectionHeader Title="Manage {!$ObjectType.Product2.LabelPlural}" subtitle="{!opportunity.Name}"/>
    <apex:messages style="color:red"/>

    <style>
        .search{
            font-size:14pt;
            margin-right: 20px;    
        }
        .fyi{
            color:red;
            font-style:italic;
        }
        .label{
            margin-right:10px;
            font-weight:bold;
            vertical-align: text-bottom;
        }
       .pbTitle {
            white-space: nowrap;
            
        }            

    </style>
    
    <script type='text/javascript'>
    
        // This script assists the search bar functionality
        // It will execute a search only after the user has stopped typing for more than 1 second
        // To raise the time between when the user stops typing and the search, edit the following variable:
        
        var waitTime = 0.1;
        
    
        var countDown = waitTime+1;
        var started = false;
        
        function resetTimer(){
        
            countDown=waitTime+0.1;
            
            if(started==false){
                started=true;
                runCountDown();
            }
        }
        
        function runCountDown(){
        
            countDown--;
            
            if(countDown<=0){
                fetchResults();
                started=false;
            }
            else{
                window.setTimeout(runCountDown,1000);
            }
        }    
    </script>
   
  
    <apex:form >
        <div id="InternalDiv" styleClass="pbTitle" style="width:600px; float:right; margin-top:-60px; font-size:9px;">     

         </div>
             <apex:outputPanel id="mainBody">
                <div id="pbName" styleClass="pbName" style="margin-top:0px;">
                    <apex:outputLabel styleClass="label">PriceBook: </apex:outputLabel>
                    <apex:outputText value="{!theBook.Name}"/>&nbsp;
                    <apex:commandLink action="{!changePricebook}" value="change" immediate="true"/>
                </div>                  
                    <br/>
                    <!-- not everyone is using multi-currency, so this section may or may not show -->
                    <apex:outputPanel rendered="{!multipleCurrencies}">
                        <apex:outputLabel styleClass="label">Currency: </apex:outputLabel>
                        <apex:outputText value="{!chosenCurrency}"/>
                        <br/>
                    </apex:outputPanel>
                <br/>
         
            
<!-- this is the upper table... a.k.a. the "Shopping Cart"-->

            <!-- notice we use a lot of $ObjectType merge fields... I did that because if you have changed the labels of fields or objects it will reflect your own lingo -->
            <apex:pageBlock title="Selected {!$ObjectType.Product2.LabelPlural}" id="selected">
                       
                <apex:pageblockTable value="{!shoppingCart}" var="s">
                    
                    <apex:column >
                        <apex:commandLink value="Remove" action="{!removeFromShoppingCart}" reRender="selected,searchResults" immediate="true">
                            <!-- this param is how we send an argument to the controller, so it knows which row we clicked 'remove' on -->
                            <apex:param value="{!s.PriceBookEntryId}" assignTo="{!toUnselect}" name="toUnselect"/>
                        </apex:commandLink>
                    </apex:column>

                    <!--********** Product Name **********-->
                    <apex:column headerValue="{!$ObjectType.Product2.LabelPlural}" value="{!s.PriceBookEntry.Product2.Name}"/>

                    <!--********** Product SKU **********-->
                    <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.SKU__c.Label}" value="{!s.PriceBookEntry.Product2.SKU__c}"/> 

                    <!--********** Annual Product Term **********-->
                    <apex:column headerValue="Annual Term" id="pt" rendered="false" value="{!s.PriceBookEntry.Product2.Product_Term_Years__c}"/>                         
                    
                    <!--********** Quantity **********-->
                    <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.Quantity.Label}">
                        <apex:inputField value="{!s.Quantity}" id="quant" style="width:70px" required="true" rendered="{!IF(s.PriceBookEntry.Product2.Type__c == 'Support', false, true)}">
                            <apex:actionSupport event="onkeyup" reRender="tot"/>
                            <apex:actionSupport event="onchange" action="{!calculateSupport}"/>
                        </apex:inputField>
                        <apex:outputText id="quants" value="{0, number, ###,###,###,##0.00}" rendered="{!IF(s.PriceBookEntry.Product2.Type__c == 'Support', true, false)}">
                            <apex:param value="{!s.Quantity}"/>
                        </apex:outputText> 
                    </apex:column>
                  

                    <!--********** Service Term in Months **********-->
                    <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.Service_Term_in_Months__c.Label}">
                        <apex:inputField value="{!s.Service_Term_in_Months__c}" id="svc" style="width:70px" required="true" rendered="{!IF(s.PriceBookEntry.Product2.Type__c == 'Support', false, true)}">
                            <apex:actionSupport event="onkeyup" reRender="tot"/>
                        </apex:inputField>
                        <apex:outputText id="svcs" value="${0, number, ###,###,###,##0.00}" rendered="{!IF(s.PriceBookEntry.Product2.Type__c == 'Support', true, false)}">
                            <apex:param value="{!s.PriceBookEntry.UnitPrice}"/>
                        </apex:outputText> 
                    </apex:column>                                        

                    <!--********** Discount (Manual) **********-->
                    <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.Discount_off_list_manual__c.Label}">
                        <apex:inputField value="{!s.Discount_off_list_manual__c}" id="disc" style="width:70px" required="True" rendered="{!IF(s.PriceBookEntry.Product2.Type__c == 'Support', false, true)}">
                            <apex:actionSupport event="onchange" reRender="tot"/>
                             <apex:actionSupport event="onkeyup" action="{!calculateSalesPrice}"/>
                        </apex:inputField>
                        <apex:outputText id="discs" value="${0, number, ###,###,###,##0.00}" rendered="{!IF(s.PriceBookEntry.Product2.Type__c == 'Support', true, false)}">
                            <apex:param value="{!s.PriceBookEntry.UnitPrice}"/>
                        </apex:outputText> 
                    </apex:column>                    
                    
                    <!--********** Sales Price **********-->
                    <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.UnitPrice.Label}">
                        <apex:inputField value="{!s.UnitPrice}" id="sp" style="width:70px" required="true" rendered="{!IF(s.PriceBookEntry.Product2.Type__c == 'Support', false, true)}">
                            <apex:actionSupport event="onchange" reRender="tot"/>
                            <apex:actionSupport event="onkeyup" action="{!calculateDiscount}"/>
                        </apex:inputField>                    
                        <apex:outputText id="sps" value="${0, number, ###,###,###,##0.00}" rendered="{!IF(s.PriceBookEntry.Product2.Type__c == 'Support', true, false)}">
                            <apex:param value="{!s.PriceBookEntry.UnitPrice}"/>
                        </apex:outputText> 
                    </apex:column>                    

                    <!--********** Disti Transfer Price (Custom) **********-->
                    <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.Disti_Transfer_Price2__c.Label}">
                        <apex:outputText id="dpc" value="${0, number, ###,###,###,##0.00}">
                            <apex:param value="{!s.PriceBookEntry.Disti_Transfer_Price__c}"/>
                        </apex:outputText> 
                    </apex:column>

                    <!--********** List Price (Custom) **********-->
                    <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.List_Price__c.Label}">
                        <apex:outputText id="lpc" value="${0, number, ###,###,###,##0.00}">
                            <apex:param value="{!s.PriceBookEntry.UnitPrice}"/>
                        </apex:outputText> 
                    </apex:column>

                    <!--********** Disti Transfer Price (Standard) Hidden **********-->
                    <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.Disti_Transfer_Price__c.Label}" value="{!s.PriceBookEntry.Disti_Transfer_Price__c}" id="dp" rendered="false"/>

                    <!--********** List Price (Standard) Hidden **********-->
                    <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.ListPrice.Label}" id="lp" value="{!s.PriceBookEntry.UnitPrice}" rendered="false"/>
                    
                    <!--********** Total Price (display only field) **********-->
                    <apex:column headerValue="Total Price">
                        <apex:outputText id="tot" value="${0, number, ###,###,###,##0.00}">
                            <apex:param value="{!IF(s.PriceBookEntry.Product2.Product_Term_Years__c != null,(s.Quantity * s.Service_Term_in_Months__c * s.UnitPrice)/(s.PriceBookEntry.Product2.Product_Term_Years__c*12),(s.Quantity * s.UnitPrice)) }"/>
                        </apex:outputText> 
                    </apex:column>                                   
                    
                </apex:pageblockTable>
            
            
                <apex:pageBlockButtons >
                    <apex:commandButton action="{!onSave}" value="Save"/>
                    <apex:commandButton action="{!onCancel}" value="Cancel" immediate="true"/>
                </apex:pageBlockButtons>
            
            </apex:pageBlock>
    
<!-- this is the lower table: search bar and search results -->
    
            <apex:pageBlock >
            
                <apex:outputPanel styleClass="search">
                    Search for {!$ObjectType.Product2.LabelPlural}:
                </apex:outputPanel>

                <apex:actionRegion renderRegionOnly="false" immediate="true">
                
                    <apex:actionFunction name="fetchResults" action="{!updateAvailableList}" reRender="searchResults" status="searchStatus"/>
                    
                    <!-- here we invoke the scripting to get out fancy 'no button' search bar to work -->
                    <apex:inputText value="{!searchString}" onkeydown="if(event.keyCode==13){this.blur();}else{resetTimer();}" style="width:300px"/>
                    &nbsp;&nbsp;
                    <i>
                        <!-- actionStatus component makes it easy to let the user know when a search is underway -->
                        <apex:actionStatus id="searchStatus" startText="searching..." stopText=" "/>
                    </i>
                    
                </apex:actionRegion>
            
                <br/>
                <br/>
            
                <apex:outputPanel id="searchResults">
                
                    <apex:pageBlockTable value="{!AvailableProducts}" var="a">
                    
                        <apex:column headerValue="{!$ObjectType.Product2.Fields.Name.Label}" value="{!a.Product2.Name}" />
                        
                        <apex:column headerValue="{!$ObjectType.Product2.Fields.SKU__c.Label}" value="{!a.Product2.SKU__c}"/>
                        
                        <apex:column headerValue="{!$ObjectType.Product2.Fields.Description.Label}" value="{!a.Product2.Description}"/>
                        
                        <apex:column >
                            <!-- command button in a column... neato -->
                            <apex:commandButton value="Select" action="{!addToShoppingCart}" reRender="selected,searchResults" immediate="true">
                                <!-- again we use apex:param to be able to tell the controller which row we are working with -->
                                <apex:param value="{!a.Id}" assignTo="{!toSelect}" name="toSelect"/>
                            </apex:commandButton>
                        </apex:column>
                        
                    </apex:pageBlockTable>
                    
                    <!-- We put up a warning if results exceed 100 rows -->
                    <apex:outputPanel styleClass="fyi" rendered="{!overLimit}">
                        <br/>
                        Your search returned over 100 results, use a more specific search string if you do not see the desired {!$ObjectType.Product2.Label}.
                        <br/>
                    </apex:outputPanel>
                    
                </apex:outputPanel>
            
            </apex:pageBlock>
            
        </apex:outputPanel>

    </apex:form>

</apex:page>

 
Hey folks, I know I'm gonna feel stupid when I get the answer here, but I just can't seem to get this right.  I'm trying to create a visualforce page that populates other visualforce pages within an iframe based on a picklist selection, btu I can't seem to figure out how to pass the selected picklist value into the src parameter of my iframe component. I've deleted a bunch of the broken code that hasn't worked so the code is pretty simple at this point.

Can someone help me sort it out?  Thanks!

Controller:
public class domoDashboardController {
    
    public List<String> pagename {
        get {
            if (pagename == null) {
                pagename = new List<String>();
                list<ApexPage> pages = [SELECT Name FROM ApexPage WHERE Name != 'domoDashBoardViewer' AND Name LIKE 'DOMO_%' ORDER BY Name ASC];
                for (ApexPage page : pages){
        			pagename.add(page.Name);
        		}
      		}
      		return pagename;          
    	}
    	set;
  	}
    
}

VF Page:
<apex:page controller="domoDashboardController">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <apex:pageBlock title="DOMO Dashboard Viewer" mode="edit">
        
        <apex:form>
            <table width="100%" border="0">
                <tr>
                    <td style="font-weight:bold; padding-left: 5px; padding-top:10px; width: 125px;">                    
                        Select Dashboard:
                    </td>                
                    <td style="font-weight:bold; padding-top:8px;">
    					<select id="pagename">
                        	<option value=""></option>
                            <apex:repeat value="{!pagename}" var="pag">
                            	<option value="{!pag}">{!pag}</option>
                            </apex:repeat>
                        </select>     
                    </td>     
                </tr>
            </table>
            <apex:pageBlock>    
                <table width="100%" border="0">
                    <tr>
                        <apex:page id="thePage">
							<apex:iframe src="" scrolling="true" id="theIframe"/>
                        </apex:page>
                    </tr>
                </table>
            </apex:pageBlock>
		</Apex:form>
    </apex:pageBlock> 
    
</apex:page>

 
I'm trying to do a data-load of 3000 records, but it's failing because I'm hitting my query limit. I've had to limit my batch size to 1 record at a time in order to successfully allow Lexi Loader to work. The offending class is pasted below, can anyone help me bulkify it? Thanks!
 
public with sharing class setAccountGeoFromCountryService {
 
    public static void updateGeo(List<Account> Accounts) {
        List<String> listCountries = new List<String>();
        List<String> listStates = new List<String>(); 
        List<String> listZips = new List<String>(); 
        
        for (Account a : Accounts) {
            if(a.BillingCountry == null){
                return;
            }
            if(a.BillingCountry != null){
                listCountries.add(a.BillingCountry );
                if(a.BillingCountry  != 'US'){
					listStates.add('NULL');
                    listZips.add('NULL');
                }                
                if(a.BillingCountry  == 'US'){
                    listStates.add(a.BillingState );
                    if(a.BillingState  == 'CA' || a.BillingState  == 'California'){
                        listZips.add(a.BillingPostalCode);
                    }
                    if(a.BillingState  != 'CA' && a.BillingState  != 'California'){
                        listZips.add('NULL');
                    }
                }
            }
        }
        try{
            Territories__c territory = [SELECT Country_Code__c, Region__c, Theater__c, Country__c, State__c, State_Code__c, Postal_Code__c
                                            FROM Territories__c 
                                            WHERE Country_Code__c IN: listCountries 
                                        			AND (State__c =: listStates OR State_Code__c =: listStates)
                                       				AND Postal_Code__c =: listZips];
     system.debug(territory);
            for (Account a2: Accounts){
            	if(a2.Owner_is_Federal__c==true){
            		 a2.Geography__c = 'Federal';
            		 a2.Country2__c = territory.Country__c;
                     a2.Region__c = territory.Region__c;
            	}    
		     	if(a2.Owner_is_Federal__c==false){            	
	                 a2.Geography__c = territory.Theater__c;
	                 a2.Country2__c = territory.Country__c;
                     a2.Region__c = territory.Region__c;
		     	}                 
            }
        }catch(QueryException e){}
    }
}

 
I've been trying to do a bulk update of records using the data loader and I keep getting the following error:
"rfp: execution of BeforeInsert
caused by: System.QueryException: List has more than 1 row for assignment to SObject
Class.setRfpOwner.setOwners: line 15, column 1
Trigger.rfp: line 4, column 1 "

After looking at my code and the records I'm querying, I the query in line 15 of my service class should only yield one result, which leads me to believe that my service class is somehow not bulk safe. Can anyone point me in the right direction:

Trigger:
trigger rfp on RFP_Response__c (before insert, before update) {

    if(trigger.isBefore && trigger.isInsert){
        setRfpOwner.setOwners(trigger.new);
        rfpKwBuilder.buildKeyWords(Trigger.new);
    }
    if(trigger.isBefore && trigger.isUpdate){
        if(checkRecursive.flag == true){
            rfpKwBuilder.buildKeyWords(Trigger.new);
            for(RFP_Response__c rfp : Trigger.new){
                RFP_Response__c oldRfp = Trigger.oldMap.get(rfp.Id);
                if(oldRfp.Response__c != rfp.Response__c){
                    setResponseToggle.toggleResponse(trigger.new);      
                }                              
            }
            for(RFP_Response__c rfp : Trigger.new){
                RFP_Response__c oldRfp = Trigger.oldMap.get(rfp.Id);
                if(oldRfp.Category__c != rfp.Category__c){
                    setRfpOwner.setOwners(trigger.new);
                }                              
            }            
            
        } 
        checkRecursive.flag = false;
    }    
    
}

Class:
public class setRfpOwner {

    public static void setOwners(list<RFP_Response__c> rfpUpdateList){
        List<String> listCategories = new List<String>();

        for (RFP_Response__c rfp : rfpUpdateList) {
            if(rfp.Category__c == null){
                return;
            }
            if(rfp.Category__c != null){
                listCategories.add(rfp.Category__c);              
            }
        }
            RFP_Owner_Mappings__c mapping = [SELECT Name, RFP_Category_Owner__c, RFP_Category_Backup_Owner__c,RFP_Category_Owner__r.Email__c,RFP_Category_Backup_Owner__r.Email__c 
                                            FROM RFP_Owner_Mappings__c  
                                            WHERE Name IN :listCategories];
            for (RFP_Response__c rfp2 : rfpUpdateList){
                if(rfp2.Category__c == mapping.Name ){
                    rfp2.RFP_Category_Owner__c = mapping.RFP_Category_Owner__c;
                    rfp2.RFP_Category_Backup_Owner__c  = mapping.RFP_Category_Backup_Owner__c ;
                    rfp2.Category_Owner_Email__c = mapping.RFP_Category_Owner__r.Email__c;
                    rfp2.Category_Backup_Owner_Email__c  = mapping.RFP_Category_Backup_Owner__r.Email__c ;                    
                }          
            }
        
    }
    
}



 
Hey all, I have two custom objects: Feature__c and Feature_Request__c.  Feature__c is the parent object in a master-detail relationship with Feature_Request__c.  When a Feature__c's status is update to "Accepted" I need to update two lookups on all of the Feature__c's child Feature_Request__c's. First I need to clear out the the Proposed_Feature__c lookup and then I need to populate the Feature__c master-detail with the id of the record that was previously populated in the Proposed_Feature__c lookup. As far as I can tell my code should work, but I keep getting a "list has no rows for assignment" error despite the debug log saying that all of my lists are populated. I've posted the code and the debug log below.  Any help would be greatly appreciated.

Trigger:
trigger Feature on Feature__c (after update) {

    if(trigger.isAfter && trigger.isUpdate){
        for(Feature__c f : trigger.new){
            if(f.Status__c == 'Accepted'){
	   updateFrsFromApprovedFeature.updateFeatureRequests(updateFrsFromApprovedFeature.filterFeature(trigger.oldmap,trigger.new));                
            }
        } 
    }
    
}

Helper Class:
public class updateFrsFromApprovedFeature {

    public static list<Feature__c> filterFeature(map<id, Feature__c> oldMap, list<Feature__c> newList) {
        list<Feature__c> temp=new list<Feature__c>();
        for (Feature__c newFeat : newList)    {
            if (oldMap.get(newFeat.id).Status__c != newFeat.Status__c && newFeat.Status__c == 'Accepted'){
                temp.add(newFeat);
            }
        }
        return temp;
    }

    public static void updateFeatureRequests(list<Feature__c> frUpdateList) {
        Feature__c featproxy = [SELECT Id, Status__c
                                FROM Feature__c
                                WHERE Id in: frUpdateList];
system.debug(featproxy);
        List<Feature_Request__c> frs = [SELECT Feature__c, Proposed_Feature__c
                                        FROM Feature_Request__c
                                        WHERE Proposed_Feature__c =: featproxy.id];
system.debug(frs);        
        List<Feature_Request__c> updateFrs = new list<Feature_Request__c>();
        for(Feature_Request__c updatefr : frs){
            updatefr.Feature__c = featproxy.Id;
            updatefr.Proposed_Feature__c = null;
            updateFrs.add(updatefr);
        }
system.debug(updateFrs);        
        If(updateFrs.size()>0){
	        update updateFrs;               
        } 
    }
    	
}

Debug Statements:
09:10:30:109 USER_DEBUG [17]|DEBUG|Feature__c:{Id=a11i000000CcIJYAA3}
09:10:30:114 USER_DEBUG [21]|DEBUG|(Feature_Request__c:{Feature__c=a11i000000CdxuPAAR, Proposed_Feature__c=a11i000000CcIJYAA3, Id=a10e0000002L7K4AAK}, Feature_Request__c:{Feature__c=a11i000000CdxuPAAR, Proposed_Feature__c=a11i000000CcIJYAA3, Id=a10e0000002L7K9AAK})
09:10:30:115 USER_DEBUG [28]|DEBUG|(Feature_Request__c:{Feature__c=a11i000000CcIJYAA3, Proposed_Feature__c=null, Id=a10e0000002L7K4AAK}, Feature_Request__c:{Feature__c=a11i000000CcIJYAA3, Proposed_Feature__c=null, Id=a10e0000002L7K9AAK})

Link to Complete Debug Log: https://docs.google.com/document/d/1S7n2LWqWfG7NU97sJ9E1ZAooIwDdiHiTpgEyWShzHXg/edit?usp=sharing

 
Hey all, 
I'm working a bit of code to automatically re-add products to an opportunity if they get deleted as a result of the user changing the pricebook.  I experimented with trying to clone the OLIs in a beforeDelete trigger, but couldn't get that work, I assume becuase updating the pricebook deleted the newly created clones in addition to the old products.

Instead I've built a custom object called OLI_Clone__c for which records are inserted every time a new OLI is added to an oppty and then deleted later when the oppty goes to closed won or closed lost.  Basically, when the pricebook updates on the oppty, the code queries back to the OLI_Clone__c records associated with the oppty and then uses the data stored there to recreate the OLIs.  The biggest challenge is that I can't create a lookup to ProcebookEntry on a custom object so I had to create a lookup to Product and then use a combination of the Opportunity's new Pricebook Id and the OLI_Clone__c's product Id to query for the correct PricebookEntry.  

I've been able to get a list of PricebookEntryIds, but I can't figure out how get the correct PricebookEntryId for each OLI_Clone__c without querying for it inside of my for loop, which is obviously a big no no.  I do know that I should be using a map, but I am relatively novice coder, and I just can't seem to get the syntax right.

Thanks in advance for your help!

I've pasted my service class below with a few comments:
public with sharing class autoAddProductsAfterPBChange {

//create a filter to listen for a change in the pricebook below
      public static list<opportunity> filterOpp(map<id, opportunity> oldMap, list<opportunity> newList) {
        list<opportunity> temp=new list<opportunity>();
        for (opportunity newOpp : newList){
            if (oldMap.get(newOpp.id).PriceBook2Id != newOpp.PriceBook2Id){
                temp.add(newOpp);
            }
        }
        return temp;
    }        

//find the pricebook entries and recreate the OLIs   
    public static void autoAdd(list<Opportunity> opps){
        Opportunity opp = new Opportunity(); 
        Pricebook2 pb = new Pricebook2();    
        for(Opportunity opp2 : opps){
            opp.id = opp2.Id;
            pb.id = opp2.Pricebook2Id;
        }
        list<OLI_Clone__c> olics = [SELECT Quantity__c, Additional_Discount_off_List__c, Manual_Discount__c, Opportunity__c, Product__c, Sales_Price__c, Service_Term_in_Months__c
                                                     FROM OLI_Clone__c
                                                     WHERE Opportunity__c =: opp.id];
        list<Id> prodids = new list<Id>();
        for(OLI_Clone__c olicprod : olics){
            prodids.add(olicprod.Product__c);
        }
        List<PricebookEntry>pbeids = [SELECT Id, Product2Id
                           			         FROM PricebookEntry
                                                         WHERE Product2Id in: prodids AND Pricebook2Id =: pb.id];
 		Map<Id, PricebookEntry> pbeMap = new Map<Id, PricebookEntry>(pbeids);  // Is this map correct? 
 		list<OpportunityLineItem>toInsert = new list<OpportunityLineItem>();
        for(OLI_Clone__c olic : olics){
            if(pbeMap.containsKey(olic.Product__c)){
                OpportunityLineItem oli = new OpportunityLineItem();
                PricebookEntry pbe = pbeMap.get(); // I know I need to be "getting" something here but I'm not sure how to structure the syntax, and I'm not sure that my map above is configured correctly either.  Basically I need to get the correct PricebookEntryId based on the Product__c field on the OLI_Clone__c in this loop and the parent Opportunity's pricebook.
                oli.Quantity = olic.Quantity__c;
                oli.UnitPrice = olic.Sales_Price__c;
                toInsert.add(oli);
            }
        }
        insert toInsert;
	}

}




 

I have a requirement to default the Company field on Lead creation page to First Name +" "+ Last Name as soon as user enters the Last Name. I am trying to use VisualForce actionSupport for the same. But rerender does not seem to work for me. I am attaching my code below. Any help would be much appreciated.

Visualforce Page:-

 
<apex:page standardController="Lead" extensions="leadControllerExtension">
    <apex:sectionHeader title="{!$ObjectType.Lead.label} Edit" subtitle="{!IF(ISNULL(Lead.name), 'New Lead', Lead.name)}"/>
    <apex:form >
        <apex:pageBlock mode="edit" title="{!$ObjectType.Lead.label} Edit">
            <apex:pageblockbuttons >
                <apex:commandbutton value="Save" action="{!Save}"/>
                <apex:commandbutton value="Cancel" action="{!Cancel}"/>
            </apex:pageblockbuttons>
           
             <apex:pageblocksection id="LeadInformationPBS" title="Lead Information">
             <!-- Make Owner field editable -->
             <apex:inputfield value="{!Lead.OwnerId}"></apex:inputfield>
             <apex:inputfield value="{!Lead.Phone}"></apex:inputfield>
 
             <!-- Since we need to group two input fields together we need a pageBlockSectionItem with an Output panel.  We also needed to create a label so we know what field we are entering in -->
             <apex:pageblocksectionitem >
             <apex:outputlabel value="{!$ObjectType.Lead.Fields.FirstName.label}"></apex:outputlabel>
             <apex:outputpanel >
             <apex:inputfield value="{!Lead.Salutation}"></apex:inputfield>
             <apex:inputfield value="{!Lead.FirstName}"></apex:inputfield>
             </apex:outputpanel>
             </apex:pageblocksectionitem>
             <apex:inputfield value="{!Lead.MobilePhone}"></apex:inputfield>
            
          
             <apex:inputfield value="{!Lead.LastName}">
             <apex:actionSupport event="onchange" reRender="CompanyDef" action="{!getCompany}"/>
             </apex:inputfield>
           
             <apex:inputfield value="{!Lead.Fax}"></apex:inputfield>
            
            
             <apex:inputField value="{!Lead.Company}" id="CompanyDef">
            
            
            
             </apex:inputField>
           
             <apex:inputfield value="{!Lead.Email}" required="true"></apex:inputfield>
            
             <apex:inputfield value="{!Lead.Title}"></apex:inputfield>
             <apex:inputfield value="{!Lead.Website}"></apex:inputfield>
            
             <apex:inputfield value="{!Lead.Leadsource}"></apex:inputfield>
             <apex:inputfield value="{!Lead.Status}"></apex:inputfield>
            
             <!-- <apex:inputField value="{!Lead.Campaign}" />
             Campaign field is not able to be used unless you write your own custom class/method to create a campaign member
             Post explaining this issue: http://boards.developerforce.com/t5/Apex-Code-Development/Cannot-Access-to-Campaign-Field-from-Lead-Object/td-p/161715
             -->
             <apex:inputfield value="{!Lead.Rating}"></apex:inputfield>
            
             <apex:inputfield value="{!Lead.Industry}"></apex:inputfield>
             <apex:inputfield value="{!Lead.NumberOfEmployees}"></apex:inputfield>
            </apex:pageblocksection>
          
       
        </apex:pageBlock>
    </apex:form>

</apex:page>

Controller:-

public class leadControllerExtension {

    transient public Lead lead {get; set;}
    transient public String Company {get; set;}
   
    // The extension constructor initializes the private member
    // variable acct by using the getRecord method from the standard
    // controller.
    public leadControllerExtension(ApexPages.StandardController stdController) {
        this.lead = (Lead)stdController.getRecord();
    }

    public String getCompany() {
    
     Company = lead.FirstName + ' ' + lead.LastName;
    
     Company='Hello Wprld';
       return (Company);
    }
}