I'm trying to clone an Opportunity and its Synced Quote along with the Quote Line Items associated with that Synced Quote, but I can't seem to insert the cloned Quote Line Items. It doesn't throw any errors when I run the Visualforce Page that calls the Apex function, and checking the debug logs tells me that the insert went fine, but when I look at the cloned Synced Quote or query for Quote Line Items I don't find the clones that I supposedly inserted.

Here is my code:

public class OpportunityExtension {
    private final Opportunity o;
    private final Quote activeQuote;
    private final List<QuoteLineItem> lineItems;

    public OpportunityExtension(apexpages.standardcontroller std) {
        this.o = (Opportunity)std.getrecord();
        this.activeQuote = this.o.SyncedQuote;
        List<Quote> temp = [SELECT (SELECT Description, Discount, Product2Id, PricebookEntryId, Quantity, UnitPrice, CurrencyIsoCode, ServiceDate, SortOrder, Subtotal FROM QuoteLineItems) FROM Quote WHERE Id = :activeQuote.Id];
        if (temp.get(0).QuoteLineItems != null) {
            this.lineItems = temp.get(0).QuoteLineItems;

    public PageReference cloneOpportunity() {
        Opportunity newO = new Opportunity(
            Type = o.Type,
            Name = o.Name + ' - CLONE',
            StageName = o.StageName,
            CurrencyIsoCode = o.CurrencyIsoCode,
            CloseDate = Date.today(),
            Account = o.Account,
            AccountId = o.AccountId

        insert newO;

        if (o.SyncedQuote != null) {
            Quote newQ = new Quote(
                Name = activeQuote.Name,
                Pricebook2Id = activeQuote.Pricebook2Id,
                opportunityId = newO.Id

            insert newQ;

            List<QuoteLineItem> newLineItems = new List<QuoteLineItem>();

            for (QuoteLineItem ql : lineItems) {

                QuoteLineItem newQL = ql.clone();

                newQL.QuoteId = newQ.Id;


            insert newLineItems;

            newO.SyncedQuoteId = newQ.Id;

            update newO;

        PageReference newPage = new PageReference('/'+newO.Id);


        return newPage;
  • You are masking the error - (1) wrap your DML logic in try-catch; (2) before trying, set a savepoint; in the catch, if an error, do a rollback; (3) in the catch, generate an apexPages.Message, return null and be sure you have <apex:pageMessages> on your VF page
    – cropredy
    Oct 27, 2017 at 0:03
  • I updated the code to include a try catch and a savepoint rollback, but it's not throwing anything. The page loads normally, and it takes me to the cloned Opportunity with the cloned Quote, but without any cloned QuoteLineItems even though the debug logs state that the QuoteLineItems cloned and inserted successfully. Oct 30, 2017 at 15:46
  • Since you are cloning the Opportunity but not OpportunityLineitems, is it possible that after cloning the Quote and QuoteLineItems that you have a process that runs later in time that copies the cloned Oppo's line items to the cloned quote's line items? -- and since the cloned Oppo has no line items, it wipes out the cloned quote's line items
    – cropredy
    Oct 30, 2017 at 16:23
  • I actually figured it out. We have a process that runs after I insert the QuoteLineItems, and because of the order in which I updated the opportunity with the quote id and inserted the QuoteLineItems, the line items were getting deleted because the opportunity didn't have a synced quote. I'll make an answer and choose it real quick. Oct 30, 2017 at 20:13
  • cool - glad you figured it out
    – cropredy
    Oct 30, 2017 at 21:16

2 Answers 2


Okay I figured this out. Turns out there's a process that gets called in our organization when I insert the Quote Line Items, which because I was inserting the Quote Line Items before giving the Opportunity a Synced Quote Id, the line items were getting deleted after being inserted.


Related objects are not automatically retrieved a controller extension, so your line

this.activeQuote = this.o.SyncedQuote;

will always result in a null object. Removing that line and changing your quote selector should fix it:

Quote activeQuote = [SELECT Name, Pricebook2Id, (SELECT Description, Discount, Product2Id, PricebookEntryId, Quantity, UnitPrice, CurrencyIsoCode, ServiceDate, SortOrder, Subtotal FROM QuoteLineItems) FROM Quote WHERE Id = :o.SyncedQuoteId];

Of course you need to change your temp and o.SyncedQuote references to activeQuote.

  • Doing it your way didn't solve the problem. On the Visualforce page, I put the SyncedQuote fields I needed, and the quote cloned correctly, sans the line items. What's strange is that the QuoteLineItems list has the correct length and states that it inserted correctly in the debug logs. I'll need to do what cropredy suggested in a comment to see if I can find anything out. Oct 30, 2017 at 14:23

You must log in to answer this question.

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