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
John BraunJohn Braun 

Creating Multiple Quotes against an opportunity WITHOUT copying existing quote line items



I was wondering if anyone has ran into this business requirement:


Currently, using native functionality, if you use products and pricebooks with quotes and the syncing functionality - everytime you create a new quote against an opportunity, it will automatically copy the existing quote line items from the synced quote into the newly created quote.


We have a business requirement for which we do NOT want to copy the existing quote line items into the new quote. Has anyone found a way around this? Thanks for any help!!!!

Boom B OpFocusBoom B OpFocus

Hi Johh,


You will need to write code for that.  There will be 1 class and 2 triggers.  Oh and a custom checkbox field in Quote if you want to give users a choice to copy the Line Items when create a new quote.


Class Util

public class Util{
	private static Set<Id> newQuoteIds = new Set<Id>();
	public static Set<Id> getNewQuoteIds() {
        return newQuoteIds;
	public static void addNewQuoteId(Id id) {
        public static void removeAllNewQuoteIds(Set<Id> ids) {

 Quote trigger:

trigger Quote on Quote (after insert) {
	if (Trigger.isAfter && Trigger.isInsert) {
Set<Id> setOppIds = new Set<Id>(); for (Quote quote : {
// Check to see if the quote is created and Don't copy OLIs is true if (quote.Don_t_copy_OLIs__c == true) setOppIds.add(quote.OpportunityId); } List<Opportunity> lstOpps = [select Id, HasOpportunityLineItem from Opportunity where Id in:setOppIds]; for (Opportunity opp : lstOpps) { for (Quote quote : {
if (opp.HasOpportunityLineItem) Util.addNewQuoteId(quote.Id); // Add the Id of the Quote that created from Opportunity that has Line Items to the NewQuoteIds cached in the Util class } } } }

 QuoteLineItem trigger: 

trigger QLI on QuoteLineItem (before insert, after insert) {
	if (Trigger.isAfter && Trigger.isInsert) {
		Set<Id> setQuoteIds = new Set<Id>();
		for (QuoteLineItem qli : {
			if (Util.getNewQuoteIds().contains(qli.QuoteId)) {
		if (!setQuoteIds.isEmpty()) {
			List<QuoteLineItem> lstQLIsTodelete = [select Id from QuoteLineItem where QuoteId in :setQuoteIds];
			delete lstQLIsTodelete; // Delete the QLIs that automatically created from creating a new Quote from Opportunity with Line Items
			Util.removeAllNewQuoteIds(setQuoteIds); // Remove Quote Ids from the Util class, so the trigger won't fire when we create a new Line Item for quote later


 I hope this is what you are looking for.


Boom B,


Would this work if you do not want the initial quote to carry over the products that have been added to the opportunity.  


We are looking to create an opportunity and add products to it, but then create a quote, but not have the products on the opportunity added to the quote.



Boom B OpFocusBoom B OpFocus
Yes, this would work.
Joe BubelJoe Bubel
I did this by mistake... this will create a new quote for an oppty, and wipe out any Oppty Products
Opportunity myOpp = [Select id, pricebook2id from Opportunity where id = '006g0000008Zct2'];

Quote testQuote = new quote();'TEST QUOTE';;
testQuote.opportunityid =;

insert testQuote;;
update myOpp;

What I want, is the opposite.  I want to mimick the New Quote button where the exiting Oppty Products are automatically created on the New Quote.