function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Complete noviceComplete novice 

Pricebook error on code to replicate quote

Hi, I am a complete coding novice and have hit a problem with code written by my predecessor in my test org.

Opportunities have a field called 'renew with what year' which is a picklist of future years. When the opp is closed and 2017 is selected in this field, the code creates a new opportunity and adds the products from the 2017 price book. It is also meant to replicate any quote attached to the opportunity.

It works ok in production but we have activated multi currency in our test org and this caused the code to fail. Salesforce support fixed it so that the opportunity is replicated fine if there isn't a quote attached (thier comment was 'you were trying to update the list which is not possible. So you have to update the record instead of list'), but it still won't work if the opportunity has a quote attached.

The error I get is:  Error:Apex trigger RenewOp6 caused an unexpected exception, contact your administrator: RenewOp6: execution of BeforeUpdate caused by: System.DmlException: Insert failed. First exception on row 1; first error: FIELD_INTEGRITY_EXCEPTION, The pricebook entry is in a different pricebook than the one assigned to the Quote, or Quote has no pricebook assigned.: Price Book Entry ID: [PricebookEntryId]: Trigger.RenewOp6: line 99, column 1

This is the portion of code that doesn't work:

//If there is a Syncing Quote create a new quote on the new opp and add same details to the new quote
IF(o.SyncedQuoteId!=null)
{    
List<Quote> Q = [select id, Account_Joining_Count__c, Which_Billing_address_should_be_used__c
                 from Quote
                 where IsSyncing =:true and Opportunity.Id =:o.Id limit 1];   
      Quote NQ = New Quote();
        NQ.Opportunityid = op.Id;
            NQ.Which_Billing_address_should_be_used__c = Q[0].Which_Billing_address_should_be_used__c;
        NQ.Contract_Start_Date__c = op.CloseDate;
        NQ.Contract_End_Date__c = op.Asset_Expires_When__c;
        NQ.Name = op.Name;
        NQ.Pricebook2Id=PBE[0].Pricebook2Id;
      Insert NQ;
list<QuoteLineItem> QLI = new list <QuoteLineItem>();
QuoteLineItem QOL = New QuoteLineItem();
FOR(PricebookEntry PE :PBE){
    FOR(OpportunityLineItem OL :OLI){
    IF(PE.Product2Id == OL.PricebookEntry.Product2Id){
        QOL = New QuoteLineItem();
            QOL.Quoteid = NQ.id;
            QOL.PricebookEntryId = PE.id;
            system.debug('gggggggggggg'+PE.id);
            QOL.Quantity = OL.Quantity;
            IF(o.Use_New_Pricebook_Values__c == true)
                QOL.UnitPrice = PE.UnitPrice;
                else
                
                    QOL.UnitPrice = OL.UnitPrice * IncPerAsDec;
                
           QLI.add(QOL);
        }
    }

}
Insert QLI;

Can anyone suggest what I need to do to get the quote to recognise the pricebook please?  Bearing in mind I don't speak code... :(
Abhilash Mishra 13Abhilash Mishra 13
Well looking at the error it seems ,  your pricebookentry  variable PBE is using a different pricebook than the one used by quotes. Can you check the pricebook value in both the object
Complete noviceComplete novice
Sorry, how do I check that?  The opportunity is creating the correct price book but I don't know how to make the quote use the same one.  The thing that confuses me as well is that this works perfectly fine in Production (single currency) just not in Test (multi currency).
Abhilash Mishra 13Abhilash Mishra 13
go to workbench, and Run a query for  pricebook2id in  Quote. you will come to know which pricebook is set in Quotes. 
All you need is to verify that same pricebook is being  everywhere.
 
Complete noviceComplete novice
Thank you for your help.  I have to confess I needed to Google 'Workbench' :)
I've run the query and it returned a list of 52 pricebook2ids.  Because the code is meant to work on all pricebooks, I can't hard code it by adding a particular ID in, and in our production org it doesn't have any IDs in the code.
It is meant to use the pricebook from the original opportunity and the year from the 'renew with what year' field, to identify the correct price book for next year.  I can't understand why it's not working in the sandbox but it does in production. :(
Abhilash Mishra 13Abhilash Mishra 13
its not like you have to hardcode code it. you just need to ensure.
pricebook from the original opportunity, pricebook from the quotes, and pricebook2id of pricebook2Entry of QuoteLineItem, they must be same.

I guess enabling the multicurrency has created a logical bug in some where in your code. You just need to find a way to get all those correctly.

Let me know if you need more help.

Regards
Abhilash Mishra

 
Abhilash Mishra 13Abhilash Mishra 13
List<Quote> Q = [select id, Account_Joining_Count__c, Which_Billing_address_should_be_used__c
                 from Quote
                 where IsSyncing =:true and Opportunity.Id =:o.Id limit 1];   
      Quote NQ = New Quote();
        NQ.Opportunityid = op.Id; // pricebook of this opportunity

            NQ.Which_Billing_address_should_be_used__c = Q[0].Which_Billing_address_should_be_used__c;
        NQ.Contract_Start_Date__c = op.CloseDate;
        NQ.Contract_End_Date__c = op.Asset_Expires_When__c;
        NQ.Name = op.Name;
        NQ.Pricebook2Id=PBE[0].Pricebook2Id; // this pricebook
      Insert NQ;

list<QuoteLineItem> QLI = new list <QuoteLineItem>();
QuoteLineItem QOL = New QuoteLineItem();
FOR(PricebookEntry PE :PBE){
    FOR(OpportunityLineItem OL :OLI){
    IF(PE.Product2Id == OL.PricebookEntry.Product2Id){
        QOL = New QuoteLineItem();
            QOL.Quoteid = NQ.id;
            QOL.PricebookEntryId = PE.id;  // and pricebook of this PE (means pricebook of All the PBE)
            system.debug('gggggggggggg'+PE.id);
            QOL.Quantity = OL.Quantity;
            IF(o.Use_New_Pricebook_Values__c == true)
                QOL.UnitPrice = PE.UnitPrice;
                else
                
                    QOL.UnitPrice = OL.UnitPrice * IncPerAsDec;
                
           QLI.add(QOL);
        }
    }

}
Insert QLI;


Pricebooks of these bold lines must be same but i guess  they are not  and that is what creating and error this is the reason of Error.
 
Complete noviceComplete novice
Thank you, I understand what you mean.  The original opportunity and quote references pricebook Sales 2016. The new opportunity references pricebook Sales 2017, I know that works fine.  I think that the new quote is trying to reference the original price book, Sales 2016, rather than the new one, Sales 2017.  I just don't know how to make it look at the right one.

Thank tou for taking the time to explain, it's helped me understand what it means. I think I need to get someone in to help me fix it.
Abhilash Mishra 13Abhilash Mishra 13
Hi,
I am happy to help. please  upvote the answers if they helped you. 
Let me know if you need more help. 
you can also contact me on abhilash.udit@gmail.com directly. if you can not share code here.

Regards
Abhilash Mishra