Monday, 24 February 2020

Salesforce Survey using Apex

How to Customize Salesforce Survey

Below are steps to enable Salesforce Survey and to use in LWC. Below Sample code will tell you how to Initiate a Salesforce Survey from Case Record. 

Step-1: Enable Salesforce Survey in Salesforce.
Setup-> quick find (Survey)->Survey Settings Enable


Step-2: Enable Community and activate community and give guest user profile access of following Object: Survey(READ), Survey Invitation (READ), Survey Response(READ,CREATE, EDIT)

click on Community ->Builder ->Administration-> Pages-> Goto Force.com-> Click on Public Access Settings-> Edit the Profile and give Object Access






Step-3: Data Model of Survey



Step-4: goto Survey Tab and create one Survey and make it active.



Step-5: Create a Case(Lookup) on Survey Invitation Object.

Step-6: Create this Exception Class:

public  class MyException extends Exception{}


Step-7: Create this LWC: sampleSurvey.html


<template>
    <lightning-button title="Click me" label="Click me" onclick={Opensurvey}></lightning-button>
</template>

Step-8: Create JS: sampleSurvey.js

import { LightningElementtrackapiwire } from 'lwc';
import CreateSurveyInvWrpResult from '@salesforce/apex/SampleSurveyController.CreateSurveyInvWrpResult';

export default class SampleSurvey extends LightningElement {
    @track weburl;
    @track error;
    @track msg;
    @api recordId;

    Opensurvey() {

        CreateSurveyInvWrpResult({ CaseId: this.recordId })
            .then(result => {
                this.msg = result;
                var obj = JSON.parse(JSON.stringify(this.msg));
                if (obj.bError == true) {
                    alert(obj.strMsg);
                }
                if (obj.bError == false) {
                    window.open(obj.strMsg);
                }
                this.error = undefined;
            })
            .catch(error => {
                this.msg = error;
                this.error = undefined;
                alert('In error' + this.msg);
            });
    }

}

Step-9: Create Apex class : SampleSurveyController.cls


public with sharing class SampleSurveyController {
    public SampleSurveyController() {
    }
    @AuraEnabled
    public static WrapperResult CreateSurveyInvWrpResult(String CaseId) {
        string CaseNumber;
        string communityId;
        string SurveyId;
        string ContactEmail;
        string ContactId;
        string surveyInvd;
        string strSurveyURL;

        communityId = [select Id from Network where Name = 'survey'].Id;
        SurveyId = [Select Id from Survey where Name = 'samplesurvey'].Id;
        WrapperResult WrpResult = new WrapperResult(nullnull);


        try {
            list<SurveyInvitationlstSurveyInv = [select id from SurveyInvitation where Case__c = :CaseId];
            if(lstSurveyInv.size() > 0) {
                throw new MyException('Survey for this case is already completed.');
            }

            SurveyInvitation SInv = New SurveyInvitation();
            Sinv.CommunityId = communityId;
            SInv.Name = caseId;
            SInv.Case__c = CaseId;
            //SInv.ParticipantId='0036g00000A04uWAAR';//userInfo.getUserId();
            SInv.OptionsCollectAnonymousResponse = true;
            SInv.OptionsAllowGuestUserResponse = true;
            SInv.SurveyId = SurveyId;
            insert SInv;

            SurveySubject SS = new SurveySubject();
            SS.SubjectId = CaseId;
            SS.ParentId = SInv.Id;
            SS.Name = CaseId;
            insert SS;

            SurveyInvitation sInvRecord = [Select idUUID from SurveyInvitation where id = :SInv.id];
            string UniquieInviteId = sInvRecord.UUID;
            //https://surveyamul-developer-edition.na174.force.com/survey/survey/runtimeApp.app?invitationId=0Ki6g000000DqqM&surveyName=samplesurvey&UUID=da11d795-ff3d-486e-819a-ffc08056234a

            strSurveyURLsystem.label.Survey_Base_URL + '' + SInvRecord.id + '&surveyName=samplesurvey&UUID=' + UniquieInviteId;
            system.debug('survey url' + json.serialize(strSurveyURL));
            WrpResultnew WrapperResult(falsestrSurveyURL);
            return WrpResult;
        } catch(exception e) {
            System.debug('The following exception has occurred while inserting SurveySubject: ' + e.getMessage());
            strSurveyURLe.getMessage();
            WrpResultnew WrapperResult(truee.getMessage());
            return WrpResult;
        } finally {
            return WrpResult;
        }
    }



    public class WrapperResult {
        @AuraEnabled public boolean bError { getset; }
        @AuraEnabled public string strMsg { getset; }
        public WrapperResult(boolean bErrstring strMessage) {
            this.bError = bErr;
            this.strMsg = strMessage;
        }
    }

}

Step-10: Enable the Above LWC page in Case Page Layout.




Step-11: On Click Me your Survey URL will open:




Tuesday, 7 January 2020

Salesforce CPQ Product Rule Vs Price Rule

CPQ: Product Rule Vs Price Rule

Product Rule:
1.Hide/Show Product
2.Add or remove Product
3.Validation Rule
4.Alert Message
5.Dynamic Product Filter

Price Rule:
1.Override the Quantity
2.Override the Price
3.Calculate and use for Rollup field value on Quote.
4.Used for Discounting



See Below Link for more Detail:













Product Rule:

Validation, alert, selection & Filter
Product Rule:

Validation, alert, selection & Filter

Product Rule:
Validation, alert, selection & Filter

Saturday, 1 June 2019

lightning:pillContainer and dialog(openModel or openPopup)

lightning:pillContainer and dialog(openModel or openPopup)





AddAttendees.cmp

<aura:component controller="AddAttendeesController" implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,force:lightningQuickAction" access="global" >
    <aura:attribute name="items" type="List" default="[
                                                      {
                                                      type: 'avatar',
                                                      href: '',
                                                      id: 'XX001',
                                                      label: 'Avatar Pill',
                                                      src: '/docs/component-library/app/images/examples/avatar2.jpg',
                                                      fallbackIconName: 'standard:user',
                                                      variant: 'circle',
                                                      alternativeText: 'User avatar',
                                                      },
                                                      {
                                                      type: 'icon',
                                                      href: '',
                                                      id: 'XX002',
                                                      label: 'Icon Pill',
                                                      iconName: 'standard:account',
                                                      alternativeText: 'Account',
                                                      },
                                                      ]"/>
    <aura:attribute name="isOpen" type="boolean" default="false"/>
    <aura:attribute name="issearching"    type="Boolean" default="false"/>
    <aura:attribute name="AttendeesList" type="List" />
    <aura:attribute name="Message" type="string" />
    <div class="slds-container_center slds-theme_shade">
        <lightning:card footer="Card Footer" title="Add Attendees">
            <aura:set attribute="actions">
                <lightning:button label="Add Attendees" onclick="{! c.openModel }" variant="brand"/>
            </aura:set>
            <p class="slds-p-horizontal_small">
                Attendees List
                <lightning:pillContainer items="{!v.items}" onitemremove="{!c.onRemovePill}"></lightning:pillContainer>
            </p>
        </lightning:card>
        <aura:if isTrue="{!v.isOpen}">
           
            <!--###### MODAL BOX Start######-->
            <section role="dialog" tabindex="-1" aria-labelledby="modal-heading-01" aria-modal="true" aria-describedby="modal-content-id-1" class="slds-modal slds-fade-in-open">
                <div class="slds-modal__container">
                    <!-- ###### MODAL BOX HEADER Start ######-->
                    <header class="slds-modal__header">
                        <lightning:buttonIcon iconName="utility:close"
                                              onclick="{! c.closeModel }"
                                              alternativeText="close"
                                              variant="bare-inverse"
                                              class="slds-modal__close"/>
                        <h2 id="modal-heading-01" class="slds-text-heading_medium slds-hyphenate">Search Attendees</h2>
                    </header>
                    <!--###### MODAL BOX BODY Part Start######-->
                    <div class="slds-modal__content slds-p-around_medium" id="modal-content-id-1">
                        <p><div onkeyup="{! c.handleKeyUp }">
                            <lightning:input
                                             aura:id="enter-search"
                                             name="enter-search"
                                             label="Search when user hits the 'enter' key"
                                             isLoading="{! v.issearching }"
                                             type="search"
                                             />
                            </div>
                        </p>
                        <div class="c-container">
                            <aura:iteration items="{!v.AttendeesList}" var="item" indexVar="count">
                               
                                <lightning:card title="{!item.RecordName}" iconName="{!item.IconName}">
                                    <aura:set attribute="actions">
                                        <lightning:button title="{!item.IconName}" name="{!item.RecordName}" onclick="{! c.AddRecordItem}" value="{!item.RecordId}" label="Add" iconName="action:new" iconPosition="left"  variant="brand" />
                                    </aura:set>
                                </lightning:card>
                               
                                <!--<lightning:card title="Hello" iconName="standard:avatar">
                            <aura:set attribute="actions">
                                 <lightning:button name="name1" value="value1" title="title1" label="Add" aura:Id="myId" iconName="action:new" iconPosition="left"  variant="brand" />
                            </aura:set>
                         </lightning:card>
                       
                        <lightning:card title="Hello" iconName="standard:groups">
                            <aura:set attribute="actions">
                                 <lightning:button label="Add" iconName="action:new" iconPosition="left"  variant="brand" />
                            </aura:set>
                         </lightning:card>-->
                            </aura:iteration>
                        </div>
                    </div>
                    <!--###### MODAL BOX FOOTER Part Start ######-->
                    <footer class="slds-modal__footer">
                        <lightning:button variant="neutral"
                                          label="Close"
                                          title="Close"
                                          onclick="{! c.closeModel }"/>
                       
                    </footer>
                </div>
            </section>
            <div class="slds-backdrop slds-backdrop_open"></div>
            <!--###### MODAL BOX Part END Here ######-->
           
        </aura:if>
        <div class="row">
            <lightning:textarea aura:id="TextMessage" class="slds-container_center slds-theme_shade slds-border_top slds-border_bottom slds-border_left slds-border_right" label="Message" placeholder="Message" variant="standard"></lightning:textarea>
        </div>
        <br></br>
        <lightning:button class="slds-m-bottom_small slds-theme_brand slds-size_1-of-1" variant="brand" label="Save" onclick="{!c.SaveEvent}"></lightning:button>
    </div>
</aura:component>

=======================================================================


AddAttendees.js



({
    openModel: function(component, event, helper) {
        // for Display Model,set the "isOpen" attribute to "true"
        component.set("v.isOpen", true);
    },
   
    closeModel: function(component, event, helper) {
        // for Hide/Close Model,set the "isOpen" attribute to "Fasle" 
        component.set("v.isOpen", false);
    },
   
    likenClose: function(component, event, helper) {
        // Display alert message on the click on the "Like and Close" button from Model Footer
        // and set set the "isOpen" attribute to "False for close the model Box.
        alert('thanks for like Us :)');
        component.set("v.isOpen", false);
       
       
       
    },
   
    onRemovePill:function(component,event,helper){
        var pillId = event.getParam('item').id;
        var myJSON = JSON.stringify(pillId);
        var pills = component.get('v.items');
        //alert(pillId);
        for (var i = 0; i < pills.length; i++) {
           
            if (pillId === pills[i].id) {
                pills.splice(i, 1);
                break;
           }
        }
       
        component.set('v.items', pills);
    },
    AddRecordItem: function(component,event,helper){
        //items
        //event.
        var btn=event.getSource();
        var recordname=btn.get('v.name');
        var recordId=btn.get('v.value');
        var varIconName=btn.get('v.title');
       
        //alert(recordname);
        var pills = component.get('v.items');
       
        var AlreadyAdded='';
        for (var i = 0; i < pills.length; i++) {
            if (recordId === pills[i].id) {
                AlreadyAdded='true';
                break;
            }
        }
       
        if(AlreadyAdded==''){
            pills.push({
                type: 'icon',
                id: recordId,
                label: recordname,
                iconName: varIconName
            });
           
            component.set('v.items', pills);
           
            var toastEvent = $A.get("e.force:showToast");
            toastEvent.setParams({
                title : 'Success Message',
                message:'Item added successfully.',
                messageTemplate: 'Item added successfully.',
                duration:' 5000',
                key: 'info_alt',
                type: 'success',
                mode: 'pester'
            });
            toastEvent.fire();
        }else if(AlreadyAdded=='true'){
            var toastEvent = $A.get("e.force:showToast");
            toastEvent.setParams({
                title : 'Error Message',
                message:'Item already added.',
                messageTemplate: 'Item already added.',
                duration:' 1000',
                key: 'info_alt',
                type: 'error',
                mode: 'pester'
            });
            toastEvent.fire();
        }       
       
       
    },
    SaveEvent: function(component,event,helper){
       
        var varMessage=component.find('TextMessage').get('v.value');
        var action= component.get("c.SaveRecord");
        var pills = component.get('v.items');
       
        action.setParams({
            'strMessage':varMessage
        });
       
        action.setCallback(this,function(response){
            var state = response.getState();
                if (state === "SUCCESS") {
                    var storeResponse = response.getReturnValue();
                        var varIsSuccess=storeResponse.bIsSuccess;
                        var varMessage=storeResponse.Message;
                        var varRecordId=storeResponse.RecordId;
                        if(varIsSuccess==true){
                            helper.helperToastMessage(varMessage,'success');
                        }else{
                            helper.helperToastMessage(varMessage,'error');
                        }
                 }else if (state === "INCOMPLETE") {
                    alert('Response is Incompleted');
                }else if (state === "ERROR") {
                    var errors = response.getError();
                    if (errors) {
                        if (errors[0] && errors[0].message) {
                            alert("Error message: " +
                                  errors[0].message);
                        }
                    } else {
                        alert("Unknown error");
                    }
                }
        });
        $A.enqueueAction(action);
    },
    handleKeyUp: function (component, event) {
        var isEnterKey = event.keyCode === 13;
        var queryTerm = component.find('enter-search').get('v.value');
        if (isEnterKey) {
           
            component.set('v.issearching', true);
            var action = component.get("c.fetchData");
            action.setParams({
                'searchKeyWord':queryTerm
            });
            action.setCallback(this, function(response) {
               
                var state = response.getState();
               
                if (state === "SUCCESS") {
                    var storeResponse = response.getReturnValue();
                   
                    // if storeResponse size is 0 ,display no record found message on screen.
                    if (storeResponse.length == 0) {
                        component.set("v.Message", true);
                    } else {
                        component.set("v.Message", false);
                    }
                   
                   
                   
                    // set searchResult list with return value from server.
                    component.set("v.AttendeesList", storeResponse);
                   
                   
                }else if (state === "INCOMPLETE") {
                    alert('Response is Incompleted');
                }else if (state === "ERROR") {
                    var errors = response.getError();
                    if (errors) {
                        if (errors[0] && errors[0].message) {
                            alert("Error message: " +
                                  errors[0].message);
                        }
                    } else {
                        alert("Unknown error");
                    }
                }
            });
            $A.enqueueAction(action);
            setTimeout(function() {
                //alert('Searched for "' + queryTerm + '"!');
                component.set('v.issearching', false);
            }, 1000);
           
        }
    }
})


========================================================================

AddAttendeesHelper.js



({
helperToastMessage : function(strmessage,strtype) {
var toastEvent = $A.get("e.force:showToast");
            toastEvent.setParams({
                title : 'Error Message',
                message:strmessage,
                messageTemplate: 'Item already added.',
                duration:' 1000',
                key: 'info_alt',
                type: strtype,
                mode: 'pester'
            });
            toastEvent.fire();
}
})



========================================================================
Apex class: AddAttendeesController 

public class AddAttendeesController {
   
    @AuraEnabled
    public static List <WrapperResult> fetchData(String searchKeyWord) {
       
        List <WrapperResult> LstWrapperResult=new List <WrapperResult>();
        string groupType='Regular';
        String newSearchText = '%'+searchKeyWord+'%';
       
       
        string SOQLUser='Select id, Name from User';
        SOQLUser=SOQLUser +' WHERE NAME LIKE:newSearchText';
        SOQLUser=SOQLUser +' LIMIT 5' ;
       
        string SOQLContact='Select id, Name from Contact';
        SOQLContact=SOQLContact +' WHERE NAME LIKE:newSearchText';
        SOQLContact=SOQLContact +' LIMIT 5' ;
       
        string SOQLPublicGroup='SELECT Id, Name FROM Group where Type=:groupType';
        SOQLPublicGroup=SOQLPublicGroup +' AND  NAME LIKE:newSearchText';
        SOQLPublicGroup=SOQLPublicGroup +' LIMIT 5' ;
       
       
       
        List<sObject> sobjListUser = Database.query(SOQLUser);
        List<sObject> sobjListContact = Database.query(SOQLContact);
        List<sObject> sobjListGroup = Database.query(SOQLPublicGroup);
       
        for(Object objUser:sobjListUser){
            WrapperResult WrpObj=new WrapperResult();
            User usr=(User)objUser;
           
            WrpObj.RecordId=usr.id;
            WrpObj.RecordName=usr.Name;
            WrpObj.IconName='standard:avatar';
           
            LstWrapperResult.add(WrpObj);
        }
        for(Object objContact:sobjListContact){
            WrapperResult WrpObj=new WrapperResult();
           
            Contact cont=(Contact)objContact;
           
            WrpObj.RecordId=cont.id;
            WrpObj.RecordName=cont.Name;
            WrpObj.IconName='standard:contact';
            LstWrapperResult.add(WrpObj);
        }
        for(Object ObjGroup:sobjListGroup){
            WrapperResult WrpObj=new WrapperResult();
           
            Group grp=(Group)ObjGroup;
           
            WrpObj.RecordId=grp.id;
            WrpObj.RecordName=grp.Name;
            WrpObj.IconName='standard:groups';
            LstWrapperResult.add(WrpObj);
        }
        return LstWrapperResult;
       
    }
   
    @AuraEnabled
    public static WrapperDataSaveResult SaveRecord(string strMessage){
        WrapperDataSaveResult SaveResult=new WrapperDataSaveResult();
        try{
           
            Event eve=new Event();
            eve.StartDateTime=system.now();
            eve.EndDateTime=system.now();
            eve.Subject='TEST 1223';
            eve.Description=strMessage;
            eve.WhatId='0010o00002MsOOSAA3';
           
            insert eve;
            SaveResult.RecordId=eve.Id;
               
            SaveResult.bIsSuccess=true;
            SaveResult.Message='Record created successfully.';
           
        }catch(exception ex){
            SaveResult.bIsSuccess=false;
            SaveResult.Message=ex.getMessage();
        }
       
        return SaveResult;
       
       
    }
   
   
    public class WrapperDataSaveResult{
        @AuraEnabled
        public string RecordId{get;set;}
        @AuraEnabled
        public string Message{get;set;}
        @AuraEnabled
        public boolean bIsSuccess{get;set;}
    }
   
    Public Class WrapperResult{
       
        @AuraEnabled
        public string RecordId{get;set;}
        @AuraEnabled
        public string RecordName{get;set;}
        @AuraEnabled
        public string IconName{get;set;}
       
       
    }
}


Tuesday, 11 December 2018

Lightning component button Create Child Record using Standard Layout

The purpose of this blog is to share you detail how to load Create child Record using Standard Layout using Lightning Action Button.


Here are the Relationship with Objects.

We are using following 3 Objects:
1. Account
2. Project
3. Invoice

Invoice has following relationship fields:

Account --Master -Detail
Project --Lookup

Project has following relationship fields:
Account--Lookup

So User can create Invoice Records from Project's Invoice Related list so while clicking on New Invoice button Project Lookup is filled but Account lookup is not autofilled. So in order to Create Invoice from Project and that new Invoice Record Layout must be defaulted with Project, Account and other detal from Project Record we will be create one Lightning Action button Project Object with following Lightning component. so without creating any server side apex controller we can use lightning data service to Read the records and then we can invoke the CreateRecord lightning enque action in JS. rest Salesforce will take care of it.

Please create following component.

CreateInvoice.cmp

<aura:component implements="force:lightningQuickActionWithoutHeader,force:hasRecordId" access="global" >
<aura:attribute name="project" type="Project_Custom__c"/>
    <aura:attribute name="projectObj" type="Project_Custom__c"/>
    <aura:attribute name="errorMessage" type="String"/>
    <force:recordData aura:id="accountRecordLoader"
        recordId="{!v.recordId}"
        fields="Customer__c,CurrencyIsoCode"
        targetRecord="{!v.project}"
        targetFields="{!v.projectObj}"
        targetError="{!v.errorMessage}"
        recordUpdated="{!c.doInit}"
    />   
</aura:component>


CreaInvoiceController.js

({
doInit : function(component, event, helper) {
        $A.get("e.force:closeQuickAction").fire();
        var eventParams = event.getParams();
        if(eventParams.changeType === "LOADED") {
            //console.log("account loaded:::::" + JSON.stringify(component.get("v.project")));
           
            var createRecordEvent = $A.get("e.force:createRecord");
            createRecordEvent.setParams({
                "entityApiName": "Invoice__c",
                "defaultFieldValues":{
                    "Account__c" : component.get("v.projectObj.Customer__c"),
                    "CurrencyIsoCode" : component.get("v.projectObj.CurrencyIsoCode"),
                    "Project__c" : component.get("v.recordId")
                }
            });
            createRecordEvent.fire();
           
        } else if(eventParams.changeType === "REMOVED") {
            // record is deleted and removed from the cache
        } else if(eventParams.changeType === "ERROR") {
            // there’s an error while loading, saving or deleting the record
        }
}
})

Create Lightning Action button on Project and select the component that you above has defined. and enable this new button on the Project Page Layout. Thanks


Friday, 7 December 2018

generate Access Token using Salesforce Connected App in SOAP UI Tool

Grab following detail from Salesforce connected app

Consumer Key
3MVG959Nd8JMmavT2IGqAtf_hIU.FqAPV7AEZHprq45mu1osf5eKlf.I7sUzaw3uafpK9CnpWQFr.vRWGqnkc


Consumer Secret
3083125027275927680

UserName:
UX@ux.com

password: 
PX00

Assuming login Access token for Sandbox:

Prepare following URL:


https://test.salesforce.com/services/oauth2/token?grant_type=password&client_id=3asdasdG959Nd8JMmavT2IGqAtf_hIU.FqAPV7AEZHprq45mu1osf5eKlf.vRWGqnkc&client_secret=3083125027275927680&username=UX@ux.compassword=PX00


Open your SOAP UI tool and Paste this URL in REST Project , choose POST method and hit run buton:





Saturday, 17 November 2018

Custom Template Salesforce CPQ. Visualforce CPQ custom Quote Template

Custom Template Salesforce CPQ: Visualforce CPQ custom Quote Template

In Salesforce while defining quote Template Admin can choose following type of template content:


In this Blog, we will learn and see how this custom Quote Template content will help in order to generate custom table, graphics in the same quote pdf doc file.

Definition from Salesforce CPQ( see Salesforce guide Book. Taken Reference from https://help.salesforce.com/articleView?id=cpq_template_content.htm&type=5)



 Custom
Select this option to use a Visualforce component in the Custom Source field that you want to show in this section of your quote template. Enter the full URL for the Visualforce page that generates this content, using the following format (page name must end with the “c__” prefix): https://c.<instance>.force.com/apex/c__OptivTemplateSectionComponent. The Visualforce component must be compatible with XML (specifically XSL-FO) to work with Salesforce QTC document output.

XSL-FO is just like HTML encoded language and we need undersatand how this language will help us in desining and defining custom tamplate. For more XSL-FO you can dig into following URL:

  1. https://www.webucator.com/tutorial/learn-xsl-fo/tables.cfm
  2. http://w3schools.sinsixx.com/xslfo/obj_table-header.asp.htm
  3. https://www.antennahouse.com/support/v2qa/QA-fo.html#QA2003082203
In this CPQ Custom template Blog page i would take one example and will see how this XSL-FO Santax we can use in Visualforce Page to generate pdf document: This pdf will show custom table as well as image while generating Quote pdf.

Sample VF Page:

This will display one Image on Top Right with Two Table

<apex:page showHeader="false" sidebar="false" cache="false"  contentType="text/xml" controller="CustomQuoteLineCtrl"  action="{!init}">

<block-container>

<block text-align="right">
<external-graphic src="https://cpqsep-dev-ed--c.ap4.content.force.com/servlet/servlet.ImageServer?id=0156F00000G41n0&oid=00D6F000002W0zo&lastMod=1541150013000"  content-height="scale-to-fit" height="1.5in"  content-width="2.00in" scaling="non-uniform"/>
</block>
<table border-bottom-style="solid" table-layout="fixed" width="100%" margin-top="10pt">
<table-header text-align="center" background-color="silver">
<table-cell display-align="center" padding="5" border="1pt solid  #800000"  number-columns-spanned="2">
<block font-weight="bold" text-align="left"><inline color="#FFFFFF">ANNUAL SERVICES</inline></block>
</table-cell>

</table-header>
<table-body>

<table-row border="1pt solid #800000">
<table-cell display-align="center" padding="5" border="1pt solid  #800000" background-color="#800000" >
<block font-weight="bold" text-align="left"><inline color="#FFFFFF">TierName Column Heading </inline></block>
</table-cell>
<table-cell display-align="center" padding="5" border="1pt solid  #800000" background-color="#800000">
<block font-weight="bold" text-align="left"><inline color="#FFFFFF">TierPrice Column Heading </inline></block>
</table-cell>
</table-row>
<table-row border="1pt solid #800000">
<table-cell display-align="center" padding="5" border="1pt solid  #800000">
<block text-align="left">TierName Column Heading </block>
</table-cell>
<table-cell display-align="center" padding="5" border="1pt solid  #800000">
<block  text-align="left">TierPrice Column Heading </block>
</table-cell>
</table-row>
<table-row border="1pt solid #800000">
<table-cell display-align="center" padding="5" border="1pt solid  #800000">
<block text-align="left">TierName Column Heading </block>
</table-cell>
<table-cell display-align="center" padding="5" border="1pt solid  #800000">
<block  text-align="left">TierPrice Column Heading </block>
</table-cell>
</table-row>
<table-row border="1pt solid #800000" >
<table-cell display-align="center" padding="5" border="1pt solid  #800000" number-columns-spanned="2"> 
<block  text-align="left">TierName Column Heading </block>
</table-cell>

</table-row>
</table-body>
</table>
</block-container>
<block-container  margin-top="40pt"> 
<table border-bottom-style="solid" table-layout="fixed" width="100%" >
<table-header text-align="center" background-color="silver">
<table-cell display-align="center" padding="5" border="1pt solid  #800000"  number-columns-spanned="2">
<block font-weight="bold" text-align="left"><inline color="#FFFFFF">PROFESSIONAL SERVICES</inline></block>
</table-cell>

</table-header>
<table-body>
<table-row border="1pt solid #800000">
<table-cell display-align="center" padding="5" border="1pt solid  #800000" background-color="#800000" >
<block font-weight="bold" text-align="left"><inline color="#FFFFFF">TierName Column Heading </inline></block>
</table-cell>
<table-cell display-align="center" padding="5" border="1pt solid  #800000" background-color="#800000">
<block font-weight="bold" text-align="left"><inline color="#FFFFFF">TierPrice Column Heading </inline></block>
</table-cell>
</table-row>
<table-row border="1pt solid #800000">
<table-cell display-align="center" padding="5" border="1pt solid  #800000">
<block text-align="left">TierName Column Heading </block>
</table-cell>
<table-cell display-align="center" padding="5" border="1pt solid  #800000">
<block  text-align="left">TierPrice Column Heading </block>
</table-cell>
</table-row>
<table-row border="1pt solid #800000">
<table-cell display-align="center" padding="5" border="1pt solid  #800000">
<block text-align="left">TierName Column Heading </block>
</table-cell>
<table-cell display-align="center" padding="5" border="1pt solid  #800000">
<block  text-align="left">TierPrice Column Heading </block>
</table-cell>
</table-row>
<table-row border="1pt solid #800000" >
<table-cell display-align="center" padding="5" border="1pt solid  #800000" number-columns-spanned="2"> 
<block  text-align="left">TierName Column Heading </block>
</table-cell>

</table-row>
</table-body>
</table>
</block-container>

</apex:page>
                 

Note: Plase save your images in document, and then copy the address of document Image and replace it with source Image Address. src.

<external-graphic src="https://cpqsep-dev-ed--c.ap4.content.force.com/servlet/servlet.ImageServer?id=0156F00000G41n0&oid=00D6F000002W0zo&lastMod=1541150013000"  content-height="scale-to-fit" height="1.5in"  content-width="2.00in" scaling="non-uniform"/>

Here is the Sample output:

For more help click here and subscribe my Youtube channel:

Salesforce CPQ AMUL BARANWAL





Salesforce Survey using Apex

How to Customize Salesforce Survey Below are steps to enable Salesforce Survey and to use in LWC. Below Sample code will tell you how ...