Here’s a fancy little trick I came up with the other day. If you’re scouring Google for ideas on this – hopefully this helps you out. *smile*
BUSINESS NEED:
In Salesforce, a user wants to be able to click a button from a Custom Object and create a new Task with pre-populated information according to a number of defined business rules. Using good “best practice” process methodology and user interface design, we’ll want to do this quickly, with a minimal number of clicks, and giving a “cool factor” to the user.
*You could do this with ANY object by just changing around the objects and fields, but this is an example for a Custom Object I was working with.
MY INITIAL APPROACH:
Not wanting to reinvent the wheel, I Googled around a little bit to see if anyone had done this before. The majority of what I found was manipulation of the HTTP GET string. Workable? Sure…but the minute Salesforce changes their form Ids, your code breaks. Granted their Ids are pretty set, but I hate coding with a “what if” like that in my head. I really hate fixing code I wrote months ago because “something changed”.
MY RE-WORKED APPROACH:
A combination of custom objects, custom settings, APEX, and Visualforce. At first blush it may seem a little over-engineered, but read on and you’ll see why it’s the *RIGHT* solution.
- Custom Object
- “Education Class”
- Custom Settings
- Will be used to store values and metrics
- Days before the class that an instructor needs to confirm classroom
- The Business can edit these settings without having to come back to me to edit code (always a good thing)
- Will be used to store values and metrics
- APEX / VF
- Because I just want this to work from this point on, we’re going to programatically set Task field values through a wizard of sorts
- Process Flow
- User hits “Confirm Classroom” Custom Button from Education Object
- APEX Controller will assemble the basic Task object with pre-populated data according to business rules
- Pulling from Custom Settings
- A Visualforce “Interstitial” page will appear confirming some limited data choices with instructions
- Users hits “Next” on the Interstitial Page
- APEX Controller will pull in the user’s data choices into the Task object and insert to the database
- APEX Controller will bring the user to the newly completed Task with a return path to the Education Class (where they started)
- Custom Object: Education Class / Education_Class__c
- Fields
- Id
- Name
- Instructor (lookup to User)
- Classroom (lookup to Classroom__c)
- Class Date
- Fields
- Custom Object: Classroom / Classroom__c
- Fields
- Id
- Name
- Scheduling Contact (lookup to Contact)
- Site Address
- Scheduling Notes
- Fields
- Custom Setting: (List) Custom Task Values / Custom_Task_Values__c
- Fields
- Checkbox: Enable Task Fields (I always build in a shutoff valve)
- Number: Days Before Class
- Text(80): Task Subject
- TextArea(255): Task Body Header
- Name
- APEX Task
- Enable Task Fields = true
- Days Before Task = 2
- Task Subject = “Confirm Classroom Availability”
- Task Body Header = “An Education Class has been scheduled for this Classroom. You need to verify the Classroom’s availability “
- APEX Task
- Fields
public class CustomTaskController { //////////// HEADER //////////////////// // This class handles the creation of a pre-populated Task from the Education Classes Page // Referenced by | CustomTaskInterstitial.page // Created on 20111022 by Andrew Boettcher // Support Info: // <my support email> // <my phone number> //////////// HEADER //////////////////// ///////////////////// // Class Variables ///////////////////// Id idEducationClass = null; public Education_Class__c ecCurrent {get;set;} public Classroom__c clCurrent {get;set;} public Task tskNew {get;set;} public Custom_Task_Values__c csTaskValues = Custom_Task_Values__c.getValues('APEX Task'); ///////////////////// // Constructors ///////////////////// public CustomTaskController(ApexPages.StandardController conMain) { // Set Variables idEducationClass = conMain.getId(); ecCurrent = [SELECT Id, Name, Class_Date__c, Instructor__c, Classroom__c FROM Education_Class__c WHERE Id = :idEducationClass]; clCurrent = [SELECT Id, Name, Scheduling_Contact__c, Site_Address__c, Scheduling_Notes__c FROM Classroom__c WHERE Id = :ecCurrent.Classroom__c]; // Instanciate and pre-populate Task createTaskRecord(); } ///////////////////// // GETers ///////////////////// // None. ///////////////////// // Actions ///////////////////// public void createTaskRecord() { /////////// // Create Task Object from Business Rules /////////// // Instanciate Object tskNew = new Task(); // Set Initial Variables Integer intDaysBeforeClass = Integer.valueOf(csTaskValues.Days_Before_Class__c); Date dteActivityDate = ecCurrent.Class_Date__c.date(); String strNotes = csTaskValues.Task_Body_Header__c; // Set Business Rules dteActivityDate = dteActivityDate.addDays(-intDaysBeforeClass); strNotes += ' ' + intDaysBeforeClass + ' days before the start of the class.\n\n'; strNotes += 'Special Scheduling Notes:\n'; strNotes += clCurrent.Scheduling_Notes__c; // Pre-populate Fields tskNew.WhoId = clCurrent.Scheduling_Contact__c; // Set Scheduling Contact tskNew.WhatId = ecCurrent.Id; // Refer to Education Class tskNew.Subject = csTaskValues.Task_Subject__c; // Pull CS Subject tskNew.ActivityDate = dteActivityDate; // Pull computed date tskNew.Description = strNotes; // Pull concatenated text tskNew.OwnerId = ecCurrent.Instructor__c; // Set as instructor of class } public PageReference saveAndProceed() { /////////// // Save Task and Redirect user to Task Page /////////// // Save the Task try { insert tskNew; } catch(DMLException e) { tskNew.addError(e.getMessage()); return null; } // Send user to Task with Return URL of Education Class PageReference pf = new PageReference('/' + tskNew.Id + '?retURL=/' + ecCurrent.Id); pf.setRedirect(true); return pf; } }
<apex:page id="pgTaskCreate" standardController="Education_Class__c" extensions="CustomTaskController" title="Verify Task Information" tabStyle="Education_Class__c"> <apex:form id="frmTask"> <apex:sectionHeader title="Create Classroom Reservation Task" /> <apex:pageBlock > <font color="red"><apex:messages ></apex:messages></font> <apex:pageBlockButtons > <apex:commandButton id="cmdCreateTask" value="Create Task" action="{!saveAndProceed}" /> <apex:commandButton id="cmdCancel" value="Cancel" action="{!cancel}" /> </apex:pageBlockButtons> <apex:pageBlockSection collapsible="true" title="Education Class and Classroom Information"> <apex:outputField id="ofClassName" value="{!ecCurrent.Name}" /> <apex:outputField id="ofInstructor" value="{!ecCurrent.Instructor__c}" /> <apex:outputField id="ofClassDate" value="{!ecCurrent.Class_Date__c}" /> <apex:outputField id="ofSchedulingContact" value="{!clCurrent.Scheduling_Contact__c}" /> </apex:pageBlockSection> <apex:pageBlockSection collapsible="true" title="Classroom Reservation Task Information"> <apex:inputField id="ifOwnerId" value="{!tskNew.OwnerId}" /> <apex:inputField id="ifWhoId" value="{!tskNew.WhoId}" /> <apex:inputField id="ifActivityDate" value="{!tskNew.ActivityDate}" /> </apex:pageBlockSection> </apex:pageBlock> </apex:form> </apex:page>
That’s all there really is to it. Now of course you need to write a Test Class and all that jazz to deploy it, but it’s a quick and elegant solution to keep clutter out of your user’s faces with minimal development effort. (I wrote this whole thing in about an hour)
(I could have really written in some more error handling in the Controller, but I just whipped this up as an example. I’m not going to do ALL of your work for you. *smile*)
Questions? Comments? Hit me up in the comments below.