O Custom Settings, Custom Settings…wherethou art thou Custom Settings?

In the spirit of the upcoming Valentine’s Day, I figure I’ll express my love for something in Salesforce.  (yeah, I know…)

Aaahhh Custom Settings, how do I love thee…let me count the ways:

  1. You allow me to insert admin-customizable variables in Apex code

    Often, you have the need to make profile-specific, record-specific, or on/off flags in your code. In “old school” desktop programming, you could access the registry or manage an ini file for these kinds of things, but in the cloud world there is not really an obvious option anymore.

    You are faced with either being eternally support-bound to the project, or training someone at the client to edit code.  Using Custom Settings, you get it back!  Declarative control over programmatic variables for the win!

  1. You allow me to create a hierarchy of settings per profile

    Need different versions of the same settings for different people, processes, or users? Do you need the decision on what setting is used to be at runtime? Boom.Custom

    Settings can either be in a:

    • List Format – where you can create multiple instances of your settings and refer to them manually throughout your code
    • Heirarchy Format – where you can create profile-specific instances of your settings
  2. You are accessible via the Schema!

    Custom Settings are rendered up just as if they were custom objects. You can create, edit, and delete them through code just as easily as you would through the UI.

On to the screenshots!  In this example, I was creating admin-customizable settings for how to manage confirming room reservations.

Advertisements

Creating a new Event or Task with prepopulated information

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)
  • 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)
THE GUTS:
1.  Review Custom Objects / Custom Settings
  • Custom Object:  Education Class / Education_Class__c
    • Fields
      • Id
      • Name
      • Instructor (lookup to User)
      • Classroom (lookup to Classroom__c)
      • Class Date
  • Custom Object:  Classroom / Classroom__c
    • Fields
      • Id
      • Name
      • Scheduling Contact (lookup to Contact)
      • Site Address
      • Scheduling Notes
  • 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 “
2.  Source Data

Scheduling Contact

Class

Classroom

3.  Create Interstitial Controller / Page
APEX Controller:  (word wrapped – FYI)
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;

}

}
Visualforce Page: (word wrapped – FYI)
<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>
4.  Create Custom Button and give it a whirl!

Class with Custom Button

New VF Create Task Screen

New VF Create Task Screen – Field Error

BOOM! Task.

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.