Automatically generate quotelineitem on first save of quote

  • 2
  • Question
  • Updated 8 months ago
  • Answered
I want to replicate the Salesforce quote generation and automation of quotelineitem records when saving a new quotel. The Quotelineitems should replicate the opportunitylineitem records. Seems like quite a lot of configuration is required in Skuid to match what Salesforce have built.

I'm guessing this has been done in the past as it's standard Salesforce functionality, so wondered if anybody had some XML they could send across please?

If not, would anyone be able to guide me through the steps of adding quotelineitems to a quote once the quote record has been saved? The quote is being generated through a pageinclude on the opportunity page where I pass it the opportunity Id through a query string
Photo of Glenn Daly

Glenn Daly

  • 1,270 Points 1k badge 2x thumb

Posted 9 months ago

  • 2
Photo of Bill McCullough

Bill McCullough, Champion

  • 12,436 Points 10k badge 2x thumb
Glenn,

I had a page that was pretty close.  I added a script to generate the quote lines from the opportunity line items.  This should get you going.

Be aware that there may be some settings on this page that were peculiar to my use case.  You may want to grab any pieces that you need and add them to your page.

Thanks,

Bill

<skuidpage unsavedchangeswarning="yes" personalizationmode="server" showsidebar="true" showheader="true" tabtooverride="Quotes">
    <models>
        <model id="Product2" limit="1" query="true" createrowifnonefound="false" sobject="Product2" datasource="salesforce">
            <fields>
                <field id="Id"/>
            </fields>
            <conditions>
                <condition type="fieldvalue" value="Service" enclosevalueinquotes="true" field="Name"/>
            </conditions>
            <actions/>
        </model>
        <model id="SelectedOpportunity" limit="1" query="true" createrowifnonefound="false" sobject="Opportunity" doclone="no" datasource="salesforce">
            <fields>
                <field id="Name"/>
                <field id="Id"/>
                <field id="AccountId"/>
                <field id="Account.Name"/>
                <field id="Account.ShippingCity"/>
                <field id="Account.ShippingCountry"/>
                <field id="Account.ShippingStreet"/>
                <field id="Account.ShippingState"/>
                <field id="Account.BillingCity"/>
                <field id="Account.BillingState"/>
                <field id="Account.BillingStreet"/>
                <field id="Account.BillingPostalCode"/>
            </fields>
            <conditions>
                <condition type="param" value="oppid" field="Id" operator="=" enclosevalueinquotes="true" novaluebehavior="noquery"/>
            </conditions>
            <actions/>
        </model>
        <model id="CurrentPriceBook" limit="1" query="true" createrowifnonefound="false" sobject="Pricebook2" doclone="no" datasource="salesforce">
            <fields>
                <field id="Id"/>
                <field id="Name"/>
                <field id="IsActive"/>
            </fields>
            <conditions>
                <condition type="fieldvalue" value="true" enclosevalueinquotes="false" field="IsActive" state=""/>
                <condition type="fieldvalue" value="Standard Price Book" enclosevalueinquotes="true" field="Name"/>
            </conditions>
            <actions/>
        </model>
        <model id="Quote" limit="1" query="false" createrowifnonefound="true" sobject="Quote" datasource="salesforce">
            <fields>
                <field id="Name"/>
                <field id="CreatedDate"/>
                <field id="QuoteNumber"/>
                <field id="OpportunityId"/>
                <field id="Opportunity.Name"/>
                <field id="AccountId"/>
                <field id="Account.Name"/>
                <field id="BillingCity"/>
                <field id="BillingName"/>
                <field id="BillingStreet"/>
                <field id="BillingPostalCode"/>
                <field id="Status"/>
                <field id="Description"/>
                <field id="Subtotal"/>
                <field id="ContactId"/>
                <field id="Contact.Name"/>
                <field id="Contact.Phone"/>
                <field id="Contact.Fax"/>
                <field id="Contact.Email"/>
                <field id="Contact.AccountId"/>
                <field id="Contact.Account.Name"/>
                <field id="Pricebook2Id"/>
                <field id="Pricebook2.Name"/>
                <field id="NewField" uionly="true" displaytype="FORMULA" readonly="true" returntype="TEXT">
                    <formula>{{$Param.lastname}}+', '+{{$Param.firstname}}+MONTH(TODAY())+'/'+DAY(TODAY())+'/'+YEAR(TODAY())</formula>
                </field>
                <field id="BillingState"/>
                <field id="Contact.Id"/>
                <field id="Id"/>
                <field id="BillingCountryCode"/>
                <field id="BillingCountry"/>
            </fields>
            <conditions>
                <condition type="modelmerge" value="" field="Pricebook2Id" state="" operator="=" model="CurrentPriceBook" enclosevalueinquotes="true" mergefield="Id" novaluebehavior="deactivate"/>
                <condition type="modelmerge" value="" field="OpportunityId" operator="=" novaluebehavior="deactivate" state="" model="SelectedOpportunity" enclosevalueinquotes="true" mergefield="Id"/>
                <condition type="modelmerge" value="" field="AccountId" state="" operator="=" model="SelectedOpportunity" enclosevalueinquotes="true" mergefield="AccountId" novaluebehavior="deactivate"/>
                <condition type="fieldvalue" value="Draft" enclosevalueinquotes="true" field="Status" state=""/>
                <condition type="modelmerge" value="" field="Name" operator="=" model="SelectedOpportunity" enclosevalueinquotes="true" mergefield="Name" novaluebehavior="deactivate"/>
            </conditions>
            <actions>
                <action>
                    <actions>
                        <action type="setCondition" fieldmodel="Quote" field="BillingCity" enclosevalueinquotes="true" value="{{ContactId}}" model="LookupContact" condition="Id"/>
                        <action type="requeryModels" model="LookupOpp" behavior="standard">
                            <models>
                                <model>LookupContact</model>
                            </models>
                        </action>
                        <action type="updateRow" fieldmodel="Quote" field="BillingStreet" enclosevalueinquotes="true" value="{{$Model.LookupContact.data.0.Address1__c}} {{$Model.LookupContact.data.0.Address2__c}} {{$Model.LookupContact.data.0.Address3__c}}"/>
                        <action type="updateRow" fieldmodel="Quote" field="BillingCity" enclosevalueinquotes="true" value="{{$Model.LookupContact.data.0.City__c}}"/>
                    </actions>
                    <events>
                        <event>row.updated</event>
                    </events>
                    <fields>
                        <field>ContactId</field>
                    </fields>
                </action>
            </actions>
        </model>
        <model id="QuoteLines" limit="20" query="true" createrowifnonefound="false" sobject="QuoteLineItem" orderby="LineNumber ASC" doclone="" processonclient="false" datasource="salesforce">
            <fields>
                <field id="Description"/>
                <field id="Quantity"/>
                <field id="Id"/>
                <field id="Discount"/>
                <field id="TotalPrice"/>
                <field id="LineNumber"/>
                <field id="ListPrice"/>
                <field id="Product2Id"/>
                <field id="Product2.Name"/>
                <field id="UnitPrice"/>
                <field id="SortOrder"/>
                <field id="Subtotal"/>
                <field id="QuoteId"/>
                <field id="Quote.Name"/>
                <field id="PricebookEntryId"/>
                <field id="PricebookEntry.Name"/>
                <field id="TotalQuoteLine" uionly="true" displaytype="FORMULA" label="Total" precision="9" scale="2" readonly="true" returntype="CURRENCY">
                    <formula>({{UnitPrice}}*{{Quantity}})*(1-({{Discount}}/100))</formula>
                </field>
            </fields>
            <conditions>
                <condition type="modelmerge" value="" field="QuoteId" operator="=" model="Quote" enclosevalueinquotes="true" mergefield="Id" novaluebehavior="noquery" state=""/>
                <condition type="blank" value="null" field="Discount" operator="!=" enclosevalueinquotes="false" state="filterableoff" inactive="true" name="DiscountNotNull"/>
            </conditions>
            <actions>
                <action>
                    <actions>
                        <action type="setCondition" model="PriceBookEntryCurrentRow" condition="Product2Id2Select" value="{{Product2Id}}"/>
                        <action type="requeryModel" model="PriceBookEntryCurrentRow" behavior="standard"/>
                        <action type="updateRow" fieldmodel="QuoteLines" field="PricebookEntryId" enclosevalueinquotes="true" value="{{$Model.PriceBookEntryCurrentRow.data.0.Id}}"/>
                        <action type="updateRow" fieldmodel="QuoteLines" field="Description" enclosevalueinquotes="true" value="{{$Model.PriceBookEntryCurrentRow.data.0.Name}}"/>
                    </actions>
                    <events>
                        <event>row.updated</event>
                    </events>
                    <fields>
                        <field>Product2Id</field>
                    </fields>
                </action>
            </actions>
        </model>
        <model id="PriceBookEntryCurrentRow" limit="1" query="false" createrowifnonefound="false" sobject="PricebookEntry" doclone="no" datasource="salesforce">
            <fields>
                <field id="Pricebook2Id"/>
                <field id="Pricebook2.Name"/>
                <field id="Product2Id"/>
                <field id="Product2.Name"/>
                <field id="Id"/>
                <field id="UnitPrice"/>
                <field id="Name"/>
            </fields>
            <conditions>
                <condition type="modelmerge" value="" field="Pricebook2Id" operator="=" model="CurrentPriceBook" enclosevalueinquotes="true" mergefield="Id" novaluebehavior="deactivate"/>
                <condition type="fieldvalue" value="" enclosevalueinquotes="true" field="Product2Id" state="filterableoff" inactive="true" name="Product2Id2Select"/>
            </conditions>
            <actions/>
        </model>
        <model id="OppLineItems" limit="20" query="true" createrowifnonefound="false" datasource="salesforce" sobject="OpportunityLineItem">
            <fields>
                <field id="ServiceDate"/>
                <field id="Discount"/>
                <field id="Description"/>
                <field id="ListPrice"/>
                <field id="OpportunityId"/>
                <field id="Opportunity.Name"/>
                <field id="Name"/>
                <field id="PricebookEntryId"/>
                <field id="PricebookEntry.Name"/>
                <field id="Product2Id"/>
                <field id="Product2.Name"/>
                <field id="Quantity"/>
            </fields>
            <conditions>
                <condition type="param" value="oppid" field="OpportunityId" fieldtargetobjects="Opportunity" operator="=" enclosevalueinquotes="true" novaluebehavior="noquery"/>
            </conditions>
            <actions/>
        </model>
    </models>
    <components>
        <pagetitle model="Quote" uniqueid="sk-1_6aMy-75">
            <maintitle>
                <template>{{Name}}</template>
            </maintitle>
            <subtitle>
                <template>{{Model.label}}</template>
            </subtitle>
            <actions>
                <action type="multi" label="Save" icon="sk-icon-save" uniqueid="sk-3xNtiu-197">
                    <actions>
                        <action type="blockUI" message="Saving quote..."/>
                        <action type="save">
                            <models>
                                <model>Quote</model>
                            </models>
                            <onerroractions>
                                <action type="blockUI" message="There was an error" timeout="3000"/>
                                <action type="unblockUI" message="There was an error" timeout="3000"/>
                            </onerroractions>
                        </action>
                        <action type="updateRow" fieldmodel="QuoteLines" field="QuoteId" enclosevalueinquotes="true" value="{{$Model.Quote.data.0.Id}}"/>
                        <action type="save">
                            <models>
                                <model>QuoteLines</model>
                            </models>
                        </action>
                        <action type="redirect" window="self" url="{{#$Param.retURL}}{{$Param.retURL}}{{/$Param.retURL}}{{^$Param.retURL}}/apex/skuid__ui?page=ViewQuote&amp;id={{Id}}{{/$Param.retURL}}"/>
                        <action type="unblockUI"/>
                    </actions>
                    <hotkeys>
                        <hotkey modifiers="ctrl" key="s"/>
                    </hotkeys>
                </action>
                <action type="multi" label="Cancel" icon="sk-icon-cancel" uniqueid="sk-3xNtiy-200">
                    <actions>
                        <action type="cancel">
                            <models>
                                <model>Quote</model>
                                <model>QuoteLines</model>
                            </models>
                        </action>
                        <action type="redirect" window="self" url="{{#$Param.retURL}}{{$Param.retURL}}{{/$Param.retURL}}{{^$Param.retURL}}/{{Model.KeyPrefix}}/o{{/$Param.retURL}}"/>
                    </actions>
                </action>
            </actions>
        </pagetitle>
        <basicfieldeditor showheader="true" showsavecancel="false" showerrorsinline="true" model="Quote" buttonposition="" uniqueid="sk-1_A8nk-377" mode="edit" layout="">
            <columns>
                <column width="50%">
                    <sections>
                        <section title="Basics" collapsible="no">
                            <fields>
                                <field id="QuoteNumber" valuehalign="" type="" uniqueid="sk-3xNtjC-209"/>
                                <field id="Name" valuehalign="" type="" uniqueid="sk-3xNtjD-212"/>
                                <field id="OpportunityId" valuehalign="" type="" optionsource="" displaytemplate="{{Name}}" searchtemplate="{{Name}}" uniqueid="sk-3xNtjE-215">
                                    <searchfields/>
                                    <filters>
                                        <filter type="multiple" operator="in" field="RecordType.Name" value="" enclosevalueinquotes="true">
                                            <values>
                                                <value>IM Patients</value>
                                            </values>
                                        </filter>
                                    </filters>
                                </field>
                            </fields>
                        </section>
                        <section title="Prepared For" collapsible="no">
                            <fields>
                                <field id="ContactId" valuehalign="" type="" optionsource="" uniqueid="sk-3xNtjI-220">
                                    <label>Contact</label>
                                    <searchfields/>
                                </field>
                                <field id="Contact.Email" valuehalign="" type="" uniqueid="sk-3xNtjJ-223"/>
                            </fields>
                        </section>
                    </sections>
                </column>
                <column width="50%">
                    <sections>
                        <section title="Status" collapsible="no">
                            <fields>
                                <field id="Status" valuehalign="" type="" uniqueid="sk-3xNtjO-229"/>
                                <field id="Description" valuehalign="" type="" uniqueid="sk-3xNtjQ-232"/>
                            </fields>
                        </section>
                        <section title="Bill to" collapsible="no">
                            <fields>
                                <field id="BillingStreet" uniqueid="sk-3xNtjU-237"/>
                                <field id="BillingCity" valuehalign="" type="" uniqueid="sk-3xNtjV-240"/>
                                <field id="BillingState" valuehalign="" type="" uniqueid="sk-3xNtjW-243"/>
                                <field id="BillingPostalCode" uniqueid="sk-3xNtjY-246"/>
                                <field id="BillingCountry" uniqueid="sk-3xNtjZ-249"/>
                            </fields>
                        </section>
                    </sections>
                </column>
            </columns>
        </basicfieldeditor>
        <skootable showconditions="true" showsavecancel="false" showerrorsinline="true" searchmethod="server" searchbox="false" showexportbuttons="false" pagesize="10" createrecords="true" model="QuoteLines" buttonposition="" mode="read" uniqueid="sk-1_DtBl-207" instantfilters="false" emptysearchbehavior="query">
            <fields>
                <field id="Product2Id" uniqueid="sk-3xNtjl-255" pagesize="5" redirecttype="datasourcedefault">
                    <searchfields/>
                </field>
                <field id="UnitPrice" allowordering="true" columnwidth="10%" uniqueid="sk-3xNtjm-258"/>
                <field id="Quantity" allowordering="true" columnwidth="10%" uniqueid="sk-3xNtjn-261"/>
                <field id="Discount" allowordering="true" columnwidth="10%" uniqueid="sk-3xNtjo-264"/>
                <field id="TotalQuoteLine" decimalplaces="" valuehalign="" type="" columnwidth="10%" uniqueid="sk-3xNtjq-267">
                    <summaries>
                        <summary>sum</summary>
                    </summaries>
                </field>
            </fields>
            <rowactions>
                <action type="edit"/>
                <action type="delete"/>
            </rowactions>
            <massactions usefirstitemasdefault="true">
                <action type="massupdate"/>
                <action type="massdelete"/>
            </massactions>
            <views>
                <view type="standard"/>
            </views>
            <searchfields/>
            <filters>
                <filter type="toggle" filteroffoptionlabel="New Filter" createfilteroffoption="true" affectcookies="false" autocompthreshold="25" conditionsource="manual" labelmode="auto" label="Only Discounted LInes">
                    <effects>
                        <effect action="activate" value="" condition="DiscountNotNull"/>
                    </effects>
                </filter>
            </filters>
        </skootable>
    </components>
    <resources>
        <labels/>
        <css/>
        <javascript>
            <jsitem location="inline" name="createQuoteLines" cachelocation="false" url="">(function(skuid){
var $ = skuid.$;
$(document.body).one('pageload',function(){
        var opplines = skuid.model.map().OppLineItems;
        var quotelines = skuid.model.map().QuoteLines;
        
        console.log(opplines);
        
        var j=1;
        $.each(opplines.data, function(i, v) {
           
           quotelines.createRow({
               
               doAppend: true,
               additionalConditions: [
                   
                   {field: 'Product2Id', value: v.Product2Id},
                   {field: 'UnitPrice', value: v.ListPrice},
                   {field: 'Quantity', value: v.Quantity},
                   {field: 'Discount', value: v.Discount}
        
                ]
           });
           i++;
        });
});
})(skuid);</jsitem>
        </javascript>
        <actionsequences uniqueid="sk-3xPilc-624"/>
    </resources>
    <styles>
        <styleitem type="background" bgtype="none"/>
    </styles>
</skuidpage>
Photo of Glenn Daly

Glenn Daly

  • 1,270 Points 1k badge 2x thumb
Thanks very much, i've been able to apply this and it's working great!