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
Daniel MuirDaniel Muir 

quote line number trigger

Hi all,

We are wanting to use a trigger that will number each quote line item, for each quote. 

The current auto-number system is not of use as the numbers do not reset, and as far as i have read, a trigger is the only option (flows were the other option, but they create severe inconvinence when adding individual lines). 

I have tried the code provided in the below link, but it did not seem to work for us. 

https://developer.salesforce.com/forums/?id=9060G000000BhAkQAK
 
Nayana KNayana K
public class QuoteLineItemHandler
{
	public void onBeforeInsert(List<QuoteLineItem> lstNewQLI)
	{
		incrementNumberRespectiveToQuote(lstNewQLI);
	}
	
	private void incrementNumberRespectiveToQuote(List<QuoteLineItem> lstNewQLI)
	{
		Set<Id> setQuoteId = new Set<Id>();
		Map<Id, Integer> mapQuoteIdToMaxNumber = new Map<Id, Integer>();
		
		// gather IDs first of quotes
		for(QuoteLineItem objQLI : lstNewQLI) 
		{
			setQuoteId.add(objQLI.QuoteId);
		}

		if (!setQuoteId.isEmpty()) 
		{
			for (AggregateResult ar : [	SELECT QuoteId, MAX(Item_Numbering__c)
										FROM QuoteLineItem
										GROUP BY QuoteId
										WHERE QuoteId IN: setQuoteId])  
			{
				mapQuoteIdToMaxNumber.put((Id)ar.get('QuoteId'), (Integer)ar.get('expr0'));
			}
			
			for(QuoteLineItem objQLI : lstNewQLI) 
			{
				//  if a QLI is already present for the quote.
				if(mapQuoteIdToMaxNumber.containsKey(objQLI.QuoteId))
				{
					mapQuoteIdToMaxNumber.put(objQLI.QuoteId, mapQuoteIdToMaxNumber.get(objQLI.QuoteId)+1);
				}
				// if this current QLI is the first QLI of the quote.
				else
				{
					mapQuoteIdToMaxNumber.put(objQLI.QuoteId, 1);
				}
				objQLI.Item_Numbering__c = mapQuoteIdToMaxNumber.get(objQLI.QuoteId);
			}
		}
	}
}
 
trigger QuoteLineItemTrigger on QuoteLineItem (before insert)
{ 
	QuoteLineItemHandler objHandler = new QuoteLineItemHandler();
	
	if(Trigger.isBefore && Trigger.isInsert)
	{
		objHandler.onBeforeInsert(Trigger.New);
	}    
}

Can you please try this and let me know. (Just written for insert use case)
Daniel MuirDaniel Muir
Hi Nayana, 

The following error appears: Error: Compile Error: unexpected token: 'WHERE' at line 24 column 40
Nayana KNayana K
for (AggregateResult ar : [	SELECT QuoteId, MAX(Item_Numbering__c)
										FROM QuoteLineItem
                                                                                WHERE QuoteId IN: setQuoteId
										GROUP BY QuoteId
										])  
			{
				mapQuoteIdToMaxNumber.put((Id)ar.get('QuoteId'), (Integer)ar.get('expr0'));
			}

Hey my Bad, query syntax was wrong before :(
Daniel MuirDaniel Muir
Thats great. The Public class saved succesfully following your changes and the creation of a custom object to match item numbering, so no issues there now :)

The trigger returns the following error: Error: Compile Error: unexpected token: for at line 1 column 0
Nayana KNayana K
public class QuoteLineItemHandler
{
	public void onBeforeInsert(List<QuoteLineItem> lstNewQLI)
	{
		incrementNumberRespectiveToQuote(lstNewQLI);
	}
	
	private void incrementNumberRespectiveToQuote(List<QuoteLineItem> lstNewQLI)
	{
		Set<Id> setQuoteId = new Set<Id>();
		Map<Id, Integer> mapQuoteIdToMaxNumber = new Map<Id, Integer>();
		
		// gather IDs first of quotes
		for(QuoteLineItem objQLI : lstNewQLI) 
		{
			setQuoteId.add(objQLI.QuoteId);
		}
		
		if (!setQuoteId.isEmpty()) 
		{
			system.debug('====setQuoteId===='+setQuoteId);
			for (AggregateResult ar : [	SELECT QuoteId, MAX(Item_Numbering__c)
										FROM QuoteLineItem
										WHERE QuoteId IN: setQuoteId
										GROUP BY QuoteId
										])  
			{
				mapQuoteIdToMaxNumber.put((Id)ar.get('QuoteId'), (Integer)ar.get('expr0'));
			}
			system.debug('====mapQuoteIdToMaxNumber===='+mapQuoteIdToMaxNumber);
			for(QuoteLineItem objQLI : lstNewQLI) 
			{
				//  if a QLI is already present for the quote.
				if(mapQuoteIdToMaxNumber.containsKey(objQLI.QuoteId))
				{
					mapQuoteIdToMaxNumber.put(objQLI.QuoteId, mapQuoteIdToMaxNumber.get(objQLI.QuoteId)+1);
				}
				// if this current QLI is the first QLI of the quote.
				else
				{
					mapQuoteIdToMaxNumber.put(objQLI.QuoteId, 1);
				}
				objQLI.Item_Numbering__c = mapQuoteIdToMaxNumber.get(objQLI.QuoteId);
			}
			system.debug('====lstNewQLI===='+lstNewQLI);
		}
	}
}

Not sure why you are getting that error. I have added debugs in the code. Can you please post debug log after running the trigger. I will be able understand what's the cause.
Daniel MuirDaniel Muir
Hi Nayana, 

It has saved now. Something copied in with the code was all. 

Just need to test it now. 
Daniel MuirDaniel Muir
Hi Nayana, 
The codes work in my sandbox. 
They number each product line in the order in which the products are selected. 
The only issues is when the items are sorted. Then you may get lines 1, 4, 5, 3, 2 (example). 
Its much more useful than what already exists though! :)  
Nayana KNayana K
The only issues is when the items are sorted. Then you may get lines 1, 4, 5, 3, 2 (example).

I have not understood this part. Can you please share screen shot on what it means exactly? 

Glad that it helped to some extent. Please mark the answer as best if you feel it is worth.
Daniel MuirDaniel Muir
The first image is the way it looks once the products are selected. The second shows what happens if the products are moved around using the "sort" button.
Another issue i have noticed that has popped up is that all products have to be entered at the same time. If you were to want to add an extra product later you need to create an entire new quote. I've posted the error underneath the image files. 
User-added imageUser-added image
User-added image