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 '17 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. – Nate Briggs Oct 30 '17 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 '17 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. – Nate Briggs Oct 30 '17 at 20:13
  • cool - glad you figured it out – cropredy Oct 30 '17 at 21:16

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.

| improve this answer | |

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.

| improve this answer | |
  • 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. – Nate Briggs Oct 30 '17 at 14:23

Your Answer

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

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