How to Create Quote and QuoteLineItem From Opportunity in Lightning Web Component – LWC Salesforce | How to add and delete rows dynamically in lightning web component | How to create multiple records dynamically with custom functionaliy in LWC

3,409 views

Hey guys, today in this post we are going to learn about How to Create Quote and QuoteLineItem From Opportunity in Lightning Web Component – LWC Salesforce.

Quote Line Items are automatically created when the Quote is created from an Opportunity based on the Opportunity Products attached to that Opportunity. Creating a Quote from an Opportunity in Classic always results in Quote Line Items created but in Lightning for the same record it is possible that no Quote Line Items are created. To know more about Quote and QuoteLineItem, Click Here.

 

 

Final Output →

Why Should You Schedule Meeting?

🎯 If You Are Facing Any Of These 6 Challenges. Schedule Meeting With Me.

  • Learn Salesforce Development
  • Career Confusion
  • No Interview Call
  • Low Salary
  • No Promotion/Growth
  • No Finding New Job Opportunity
  • Why you stucking from past so many years in same company?

 

Create Quote and QuoteLineItem From Opportunity -- w3web.net

 

You can download file directly from github by Click Here.

 
 

Other related post that would you like to learn in Salesforce

 

  • Find the below steps ▾

 

Create Lightning Web Component HTML

Step 1:- Create Lightning Web Component : createQuoteAndLineItemLwc.html

SFDX:Lightning Web Component >> New >> createQuoteAndLineItemLwc.html

createQuoteAndLineItemLwc.html [Lightning Web Component HTML]

  1.    <template>
  2.  
  3.   <lightning-card title="Create Quote and Quote Line Item from Opportunity" icon-name="custom:custom17">
  4.       <div class="slds-p-around_medium">
  5.         <div class="slds-m-bottom_large">
  6.           <h2 class="slds-section-title--divider"><strong>Quote</strong></h2>
  7.         </div>
  8.       <table border="0" cellspacing="0" cellpadding="0" style="border-collapse:collapse;">
  9.         <tr >
  10.             <td>
  11.               <div style="height: 600px; overflow:auto; width:100%;">
  12.                   <table border="0" cellspacing="0" cellpadding="0" style="border-collapse:collapse;">
  13.                       <tr for:each={oppProductLineItemArr} for:item='optFormData' key={rowId} for:index='index' >
  14.                           <td>
  15.                           <form data-name="opptForm">
  16.  
  17.                               <div class="slds-grid slds-wrap">
  18.                                   <div class="slds-col slds-size_6-of-12">
  19.                                   <div class="slds-form-element_controller">
  20.                                       <label class="slds-form-element__label">Name</label>
  21.                                       <lightning-input type="text" class="inpFld" data-type="input-field"
  22.                                       name="Name" value={optFormData.Name} style="width: 200px;">
  23.                                       </lightning-input>
  24.                                   </div>
  25.                                 </div> 
  26.  
  27.                                 <div class="slds-col slds-size_6-of-12">
  28.                                   <div class="slds-form-element_controller">
  29.                                       <label class="slds-form-element__label">Quote</label>
  30.                                       <lightning-input type="text" class="inpFld" data-type="input-field"
  31.                                       name="OpportunityId" value={optFormData.Id} data-inx={index} style="width: 200px;">
  32.                                   </lightning-input>
  33.                                   </div>
  34.                                 </div>
  35.  
  36.                                 <div class="slds-col slds-size_6-of-12">
  37.                                   <div class="slds-form-element_controller">
  38.                                       <label class="slds-form-element__label">Description</label>
  39.                                       <lightning-input type="text" class="inpFld" data-type="input-field"
  40.                                       name="Description" value={optFormData.Description} style="width: 200px;">
  41.                                       </lightning-input>
  42.                                   </div>
  43.                                 </div> 
  44.  
  45.                                 <div class="slds-col slds-size_6-of-12">
  46.                                   <div class="slds-form-element_controller">
  47.                                       <label class="slds-form-element__label">Pricebook2Id</label>
  48.                                       <lightning-input type="text" class="inpFld" data-type="input-field"
  49.                                       name="Pricebook2Id" value={Pricebook2Id} style="width: 200px;">
  50.                                       </lightning-input>
  51.                                   </div>
  52.                                 </div>
  53.                               </div>
  54.  
  55.                         </form>    
  56.                           </td>
  57.                       </tr>
  58.                   </table>        
  59.  
  60.                   <div class="slds-m-bottom_large">
  61.                     <h2 class="slds-section-title--divider slds-m-top_large"><strong>Quote Line Item</strong></h2>
  62.                   </div>
  63.             <div class="slds-m-around--x-small container-fluid">
  64.                 <div class="slds-float_right slds-p-bottom_small">
  65.                     <h1 class="slds-page-header__title">
  66.                         <lightning-button-icon icon-name="utility:add" value="Add Quote Line Item"  size="large" variant="brand" alternative-text="Add" onclick={addRow}> Add Quote Line Item </lightning-button-icon>
  67.                     </h1>
  68.                 </div>
  69.                 <div class="container-fluid">        
  70.                     <table class="slds-table slds-table_bordered slds-table_cell-buffer"> 
  71.                             <template for:each={quoteLineItemList} for:item="qItem" for:index="indx">
  72.                                 <tr key={qItem.key} id={qotLine.key}> 
  73.                                     <td class="slds-hide">{indx}</td>                                                  
  74.  
  75.                                     <td>
  76.                                       <p>Description:- <lightning-input class="reqInpFld" data-id={indx} value={qItem.Description} onchange={handleDescriptionChange}></lightning-input></p>
  77.  
  78.                                     </td>
  79.                                     <td>
  80.                                       <p>UnitPrice:- <lightning-input class="reqInpFld" data-id={indx} value={qItem.UnitPrice} onchange={handleUnitPriceChange}></lightning-input></p>
  81.  
  82.                                     </td>
  83.                                     <td>
  84.                                       <p>Quantity:- <lightning-input class="reqInpFld" data-id={indx} value={qItem.Quantity} onchange={handleQuantityChange}></lightning-input></p>
  85.  
  86.                                     </td>
  87.                                     <td style="display:none;">
  88.                                       <p>QuoteId:- <lightning-input class="reqInpFld" data-id={indx} value={quoteRecId}></lightning-input></p>
  89.                                     </td>
  90.                                     <td>
  91.                                       <p>Product2Id:- <lightning-input class="reqInpFld" data-id={indx} value={Product2Id}></lightning-input></p>
  92.                                     </td>
  93.  
  94.                                     <td>
  95.                                         <div class="slds">
  96.                                           <br/><br/>
  97.                                           <lightning-button-icon icon-name="utility:delete"
  98.                                                                                     data-id={indx}       
  99.                                                                                     alternative-text="Delete"     
  100.                                                                                     class="slds-m-left_xx-small"
  101.                                                                                     onclick={removeRow} 
  102.                                                                                     title="Delete"></lightning-button-icon>
  103.                                         </div>
  104.                                     </td>
  105.  
  106.  
  107.                                 </tr>
  108.                             </template>
  109.  
  110.  
  111.                     </table>
  112.  
  113.                 </div>
  114.             </div>
  115.  
  116.             <!--End Line Item--> 
  117.  
  118.  
  119.  
  120.  
  121.  
  122.                     <!--Start Save Button--> 
  123.                     <div class="slds-align_absolute-center slds-p-top_small">                
  124.                         <lightning-button name="Save" variant="brand" label="Save" onclick={saveRecord} ></lightning-button>
  125.                     </div>
  126.  
  127.                     <!--End Save Button--> 
  128.               </div>
  129.           </td>
  130.     </tr>
  131. </table>
  132. </div>
  133.  
  134. </lightning-card>
  135.  
  136. </template>

 

Create Lightning Web Component JavaScript

Step 2:- Create Lightning Web Component : createQuoteAndLineItemLwc.js

SFDX:Lightning Web Component >> New >> createQuoteAndLineItemLwc.js

createQuoteAndLineItemLwc.js [LWC JavaScript File]

  1.    import { LightningElement, track,api, wire  } from 'lwc';
  2. import { getRecord } from 'lightning/uiRecordApi';
  3. import submitOptRecord from '@salesforce/apex/createQuoteAndLineItemLwcCtrl.submitOptRecord';
  4. import getOpportunityList from '@salesforce/apex/createQuoteAndLineItemLwcCtrl.getOpportunityList';
  5. import saveQuoteLineItem from '@salesforce/apex/createQuoteAndLineItemLwcCtrl.saveQuoteLineItem';
  6.  
  7. //import NAME_FIELD from '@salesforce/schema/QuoteLineItem.Name';
  8. import Description_FIELD from '@salesforce/schema/QuoteLineItem.Description';
  9. import UnitPrice_FIELD from '@salesforce/schema/QuoteLineItem.UnitPrice';
  10. import Quantity_FIELD from '@salesforce/schema/QuoteLineItem.Quantity';
  11. import { ShowToastEvent } from 'lightning/platformShowToastEvent';
  12. import {NavigationMixin} from 'lightning/navigation';
  13.  
  14. export default class CreateQuoteAndLineItemLwc extends NavigationMixin(LightningElement)  {
  15.  
  16.     @track quoteLineItemList = []; 
  17.  
  18.     @track index = 0;
  19.     @api recordId;    
  20.     @api quoteRecId;
  21.    // @track name = NAME_FIELD;
  22.     @track Description = Description_FIELD;
  23.     @track UnitPrice = UnitPrice_FIELD;
  24.     @track Quantity = Quantity_FIELD;
  25.     @track quoteLineRecoreId;
  26.     @track message; 
  27.     @track error;
  28.     isLoaded = false;
  29.  
  30.     @track optItemList ;
  31.     @track oppProductLineItemArr=[];
  32.     @track optFormData = {};
  33.     @track Product2Id= '01t5g000003OxvQAAS';
  34.     @track PricebookEntryId='01u5g000003gfcsAAA';
  35.     @track Pricebook2Id='01s5g00000KmN13AAF';
  36.  
  37.  
  38.  
  39.         //Start ConnectedCallback
  40.  
  41.         connectedCallback() {
  42.  
  43.  
  44.  
  45.         }
  46.  
  47.  
  48.  
  49.         @wire(getOpportunityList,{recId:'$recordId'})
  50.         getInfos({error,data}){
  51.         if(error){
  52.             console.log('error == '+JSON.stringify(error));
  53.         }else if(data){
  54.             console.log('data == ', JSON.stringify(data));
  55.             this.oppProductLineItemArr = JSON.parse(JSON.stringify(data));
  56.  
  57.           return;
  58.  
  59.         }
  60.     }
  61.  
  62.  
  63.  
  64.  
  65.   //Start Quote
  66.  
  67.  
  68.  
  69. //Start Quote Line Item
  70.    // acc
  71.     qotLine = {
  72.         Name : this.name,      
  73.         Description : this.Description,       
  74.         UnitPrice : this.UnitPrice,
  75.         Quantity : this.Quantity, 
  76.         QuoteId : '',
  77.         Product2Id :this.Product2Id,    
  78.         PricebookEntryId :this.PricebookEntryId,
  79.         key : ''
  80.     }
  81.  
  82.  
  83.  
  84.     addRow(){
  85.  
  86.         this.index++;
  87.  
  88.         var i = this.index;
  89.  
  90.  
  91.         this.qotLine.key = i;
  92.         this.quoteLineItemList.push(JSON.parse(JSON.stringify(this.qotLine)));
  93.  
  94.         console.log('Enter ',this.quoteLineItemList);
  95.  
  96.  
  97.     }
  98.  
  99.     removeRow(event){
  100.         this.isLoaded = true;
  101.         var selectedRow = event.currentTarget;
  102.         var key = selectedRow.dataset.id;
  103.         if(this.quoteLineItemList.length>1){
  104.             this.quoteLineItemList.splice(key, 1);
  105.             this.index--;
  106.             this.isLoaded = false;
  107.         }else if(this.quoteLineItemList.length == 1){
  108.             this.quoteLineItemList = [];
  109.             this.index = 0;
  110.             this.isLoaded = false;
  111.         }
  112.  
  113.  
  114.     } 
  115.  
  116.  
  117.  
  118.     handleNameChange(event) {
  119.         var selectedRow = event.currentTarget;
  120.         console.log('selectedRow_! ' + selectedRow );
  121.         var key = selectedRow.dataset.id;
  122.         var accountVar = this.quoteLineItemList[key];
  123.         this.quoteLineItemList[key].Name = event.target.value;
  124.       console.log('handleNameChange# ' + this.quoteLineItemList[key].Name);
  125.     }
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.     handleDescriptionChange(event) {
  135.         var selectedRow = event.currentTarget;
  136.         var key = selectedRow.dataset.id;
  137.         var lineItemVar = this.quoteLineItemList[key];
  138.         this.quoteLineItemList[key].Description = event.target.value;
  139.     }
  140.  
  141.  
  142.     handleUnitPriceChange(event) {
  143.         var selectedRow = event.currentTarget;
  144.         var key = selectedRow.dataset.id;
  145.         var lineItemVar = this.quoteLineItemList[key];
  146.         this.quoteLineItemList[key].UnitPrice = event.target.value;
  147.     }
  148.  
  149.  
  150.     handleQuantityChange(event) {
  151.         var selectedRow = event.currentTarget;
  152.         var key = selectedRow.dataset.id;
  153.         var lineItemVar = this.quoteLineItemList[key];
  154.         this.quoteLineItemList[key].Quantity = event.target.value;
  155.     }
  156.  
  157.  
  158.  
  159.     //Start Quote Javascript
  160.  
  161.  
  162.     //Start Quote and Quote Lline Item Save Functionality 
  163.     saveRecord(){        
  164.  
  165.  
  166.  
  167.       //Start Quote  
  168.  
  169.         let flag = true;
  170.  
  171.         for (const elem of [...this.template.querySelectorAll('form[data-name="opptForm"] [data-type="input-field"]')]) {
  172.             this.optFormData[elem.name] = elem.value;
  173.             console.log('aaaaa' , elem.value);
  174.         }
  175.  
  176.         console.log('optFormData## ', this.optFormData);
  177.         console.log('optFormDataStringyFy',JSON.stringify(this.optFormData));
  178.  
  179.         const data = {
  180.             optDataFyObj: this.optFormData, 
  181.  
  182.         };
  183.  
  184.         console.log('optDataFyObj## ',JSON.stringify(data));
  185.  
  186.         //if(flag){
  187.             const result = submitOptRecord({
  188.                 jsonDataStr: JSON.stringify(data)
  189.             })
  190.             .then(result => {
  191.                 //resultData1 =JSON.stringify(result);
  192.                 console.log('result1' , JSON.parse(result));
  193.                // console.log('result1_A' , result);
  194.                 this.quoteJsonData = result[0].Id;
  195.                 console.log('quoteJsonData' , this.quoteJsonData);
  196.                 console.log('result2', result[0].id);
  197.                 var quoteId;
  198.                 var obj = JSON.parse(result, function (key, value) {
  199.                     if(key == 'id' && value != undefined &&  value != null) {
  200.                     console.log('Quote id '+ key+'   :: '+value);
  201.                     quoteId = value;
  202.  
  203.                     }
  204.  
  205.                   });
  206.  
  207.  
  208.                  console.log('quoteId 175 #' + quoteId );
  209.                   this.quoteRecId=quoteId;
  210.  
  211.                   for(let i of this.quoteLineItemList){
  212.  
  213.                    i['QuoteId'] =quoteId;
  214.                   i['Name'] =quoteId;
  215.  
  216.                     console.log('aaa Item_' + JSON.stringify(i)); 
  217.  
  218.                   }
  219.  
  220.                    console.log('quoteLineItemListQQ ' + this.quoteLineItemList);
  221.                   //Start Qoute Line Item 
  222.                         saveQuoteLineItem({quoteItemList : this.quoteLineItemList})
  223.                         .then(result => {
  224.                             console.log('result_11' , JSON.parse(result));
  225.                             this.quoteLineRecoreId = result.Id;
  226.                             console.log('resultId ' + result[0].Id);
  227.                             console.log('quoteLineRecoreId@@@ ' + this.quoteLineRecoreId);
  228.                             this.message = result;
  229.                             this.error = undefined;
  230.  
  231.                         })
  232.                         .catch(error => {
  233.                             this.message = undefined;
  234.                             this.error = error;                            
  235.                             console.log("error", JSON.stringify(this.error));
  236.                         });
  237.  
  238.                         //End Qoute Line Item 
  239.  
  240.                        //Start Toast Message 
  241.                         const toastEvent = new ShowToastEvent({
  242.                             title:'Success!',
  243.                             message:'Record created successfully',
  244.                             variant:'success'
  245.                           });
  246.                           this.dispatchEvent(toastEvent);
  247.  
  248.                           //End Toast Message
  249.  
  250.                         /*Start Navigation*/
  251.                         this[NavigationMixin.Navigate]({
  252.                             type: 'standard__recordPage',
  253.                             attributes: {
  254.                                 recordId: quoteId,
  255.                                 objectApiName: 'Quote',
  256.                                 actionName: 'view'
  257.                             },
  258.                         });
  259.                         /*End Navigation*/ 
  260.  
  261.             });
  262.         //}
  263.  
  264.       //End Quote
  265.  
  266.     }
  267. }

 

Create Lightning Web Component Meta XML

Step 3:- Create Lightning Web Component : createQuoteAndLineItemLwc.js-meta.xml

SFDX:Lightning Web Component >> New >> createQuoteAndLineItemLwc.js-meta.xml

createQuoteAndLineItemLwc.js-meta.xml [LWC Meta Data XML]

  1.  <?xml version="1.0" encoding="UTF-8"?>
  2. <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
  3.     <apiVersion>56.0</apiVersion>
  4.     <isExposed>true</isExposed>
  5.     <targets>
  6.         <target>lightning__AppPage</target>
  7.         <target>lightning__HomePage</target>
  8.         <target>lightning__RecordPage</target>
  9.         <target>lightning__RecordAction</target>
  10.         <target>lightning__UtilityBar</target>
  11.     </targets>
  12.     <targetConfigs>
  13.  
  14.         <targetConfig targets="lightning__AppPage, lightning__HomePage, lightning__RecordPage">
  15.             <supportedFormFactors>                
  16.                 <supportedFormFactor type="Large" /> 
  17.                 <supportedFormFactor type="Small" />
  18.             </supportedFormFactors>
  19.         </targetConfig>
  20.     </targetConfigs>
  21. </LightningComponentBundle>

 

Create Apex Class Controller

Step 4:- Create Apex Controller : insertLookupFieldValueLwcCtrl.cls

SFDX:Create Apex Class >> New >> createQuoteAndLineItemLwcCtrl.cls

createQuoteAndLineItemLwcCtrl.cls [Apex Class]

  1.    public WITH sharing class createQuoteAndLineItemLwcCtrl {
  2.     public createQuoteAndLineItemLwcCtrl() {
  3.  
  4.     }
  5.  
  6.     @AuraEnabled(cacheable=TRUE)
  7.     public static List<Opportunity> getOpportunityList(Id recId){
  8.         List<Opportunity> optList = [SELECT Id, Name, Description FROM Opportunity WHERE Id=:recId];
  9.         RETURN optList;
  10.     }
  11.  
  12.      //START Quote
  13.  
  14.   @AuraEnabled
  15.   public static String  submitOptRecord(String jsonDataStr) {
  16.  
  17.       Map<String, Object> RESULT = NEW Map<String, Object>();
  18.       String DataRespoce ='';
  19.       try {
  20.           Map<String, Object> formDataMap = (Map<String, Object>)JSON.deserializeUntyped(jsonDataStr);
  21.  
  22.           Map<String, Object> OptDataMap = (Map<String, Object>)formDataMap.get('optDataFyObj');
  23.  
  24.          // Opportunity optObj = NEW Opportunity();
  25.           Quote optObj = NEW 	Quote();
  26.           optObj.Name = getStringValueFromMap(OptDataMap, 'Name');
  27.           optObj.OpportunityId = getStringValueFromMap(OptDataMap, 'OpportunityId');
  28.           optObj.Description = getStringValueFromMap(OptDataMap, 'Description');
  29.           optObj.Pricebook2Id = getStringValueFromMap(OptDataMap, 'Pricebook2Id');
  30.           List<DATABASE.SaveResult> insertResult = DATABASE.insert(NEW List<Quote>{optObj});
  31.  
  32.           DataRespoce =JSON.serialize(insertResult); 
  33.  
  34.  
  35.       }catch(Exception ex) {
  36.  
  37.           RESULT.put('status', 500);
  38.           RESULT.put('message', 'Exception ' + ex.getMessage() + ',line' + ex.getLineNumber());
  39.       }
  40.       RETURN DataRespoce;
  41.   }
  42.  
  43.  
  44.   public static String getStringValueFromMap(Map<String, Object> dataMap, String fieldName) {
  45.       String VALUE;
  46.       try {
  47.           IF(dataMap.containsKey(fieldName)) {
  48.               VALUE = String.valueOf(dataMap.get(fieldName));
  49.           }
  50.  
  51.           VALUE = String.isEmpty(VALUE) ? VALUE :  String.valueOf(VALUE);
  52.       } catch(Exception ex) {
  53.           System.debug('Exception getValueFromMap : '+ ex.getMessage() + ' line ' + ex.getLineNumber());
  54.       }
  55.  
  56.       RETURN VALUE;
  57.   }
  58.  
  59.  
  60.  
  61.   public static DATE getDateValueFromMap(Map<String, Object> dataMap, String fieldName) {
  62.       DATE VALUE;
  63.       try {
  64.           String str;
  65.           IF(dataMap.containsKey(fieldName)) {
  66.               str = String.valueOf(dataMap.get(fieldName));
  67.           }
  68.  
  69.           VALUE = String.isEmpty(str) ? VALUE :  DATE.valueOf(str);
  70.       } catch(Exception ex) {
  71.           System.debug('Exception getIntValueFromMap : '+ ex.getMessage() + ' line ' + ex.getLineNumber());
  72.       }
  73.  
  74.       RETURN VALUE;
  75.   }
  76.  
  77.  
  78.  
  79.   //START Quote Line Item
  80.  
  81.  
  82.  
  83.   @AuraEnabled
  84.   public static void saveQuoteLineItem(List<QuoteLineItem> quoteItemList){
  85.       try {           
  86.          INSERT quoteItemList;
  87.          System.debug('quoteItemList## ' + quoteItemList);
  88.       }
  89.       catch(Exception ex) {
  90.           System.debug('Exception getValueFromMap : '+ ex.getMessage() + ' line ' + ex.getLineNumber());
  91.       }
  92.  
  93.  
  94.   } 
  95.  
  96. //END Quote Line Item
  97.  
  98. }

 

Further post that would you like to learn in Salesforce

 

 

Can I create quote without opportunity?

A quote is always associated with an opportunity. You can either create a quote for an existing opportunity or create a quote even without the existence of an opportunity for it. If you create a quote without a preexisting opportunity, the opportunity is automatically created when the quote is created.

What is quote and quote line in Salesforce?

Quote lines store information about products that a sales rep has quoted. With certain page layout and field-level security settings, some fields aren't visible or editable.

What is the difference between opportunity and quote?

An opportunity acts as a container for holding a quote or related alternative quotes that are to be presented to a customer. A quote, on the other hand, is a commercial document that allows a customer to see a predetermined set of products, their quantity, predetermined price, and delivery date.

Related Topics | You May Also Like

 
  

Our Free Courses →

👉 Get Free Course →

📌 Salesforce Administrators

📌 Salesforce Lightning Flow Builder

📌 Salesforce Record Trigger Flow Builder

👉 Get Free Course →

📌 Aura Lightning Framework

📌 Lightning Web Component (LWC)

📌 Rest APIs Integration




Hi, This is Vijay Kumar behind the admin and founder of w3web.net. I am a senior software developer and working in MNC company from more than 8 years. I am great fan of technology, configuration, customization & development. Apart of this, I love to write about Blogging in spare time, Working on Mobile & Web application development, Salesforce lightning, Salesforce LWC and Salesforce Integration development in full time. [Read full bio] | | The Sitemap where you can find all published post on w3web.net