Friday 17 November 2017

Task Custom Record Type Selection Lightning Component with Related(whatID) pre populate (force:createRecord event)

To Make Custom Record Type Selection Available for Users in Custom Components With force:createRecord i Have created below custom Lightning component . by using this when user create task from any object like Opportunity  it will navigate to Task Record Type Selection page , once he select recordtype it will open editable mode Task record with pre populated Relatedto field (opportunity).

Lightning component:
<aura:component controller="recordtypeController" implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" access="global">
    
    <aura:handler name="init" value="{!this}" action="{!c.fetchListOfRecordTypes}"/>
    
    <aura:attribute name="lstOfRecordType" type="String[]" />
    <aura:attribute name="isOpen" type="boolean" default="false" />
    <aura:attribute name="recordId" type="String" />
  <div class="slds-m-around--x-large">
    <lightning:button label="Create a Task" onclick="{!c.openModal}" />
  </div>    
   <!-- Model Box Start -->    
    <aura:if isTrue="{!v.isOpen}">
        <div role="dialog" tabindex="-1" aria-labelledby="header43" class="slds-modal slds-fade-in-open">
            <div class="slds-modal__container">
                <div class="slds-modal__header">
                    <button class="slds-button slds-modal__close slds-button--icon-inverse" title="Close" onclick="{!c.closeModal}">
                        X<span class="slds-assistive-text">Cancel</span>
                    </button>
                    <h2 id="header43" class="slds-text-heading--medium">New Task</h2>
                </div>
                
                <div class="slds-modal__content slds-p-around--medium">
                    <div class="slds-grid slds-wrap">
                        <div class="slds-size--1-of-2 slds-large-size--1-of-2">
                             <div class="slds-align--absolute-center">Select a Record Type</div>                            
                        </div>
                        <div class="slds-size--1-of-2 slds-large-size--1-of-2">
                            <ui:inputSelect aura:id="selectid">
                                <aura:iteration items="{!v.lstOfRecordType}" var="Objtask">                            
                                    <ui:inputSelectOption text="{!Objtask}" label="{!Objtask}"  />
                                </aura:iteration>
                            </ui:inputSelect>
                        </div>&nbsp; &nbsp;
                    </div>                   
                </div>
                
                <div class="slds-modal__footer">
                    <lightning:button class="slds-button slds-button--neutral" onclick="{!c.closeModal}">Cancel</lightning:button>
                    <lightning:button class="slds-button slds-button--brand" onclick="{!c.createRecord}">Next</lightning:button>
                </div>
            </div>
        </div>
        <div class="slds-backdrop slds-backdrop--open"></div>
    </aura:if>
</aura:component>


Javascript controller:
({
   /* On the component Load this function call the apex class method, 
    * which is return the list of RecordTypes of object 
    * and set it to the lstOfRecordType attribute to display record Type values
    * on ui:inputSelect component. */
   fetchListOfRecordTypes: function(component, event, helper) {
      var action = component.get("c.fetchRecordTypeValues");
      action.setCallback(this, function(response) {
         component.set("v.lstOfRecordType", response.getReturnValue());
      });
      $A.enqueueAction(action);
   },
   /* In this "createRecord" function, first we have call apex class method 
    * and pass the selected RecordType values[label] and this "getRecTypeId"
    * apex method return the selected recordType ID.
    * When RecordType ID comes, we have call  "e.force:createRecord"
    * event and pass object API Name and 
    * set the record type ID in recordTypeId parameter. and fire this event
    * if response state is not equal = "SUCCESS" then display message on various situations.
    */
   createRecord: function(component, event, helper) {
      component.set("v.isOpen", true);
      var action = component.get("c.getRecTypeId");
      var recordTypeLabel = component.find("selectid").get("v.value");
      action.setParams({
         "recordTypeLabel": recordTypeLabel
      });
      action.setCallback(this, function(response) {
         var state = response.getState();
         if (state === "SUCCESS") {
            var createRecordEvent = $A.get("e.force:createRecord");
            var RecTypeID  = response.getReturnValue();
             var whatidvar  = component.get("v.recordId");
             alert(whatidvar);
            createRecordEvent.setParams({
               "entityApiName": 'Task',
               "recordTypeId": RecTypeID,
                 'defaultFieldValues': {
                'WhatId': whatidvar
          }

            });
            createRecordEvent.fire();
             
         } else if (state == "INCOMPLETE") {
            var toastEvent = $A.get("e.force:showToast");
            toastEvent.setParams({
               "title": "Oops!",
               "message": "No Internet Connection"
            });
            toastEvent.fire();
             
         } else if (state == "ERROR") {
            var toastEvent = $A.get("e.force:showToast");
            toastEvent.setParams({
               "title": "Error!",
               "message": "Please contact your administrator"
            });
            toastEvent.fire();
         }
      });
      $A.enqueueAction(action);
   },
   closeModal: function(component, event, helper) {
      // set "isOpen" attribute to false for hide/close model box 
      component.set("v.isOpen", false);
   },
   openModal: function(component, event, helper) {
      // set "isOpen" attribute to true to show model box
      component.set("v.isOpen", true);
   },
})


Server side Controller :
public class recordtypeController {
    public static Map<Id, String> recordtypemap {get;set;}
    
   @AuraEnabled        
    public static List<String> fetchRecordTypeValues(){
        List<Schema.RecordTypeInfo> recordtypes = Task.SObjectType.getDescribe().getRecordTypeInfos();    
        recordtypemap = new Map<Id, String>();
        for(RecordTypeInfo rt : recordtypes){
            if(rt.getName() != 'Master')
            recordtypemap.put(rt.getRecordTypeId(), rt.getName());
        }        
        return recordtypemap.values();
    }
    
    @AuraEnabled
    public static Id getRecTypeId(String recordTypeLabel){
        Id recid = Schema.SObjectType.Task.getRecordTypeInfosByName().get(recordTypeLabel).getRecordTypeId();        
        return recid;
    }      
}

Test class:
@isTest

public class recordtypeControllerTest {


static testmethod void testFetchRecordTypes() {
    List<String> values = recordtypeController.fetchRecordTypeValues();
  }

 static testmethod void testgetRecordTypeId() {
    String recordTypeLabel = 'Test1';
    ID testId = recordtypeController.getRecTypeId(recordTypeLabel);
    System.assert(testId != null);
  }

}

Tuesday 23 May 2017

Custom approval process : to Add Custom fields to "Items to Approve" home page component

I  have approval process on Opportunity. my requirement is like to display custom field (TC Meeting Notes)to "Items to Approve" home page component, we can't customise this, but we can create a custom component for this behaviour using Visualforce.  i have created vf page apex class and
custom home page component .
here TC_Meeting_Notes__c is custom field from opportunity :
Idea link: https://success.salesforce.com/ideaView?id=08730000000BrKHAA0



VF page:
<apex:page controller="ItemstoApprovvecontroller" sidebar="false" showHeader="false" tabStyle="Approver_Configuration__c" >
    <apex:form >
        <apex:pageBlock title="Items To Approve">
            <apex:pageBlockTable value="{!items_to_approve}" var="item_to_approve">
                <apex:column headerValue="Action" width="160 px" >
                                    <apex:commandLink target="_top" value="Reassign |" action="{!REASSIGNnavigation}" style="text-decoration:none;color: #015ba7;" styleClass="cactionLink">
                                                       <apex:param name="myParam" value="{!item_to_approve.approvalid }" />
                                                                                             
                                                                    </apex:commandLink>

                    <apex:commandLink target="_top" value=" Approve / Reject" action="{!ApproveRejectnavigation}" style="text-decoration:none;color: #015ba7;"  >

                   <apex:param name="myParam" value="{!item_to_approve.approvalid }" />
                </apex:commandLink>

         
                </apex:column>
               <apex:column headerValue="Type"  width="100 px">
                    <apex:outputText >{!item_to_approve.objtype}
                      </apex:outputText>
                </apex:column>
             
                <apex:column headerValue="Deal" width="300 px">
                    <apex:outputLink target="_top" value="/{!item_to_approve.id}">{!item_to_approve.name}
                      </apex:outputLink>
                </apex:column>
             
             
                <apex:column headerValue="TC Meeting Notes">
                    <apex:outputtext >{!item_to_approve.tcmeetingcomments}
                      </apex:outputtext>
                </apex:column>
                <apex:column headerValue="Date Submitted" width="150 px">
                    <apex:outputtext >{!item_to_approve.DateSubmited }
                      </apex:outputtext>
                </apex:column>
            </apex:pageBlockTable>
        </apex:pageBlock>
    </apex:form>
</apex:page>

Apex class:
public class ItemstoApprovvecontroller {
 
    ApexPages.standardController stdController= null;
    public ItemstoApprovvecontroller(ApexPages.StandardController controller) {
        stdController=controller;
    }
    public opportunity Objectopportunity {get; set;}
    public List<opportunity> lstopportunityapprove {get; set;}
    ID Oppyid;
    Set<ID> oppyids=new Set<ID>();
 
    public class item_wrapper {
        public item_wrapper(id id,string name,string objtype,String DateSubmited,string tcmeetingcomments, id approvalid ) {
            this.id = id;
            this.name = name;
            this.objtype = objtype;
            this.DateSubmited = DateSubmited;
            this.tcmeetingcomments=tcmeetingcomments;
            this.approvalid =approvalid ;
        }
        public id id { get; set; }
        public string name { get; set; }
        public string objtype { get; set; }
        public String DateSubmited { get; set; }
        public string tcmeetingcomments{ get; set; }
        public id approvalid { get; set; }
     
    }
 
    public list<item_wrapper> items_to_approve { get; set; }
 
    public ItemstoApprovvecontroller() {
        items_to_approve = new list<item_wrapper>();
     
        map<id,ProcessInstanceWorkItem> mpaPIWIdToPIW = new map<id,ProcessInstanceWorkItem>();
        list<ProcessInstanceWorkItem> lstPIWI = [select processinstance.targetobjectid,CreatedDate ,processinstance.targetobject.name,ProcessInstance.TargetObject.type from processinstanceworkitem where actorid = :userinfo.getuserid() Order by CreatedDate Desc];
        if(!lstPIWI.isEmpty()){
            for(ProcessInstanceWorkItem item: lstPIWI) {
                oppyids.add(item.processinstance.targetobjectid);
                if(!mpaPIWIdToPIW.containsKey(item.processinstance.targetobjectid)){
                    mpaPIWIdToPIW.put(item.processinstance.targetobjectid,item);
                }
            }
        }
     
        map<id,Opportunity> mapoptyIdtoMeetingnotes = new map<id,Opportunity>();
     
        if(oppyids.size()>0){
            lstopportunityapprove=[select id,Owner.name,name,Deal_Comments__c,stagename,TC_Meeting_Notes__c  from Opportunity where id in : oppyids];
            if(!lstopportunityapprove.isEmpty()){
                for(opportunity objoppy:lstopportunityapprove){
                    mapoptyIdtoMeetingnotes.put(objoppy.id,objoppy);
                }
            }
        }
        if(!lstPIWI.isEmpty()){
         
            for(ProcessInstanceWorkItem item: mpaPIWIdToPIW.values()) {
                String dateTimeValue = item.CreatedDate.format('MM/dd/yyyy hh:mm a');
                system.debug(dateTimeValue +'Debug2 dateTimeValue ');
                if(item.processinstance.TargetObject.type == 'Opportunity'){
                                    system.debug(item.processinstance.targetobjectid +'Debug2 dateTimeValue ');

                    items_to_approve.add(new item_wrapper(item.processinstance.targetobjectid,item.processinstance.targetobject.name,item.processinstance.TargetObject.type,dateTimeValue ,mapoptyIdtoMeetingnotes.get(item.processinstance.targetobjectid).TC_Meeting_Notes__c,item.id ));
                }else{
                   system.debug(item.processinstance.targetobjectid +'Debug2 dateTimeValue ');


                    String sObjName = item.processinstance.targetobjectid.getSObjectType().getDescribe().getLabel();
                                                           system.debug(sObjName +'sObjNameValue ');

                    items_to_approve.add(new item_wrapper(item.processinstance.targetobjectid,item.processinstance.targetobject.name,sObjName ,dateTimeValue ,'',item.id ));
                }
            }
        }
    }  
    public  static String ApproveRejectnavigation() {
        String url='';
        string myParam = apexpages.currentpage().getparameters().get('myParam');
        url='https://'+ System.URL.getSalesforceBaseUrl().getHost() +
            '/p/process/ProcessInstanceWorkitemWizardStageManager?id=' + myParam ;    
     
        return url;
     
    }
    public  static String REASSIGNnavigation() {
        String url='';
        string myParam = apexpages.currentpage().getparameters().get('myParam');
        url='https://'+ System.URL.getSalesforceBaseUrl().getHost()+'/'+ myParam +'/e?et=REASSIGN';    
        return url;
     
    }
 
}

Sunday 23 April 2017

Opportunity Owner should get email notification when task is completed on opportunity

trigger NotifyOpportunityowner on Task ( after update) {
List<Task> taskList = new List<Task>();
Set<ID> taskIDSet = new Set<ID>();

if (trigger.old != null)
{
for (Task t: trigger.old)
{
taskIDSet.add(t.ID);
}Set<String> strwhatIDs = new Set<String>();
set<Id> setClosedTaskId = new set<Id>();
Map<id,string> maprecortypes=new Map<id,string>();
Map<id,string> mapEmailAdress=new Map<id,string>();
Map<id,string> mapcurrentOwnerid=new Map<id,string>();
string[] toaddress = New String[] {};
for (Task t : (List<Task>)Trigger.new) {
Task oldTask = (Task)trigger.oldMap.get(t.Id);
Task newTask = (Task)trigger.newMap.get(t.Id);
if(((oldTask.status != newTask.status) && t.status == 'Completed' )){
strwhatIDs.add(t.whatID);
setClosedTaskId.add(t.id);

}  
}
list<Task> lstTask = [select id,OwnerId,what.recordtype.developername,what.recordtype.name from Task where Id IN : setClosedTaskId ];

EmailTemplate objEt =  [select id,developername from EmailTemplate where developername ='Testing_vf_template'];
list<Opportunity> lstopt = [select id,owner.email from Opportunity where id IN: strwhatIDs];

if(!lstopt.isEmpty()){
for(Opportunity Opt : lstopt){

mapEmailAdress.put(Opt.id,Opt.owner.email);

}
}
 
if(!mapEmailAdress.values().isEmpty()){
for(string str :mapEmailAdress.values()){
toaddress = New String[] {str};
}
}
List<Messaging.SingleEmailMessage> lstEmailId=new List<Messaging.SingleEmailMessage>();
Contact cont = [select id,name from contact limit 1];

if(!lstTask.isEmpty()){
for(Task tk : lstTask){
system.debug('toaddress exception'+toaddress);

Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setToAddresses(toaddress);
mail.setTemplateId(objEt.id);
mail.setWhatId(tk.id);
mail.setTargetObjectId(cont.id);
mail.setTreatTargetObjectAsRecipient(false);
mail.setSaveAsActivity(false);
lstEmailId.add(mail);                

}
}
if(lstEmailId.size()>0){
try{              
Messaging.sendEmail(lstEmailId);
}Catch(Exception ee){
system.debug('Print exception'+ee);
}
}
}
 

}

customize omni channel logic to distribute cases based on Case Creation Date

Omni Channel queues distributes cases, based on Date/Time the case is assigned to the queue. we can customize this logic to look for some ...