Custom Approval Process in Salesforce – Part 2

By | December 9, 2021

In continuation to our previous blog, where we worked on the UI for Approver. In this blog, we will be working on the functionality & also build UI.

ApproverOrReject.cmp

<aura:component controller="QuoteApprovalProcessController" implements="force:lightningQuickActionWithoutHeader,force:hasRecordId,force:appHostable,lightning:actionOverride" access="global" >
            <!--<aura:handler name="reinit" value="{!this}" action="{!c.reInit}" />-->
            <aura:attribute name="recordId" type="Id" default=""/>
            <aura:attribute name="comment" type="String" default="" />
            <aura:attribute name="loaded" type="Boolean" default="true" />
            <aura:attribute name="Spinner" type="Boolean" default="false"/>
            <aura:attribute name="LoadMessage" type="string" default="Loading.."/>
            <aura:attribute name="showProgressbar" type="Boolean" default="false"/>
            <aura:attribute name="isOpen" type="Boolean" default="false"/>
            <aura:attribute name="filetype" type="List" default="['.pdf']" />
            <aura:attribute name="multiple" type="Boolean" default="true" />
            <aura:attribute name="disabled" type="Boolean" default="true" />
    	    <aura:attribute name="encryptedToken" type="String" />
            <aura:attribute name="FileList" type="String"/>
            <ltng:require scripts="{!$Resource.CommonFunction}" afterScriptsLoaded="{!c.doInit}" />
    		<c:spinner Spinner="{! v.Spinner}" LoadMessage="{! v.LoadMessage}" showProgressbar="{! v.showProgressbar}" progress="{! v.progress}"/>
            <aura:html tag="style"> 
                .cuf-content 
                {
                padding: 0 0rem	!important;
                }
                <!-- MOD -->
                .slds-p-around--medium 
                {
                padding: 0rem !important;
                }        
                
                .slds-modal__content
                {
                //	overflow-y:hidden !important;
                height:unset !important;
                max-height:unset !important;
                }       
                
                .GUMUStyle 
                {
                z-index: 10000;
                position: fixed;
                visibility: visible;
                opacity: 1;
                height: 100%;
                width: 100%;
                max-height: 250px;
                background-color: rgba(255, 255, 255, 0.75) !important;
                }
    
            </aura:html>
    <aura:if isTrue="{!v.isOpen}">
            <section role="dialog" tabindex="-1" aura:id="Modalbox" 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 slds-col slds-size_1-of-1 slds-small-size_1-of-1 slds-medium-size_1-of-1">
                    <header class="slds-modal__header">
                        <h2 id="modal-heading-01" class="slds-text-heading_medium slds-hyphenate">Approval / Reject</h2> 
                    </header> 
                    <div class="slds-modal__content slds-p-around_medium" id="modal-content-id-1">
                        <div class="slds-grid slds-wrap"> 
                                <div class="slds-col slds-size_1-of-1 slds-small-size_1-of-1 slds-medium-size_1-of-1 inputArea">
                                    <lightning:textarea name="comment" label="Comments" value="{!v.comment}" placeholder="Type here..." />
                                </div>
                         </div>
                         <div class="slds-text-align_center slds-p-top_small">
                               <!--<aura:if isTrue="{! v.loaded }">-->
                                      <!--<footer class="slds-modal__footer slds-m-top_x-small slds-m-bottom_medium slds-m-horizontal_none">--> 
                        					<div class="slds-m-top_x-small slds-m-bottom_medium slds-m-horizontal_none slds-float_right">
       											<lightning:button class="slds-button slds-button_neutral slds-float_bottom" label="Cancel" onclick="{!c.closeModal }"/> 
                                                <lightning:button class="slds-button " variant="brand" label="Approve" onclick="{!c.handleApproval}" />
                                                <lightning:button class="slds-button slds-button_destructive" variant="brand" label="Reject" onclick="{!c.handleRejection}" />
                                            </div>
                                      <!--</footer>-->
                               <!--</aura:if>-->
                        </div>
                    <!--</div>-->
                </div>
                </div>
            </section>
    </aura:if>
</aura:component>

The above code will create the UI for the Approver Screen as shown below,

Approver Screen
Approver Screen

Here Approver can write their comment prior to Approval or Rejection

  • Approve: Where Approver can approve the request for Approval with comment.
  • Reject: Where Approver can reject the request for Approval with comment.
  • Comment: Where Approver can write their comment regarding notes or reason to reject.

ApproverOrRejectController.cmp

({
    doInit : function(component, event, helper) {
        helper.approvalStatusChecker(component, event, helper);
    },
                           
    handleApproval : function (component, event, helper) 
    {
        helper.goToApproval(component, event, helper,'Approved');
    },
    handleRejection : function (component, event, helper)
    {
        helper.goToApproval(component, event, helper,'Rejected');
    },
    closeModal : function(component,event,helper)
    {    
        component.set("v.isOpen", false);
        $A.get("e.force:closeQuickAction").fire();
    },    
    handleUploadFinished: function (cmp, event,helper) 
    {
       
        var uploadedFiles = event.getParam("files");
        //alert ("uploadedFiles"+uploadedFiles);
        cmp.set("v.FileList",uploadedFiles);
        var showToast = $A.get("e.force:showToast");
        showToast.setParams({
            title : 'Files Load',
            message : 'Files Loaded Successfully.',
            duration:' 10000',
            type : 'success',
            mode: 'dismissible'
        });
        showToast.fire();
        $A.get('e.force:refreshView').fire(); 
       
    }
})

ApproverOrRejectHelper.cmp

({
	approvalStatusChecker : function(component, event, helper)
    {
        debugger;
        var getID = component.get("v.recordId");
        //alert('getID'+getID)
        var action = component.get('c.ApprovalRequestCheck');
        component.set("v.Spinner", true);
        action.setParams({
            "recordId": component.get("v.recordId")
        });
        action.setCallback(this, function(response) 
          {
            component.set("v.Spinner", false);  
            var state = response.getState();
            //alert('state::'+state);
            if(state === "SUCCESS") 
            {
                var resp = response.getReturnValue();
                //alert('resp::'+resp);
                if(resp == 'failure')
                {
                    //alert('response:::'+resp);
                    helper.showToast(component, event, helper, 'warning', 'There is no request for Approval','warning Message');
                    $A.get("e.force:closeQuickAction").fire(); 
                }
                else if(resp == 'success')
                {
                     helper.UserChecker(component, event, helper);
                }	
            } 
              else 
              {
                var errors = response.getError();
                if (errors) 
                {
                    if (errors[0] && errors[0].message) 
                    {
                        console.log("Error message: " +errors[0].message);
                    }
                } 
                  else 
                    {
                        //alert("Unknown error");
                    }
                console.log('Problem getting account, response state: ' + state);
            }
        });
        $A.enqueueAction(action);        
    },
    
    UserChecker : function(component, event, helper)
    {
        debugger;
        var getID = component.get("v.recordId");
        //alert('getID'+getID)
        var action = component.get('c.UserCheck');
        component.set("v.Spinner", true);
        action.setParams({
            "recordId": component.get("v.recordId")
        });
        action.setCallback(this, function(response) 
          {
            component.set("v.Spinner", false);  
            var state = response.getState();
            //alert('state::'+state);
            if(state === "SUCCESS") 
            {
                var resp = response.getReturnValue();
                //alert('resp::'+resp);
                if(resp == 'Userfailure')
                {
                    //alert('response:::'+resp);
                    helper.showToast(component, event, helper, 'error', 'Not A valid Approver','Error Message');
                    $A.get("e.force:closeQuickAction").fire(); 
                }
                else if(resp == 'success')
                {
                    component.set("v.isOpen", true);
                }	
            } 
              else 
              {
                var errors = response.getError();
                if (errors) 
                {
                    if (errors[0] && errors[0].message) 
                    {
                        console.log("Error message: " +errors[0].message);
                    }
                } 
                  else 
                    {
                        //alert("Unknown error");
                    }
                console.log('Problem getting account, response state: ' + state);
            }
        });
        $A.enqueueAction(action);        
    },
    goToApproval : function(component, event, helper,State)
    {
        debugger;
        component.set('v.loaded', false);
        var getID = component.get("v.recordId");
        //alert('Id:::'+getID);
        var getComment = component.get("v.comment");
        //alert('comments:::'+getComment);
        var action = component.get('c.ApprovedOrReject');
        component.set("v.Spinner", true);
        action.setParams({
                            "recordId": component.get("v.recordId"), 
                            "comment": component.get("v.comment"),
                            "State" : State,
        				});
        console.log('action::'+JSON.stringify(action));
        action.setCallback(this, function(response) 
         {
            component.set("v.Spinner", false); 
            var state = response.getState();
            if(state === "SUCCESS") 
            {
                var resp = response.getReturnValue();
                //alert('response:::'+resp);
                if(!$A.util.isEmpty(resp) && resp == 'success') 
                {
                    helper.showToast(component, event, helper, 'success', 'Your Responce successfully submitted!', 'Success Message');
                    $A.get("e.force:closeQuickAction").fire();
                    $A.get('e.force:refreshView').fire();
                }
                if((!$A.util.isEmpty(resp)) && (!$A.util.isUndefined(resp)) && resp.includes('first error:')) {
                    var showErrorList = [];
                    showErrorList = resp.split('first error: ');
                    helper.showToast(component, event, helper, 'error', showErrorList[1], 'Error Message');
                    var erromessage = showErrorList[1];
                    //alert('erromessage==='+erromessage);
                    $A.get("e.force:closeQuickAction").fire();
                }
                if(resp == 'failure')
                {
                    helper.showToast(component, event, helper, 'warning', 'No Active Approval Process Found.','Error Message');
                    $A.get("e.force:closeQuickAction").fire();                    
                }
                component.set('v.loaded', false);
            } else {
                component.set('v.loaded', true);
                var errors = response.getError();
                if (errors) {
                    if (errors[0] && errors[0].message) {
                        console.log("Error message: " +
                                    errors[0].message);     
                    }
                } else {
                    console.log("Unknown error");
                }
                console.log('Problem getting account, response state: ' + state);
            }
        });
        $A.enqueueAction(action);
    }, 
    
    showToast : function(component, event, helper, messageType, message, title) {
        var toastEvent = $A.get("e.force:showToast");
        //alert('toastEvent'+toastEvent);
        toastEvent.setParams({
            title : title,
            message: message,
            messageTemplate: '',
            duration:' 10000',
            key: 'info_alt',
            type: messageType,
            mode: 'dismissible'
        });
        toastEvent.fire();
    }
})

The above code will update data from custom object Named as “ApprovalInstance__c” where based on Approver action, record has been Updated.

We hope you may find this blog resourceful and helpful. If you still have concerns and need more help, please contact us at salesforce@greytrix.com.

References – Custom file upload in Salesforce lightning component & Dynamic Approval Process based on Apex and Trigger

About Us
Greytrix – a globally recognized and one of the oldest Sage Development Partner and a Salesforce Product development partner offers a wide variety of integration products and services to the end users as well as to the Partners and Sage PSG across the globe. We offer Consultation, Configuration, Training and support services in out-of-the-box functionality as well as customizations to incorporate custom business rules and functionalities that require apex code incorporation into the Salesforce platform.

Greytrix has some unique solutions for Cloud CRM such as Salesforce Sage integration for Sage X3Sage 100 and Sage 300 (Sage Accpac). We also offer best-in-class Cloud CRM Salesforce customization and development services along with services such as Salesforce Data MigrationIntegrated App developmentCustom App development and Technical Support to business partners and end users. Salesforce Cloud CRM integration offered by Greytrix works with Lightning web components and supports standard opportunity workflow. Greytrix GUMU™ integration for Sage ERP – Salesforce is a 5-star rated app listed on Salesforce AppExchange.

The GUMU™ Cloud framework by Greytrix forms the backbone of cloud integrations that are managed in real-time for processing and execution of application programs at the click of a button.

For more information on our Salesforce products and services, contact us at salesforce@greytrix.com. We will be glad to assist you.

Related Posts