How To Generate Approval Required E-mail On Quote Save

If a client's workflow requires that the quote remains editable after being submitted for approval and notifications must be sent to the approvers, this can be achieved by generating the notification e-mails when the quote is saved (rather than submitted). The basic concept entails creating a “Submit To” flag with “Yes”/”No”/null options and a price parameter table to keep track of the generated e-mails (to prevent the e-mails from being generated more than once).

  • When the quote is saved with “Submit To” == null -> nothing happens.
  • When the quote is saved with “Submit To” == “Yes” -> a notification e-mail is generated to the appropriate parties and the quote gets entered into a tracking table to avoid duplicate e-mail generation.
  • When the quote is saved with “Submit To” == “No” -> the quote record is deleted from the tracking table so that when the quote is saved with “Submit To” == “Yes” the e-mail is generated again.

Create a Price Parameter MLTV table (in this case called “QuotesEmailSent”) as follows:


Create a Calculation Flow Logic with the following code: 

if (api.isSyntaxCheck()) return

def quotesSaved = true
int i = 0
int step = 200
def qs = []
def quotes = []
def table = api.findLookupTable("QuotesEmailSent")
def tableValues = api.findLookupTableValues("QuotesEmailSent")
def quoteList = []
//create a list of quotes in the PP tracking table
for (quote in tableValues) {

//find all users in the approver group

def ug = api.find("U", Filter.equal("groups.uniqueName", "Marketing Manager"))

//create the list of e-mails of the users in the approver group

def emailList = []

for (e in ug) {

//iterate over saved quotes

while (quotesSaved) {
  qs = api.find("Q", i, step, null)
  if (qs.size() != 0) {
    i += step
  } else {
    quotesSaved = false

/*Find the quotes with the “Submit To” flag switched to “Yes” that are not in the tracking table, 
and generate the e-mails adding the quote(s) to the tracking tables. 
Find the quotes with the “Submit To” flag switched to “No” and remove the quote(s) from the tracking table*/

  for (q in qs) {
    def clic = api.getCalculableLineItemCollection(q?.typedId)
    for (lineItem in clic?.lineItems) {
      		if (lineItem.folder) continue
	for (input in clic?.inputs) {

  		if ( == "submitForApproval" && input.value == "Yes" && !quoteList.contains(q.typedId)) {
          for (email in emailList) {
            api.sendEmail(email, "Submitted For Quote", "" + q.typedId + "&targetPage=priceShopPage#priceShopPage")
          	updateRecord = [lookupTableId :, "name" : q.typedId, "attribute1" : q.uniqueName, "attribute2" : q.lastUpdateDate]
          	api.addOrUpdate("MLTV", updateRecord)
        } else if ( == "submitForApproval" && input.value == "No") {
          existingRecord = [lookupTableId :, "name" : q.typedId, "attribute1" : q.uniqueName, "attribute2" : q.lastUpdateDate]
          api.delete("MLTV", existingRecord)

Create a calculation flow which will run this logic every 5 minutes (or as often as you and the client deem reasonable). 

In case there are more than one approval levels you will need to create a "Submit To" flag and a PP tracking table for each level.

The full code (including HTML formatting for the e-mail) is avaliable in Git - Copy_of_GenerateEmailOnQuoteSave_VA1.groovy