Project: Change Owner Button in Visualforce
Salesforce Labs has put out a series of Mass Action packages on the AppExchange. There is Mass Transfer Opportunity Owner (uses AJAX), Mass Update Contact Addresses (AJAX), Mass Update Opportunity Owner, Mass Update Opportunity Close Dates, etc. All of these are “thick client” tools, meaning that data must be loaded onto your computer, altered, and then uploaded back to Salesforce.
Ron Hess released a super bit of code, found in the Visualforce documentation and elsewhere, to Mass Update Opportunity Stage and Close Date. It could, theoretically, be expanded to other fields as well. This got me thinking about doing so with other objects.
A while ago, I took the code for the Mass Delete button and altered it to change the owner of the selected records to the User clicking the button. It was like an Accept button, but I could use it for any object. Actually, it wasn’t as easy as that. I had to make one button for each object, and maintenance was a pain–whenever I created a new object, I needed to clone my code.
Drawing upon some code I found in the Developers Guide, I have written a Visualforce page to mass-change the owner of all selected records to any active User in Salesforce. Yes, it only works with Contacts for now, but my next step will be to use Dynamic Apex to pass the sObject name to the page and its extension/controller, allowing me to reuse one bit of code for multiple objects. We’ll see how it goes. But in the meantime, enjoy this page that lets you perform a search, check which records you want to transfer, and then input a User. I’ve tested it with 50 records at once, so that should suffice for most uses.
VF Page:
<apex:page standardController="Contact" recordSetVar="Contacts" id="updateOwnerPage">
<apex:form>
<apex:sectionHeader title="Change Owner for Contacts"/>
<apex:pageBlock mode="edit">
<apex:pageMessages />
<apex:pageblockSection title="Change" columns="1">
<apex:pageblockSectionItem >
<apex:outputLabel for="owner">New Owner</apex:outputLabel>
<apex:inputField id="owner" value="{!Contact.OwnerId}"/>
</apex:pageblockSectionItem>
</apex:pageBlockSection>
<apex:pageBlockSection title="Selected Contacts" columns="1">
<apex:pageBlockTable value="{!selected}" var="j" bgcolor="#F3F3EC" width="100%"
styleClass="list" rowClasses="dataRow" onRowMouseOver="hiOn(this);" onRowMouseOut="hiOff(this);">
<apex:column >
<apex:facet name="header">Contact Name</apex:facet>
<apex:outputLink value="{!URLFOR($Action.Contact.View, j.id)}">
{!j.FirstName} {!j.LastName}</apex:outputLink>
</apex:column>
<apex:column >
<apex:facet name="header">Account Name</apex:facet>
<apex:outputLink value="{!URLFOR($Action.Account.View, j.Account.id)}">
{!j.Account.Name}</apex:outputLink>
</apex:column>
<apex:column>
<apex:facet name="header">Current Owner</apex:facet>
{!j.Owner.Name}
</apex:column>
</apex:pageBlockTable>
</apex:pageblockSection>
<apex:pageBlockButtons location="bottom">
<apex:commandButton value="Save" action="{!save}"/>
<apex:commandButton value="Cancel" action="{!cancel}"/>
</apex:pageBlockButtons>
</apex:pageBlock>
</apex:form>
</apex:page>
Button:
Go to Setup -> Contact -> Buttons and Links
Create a new button, set it to execute in the current window with sidebar and header, and set it to call a Visualforce page. Select the page you just created. Then add the button to Contact Search Layout and to any Contact related lists you like.
Voila!
Project: Lookup to Picklist
In the first installment of post-Dreamforce projects, I present a mechanism to present the user with all available Lookup options in a picklist. This should simplify some Visualforce pages. (Credit to the Developers Guide from the new post-Dreamforce Library.)
The key to the code is the ability to customize the SOQL statement to focus as much, or as little, as the developer would like. Though the code I provide makes no limit on the number of records returned, I encourage developers to limit the select statement as seen fit.
VF Page:
<apex:page standardcontroller="Child__c" Extensions="ChildExtension">
<apex:messages ></apex:messages>
<apex:form >
<apex:pageBlock mode="edit" id="thePageBlock">
<apex:pageBlockButtons >
<apex:commandButton value="Save" action="{!save}"/>
<apex:commandButton value="Cancel" action="{!cancel}"/>
</apex:pageBlockButtons>
<apex:pageblockSection id="ParentList" title="1">
<apex:pageBlockSectionItem >
<apex:outputLabel value="Parent" for="p"/>
<apex:selectList id="p" value="{!Child__c.Parent__c}" size="1" title="3">
<apex:selectOptions value="{!ParentOptions}"/>
</apex:selectList>
</apex:pageBlockSectionItem>
</apex:pageblocksection>
</apex:pageBlock>
</apex:form>
</apex:page>
Extension:
Note the SOQL query in Line 12 (below) that defines which records are included in the picklist. You can include WHERE and LIMIT statements to get the picklist down to a manageable number of items.
public class ChildExtension {
private final Child__c child;
public ChildExtension(ApexPages.StandardController controller) {
this.child = (Child__c)controller.getRecord();
}
public List<selectOption> PositionOptions {get
{
List<selectOption> parents = new List<selectOption>();
for (Parent__c prt : [select name from Parent__c pt])
parents.add(new selectOption(prt.id, prt.name));
return parents;
}
private set;
}
}
I just had lunch with John Rotenstein aka The Enforcer, who already put up a photo of our time in his office. (I think the pirate logo was an accident, but it does add to my sinister persona, no?)
In any event, because the parents List in the extension sends an ID to the application, it can successfully create a record with the parent Name in the picklist, but the ID in the background. You can also substitute a different field for Name: If you prefer, put a contact’s email address or anything else. Try it out!
One more thing: This is an easy segue into another project, which will be a way to use the traditional lookup interface but to pre-filter the records available in the lookup.
And because I put this in every post: There’s a catch. (There always is.) I’m sure that somewhere in there, Salesforce would prefer that we not create a picklist of a few hundred items. So please feel free to test the limits of this visualforce method, but please be prepared to filter your SOQL query.
Salesforce Order of Execution
I came across this page in the Apex documentation and wanted to share it with everyone. So many people have asked about this in the past, so it seems a good idea to publicize it:
http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_triggers_order_of_execution.htm
Triggers and Order of Execution
When a record is saved with an insert, update, or upsert statement, the following events occur in order:
1. The original record is loaded from the database (or initialized for an insert statement)
2. The new record field values are loaded from the request and overwrite the old values
3. All before triggers execute
4. System validation occurs, such as verifying that all required fields have a non-null value, and running any user-defined validation rules
5. The record is saved to the database, but not yet committed
6. All after triggers execute
7. Assignment rules execute
8. Auto-response rules execute
9. Workflow rules execute
10. If there are workflow field updates, the record is updated again
11. If the record was updated with workflow field updates, before and after triggers fire one more time (and only one more time)
12. Escalation rules execute
13. All DML operations are committed to the database
14. Post-commit logic executes, such as sending email
Additional Considerations
Please note the following when working with triggers:
* When Enable Validation and Triggers from Lead Convert is selected, if the lead conversion creates an opportunity and the opportunity has Apex before triggers associated with it, the triggers run immediately after the opportunity is created, before the opportunity contact role is created. For more information, see “Customizing Lead Settings” in the Salesforce online help.
* If you are using before triggers to set Stage and Forecast Category for an opportunity record, the behavior is as follows:
o If you set Stage and Forecast Category, the opportunity record contains those exact values.
o If you set Stage but not Forecast Category, the Forecast Category value on the opportunity record defaults to the one associated with trigger Stage.
o If you reset Stage to a value specified in an API call or incoming from the user interface, the Forecast Category value should also come from the API call or user interface. If no value for Forecast Category is specified and the incoming Stage is different than the trigger Stage, the Forecast Category defaults to the one associated with trigger Stage. If the trigger Stage and incoming Stage are the same, the Forecast Category is not defaulted.
Upcoming Plans
This is my first blog post since Dreamforce 2008, and I had an amazing time. Hello to everyone I met, and hello to all the people that I said I’d meet - but couldn’t. I left Dreamforce and came to Sydney to visit my family, and am writing this blog post sitting on a deck chair under a setting sun, listening to my niece and nephew play nicely.
This blog post is partly an announcement of X-Squared’s upcoming plans and projects, and partly a way to hold myself to my word. It is said that while managing the Yankees, Joe Torre tried to quit many times, until someone bet him $1000 that he couldn’t quit… and told everyone he knew about the bet. Clearly, $1000 is small change to Torre, but the pressure of the whole world knowing his plan to quit helped him quite a bit. So here is X-Squared On Demand’s list of projects and plans (outside of the standard billing work for our amazing clients):
Jon Mountjoy suggested that I pick one Salesforce development feature and learn it completely instead of making the mistake of trying to learn everything and doing it all poorly. I chose Visualforce. All my side projects from now on will involve Visualforce to some degree.
- Lookup to Picklist: I’ve always been interested in lookup fields and have written some interesting implementations that use error messages and custom buttons to simplify and focus allowed values for lookups. Here, I plan to present the user with a list of all the target records available and to present them in a picklist. (Of course, if there are more than 50 records, I will leave the field as a lookup.)
- Filtered Lookup: I have the code for a filtered lookup that utilizes a three-page wizard to choose the proper record for a lookup, but I want to simplify this to allow an administrator to limit a lookup to one Record Type or any other hard-coded filter. Then I’ll use a simplified wizard to enhance that feature, which would basically be like using the lookup filters in Enhanced Lookups currently available in the standard UI.
- NonProfit EventForce using Google Sites: We started this project at Dreamforce 2008, and I have a non-profit client who would like a tool to allow registration for various kinds of events. This is a super opportunity to expand upon this hackathon project. Colin Loretz has agreed to help on this, and Steve Wright of Salesforce.com Foundation has offered to provide a salesforce.com technical resource if we make the code open-source. I told Steve that in my mind I was writing the code for the Foundation, and that the Foundation could do whatever it wanted with the code. So keep an eye out for this in the next month or two.
- Airport Codes to Full Name of the airport when entered into a field, using Visualforce.
- SIC to NAICS: I have NO idea why Salesforce CRM is so attached to SIC codes–after all, the government has completed its changeover to NAICS codes. I plan to use the existing conversion charts provided by the government to allow orgs to convert their data from SIC to NAICS.
- Google Maps as a Data Enrichment Tool: Input the ZIP Code, and Google Maps will return a city/state. Or input the Street and City/State, and Google Maps will return the ZIP Code. Sorry, DemandTools and Postcode Anywhere, this might cut into your profit margin.
- Drop.io for AppExchange: I love drop.io as a file sharing and storage tool, and with the release of their API–and Ron Hess’s explanation of his XMLDom Apex Class, it may be time to create a nice app allowing 100MB of storage per record in Salesforce CRM. It might require a couple of hacks before it can be used for more than standard objects, but this will likely be my ongoing work in progress.
- Use Amazon EC2 Windows to put the Workbench in the Cloud.
- And finally, I will spend the next year making a list of everyone I want to meet at Dreamforce 2009, and will find a way to see everyone there!
There are probably many more ideas sketched on napkins and pads of paper around my office, but this is a beginning list of projects I’m most passionate about. If anyone would like to help with any, please let me know!
X-Squared at Dreamforce 2008
Please be sure to register for sessions at Dreamforce.
And DEFINITELY don’t miss my session!
Wrangle Data & Pump up the Configuration
“I’m administering Salesforce. I’ve learned the ropes. Now I want to get great!” In this session, we’ll review the latest insights and subtlties that top Salesforce consultants have learned on the front lines. We’ll focus on data and configuration to help cut the time you spend massaging data. You’ll also learn how to implement tricky config quirks you never thought possible.
Speaker: Ezra Kenigsberg, SALESFORCE.COM
Speaker: David Schach, X-Squared On Demand LLC
Date: Monday, November 3
Time: 11:45 a.m. - 12:45 p.m.
I’m on the Administrator track - we’ll be providing tips for configuring your org implementation and optimizations, and for ensuring that things remain smooth as you move forward as a Super Administrator.
Salesforce CRM “Locale” Field
Most of the people reading this are probably in the United States, so on our User record, we have Locale set to “English (US).” This has a few effects on how we see Salesforce data, including the Calendar.
I wanted to change the first day of my week to Monday, and to see my weekends on the right-side of the 7-day view. I’ve started doing this on my Google and Outlook calendars, so why not be consistent? To do this, I changed my Locale to “English (United Kingdom).”
There’s a catch (there always is!): My dates are now reversed. D’Oh!
Time will tell if I have any other major changes to the org. I don’t mind British spellings (colour vs. color) — though I’ve found the word “color” three times since I switched. The org currency will remain US Dollars, as that is set elsewhere, in the Company Profile.
So what will I do, on the whole? I need to decide if the date format is more or less important than the week format. I’ll try out this UK thing… and will decide later.
A Super Apex/Visualforce Blog
I recently discovered a blog so chock-full of Apex and Visualforce goodies that I had to mention it.
Sam Arjmandi is a CRM System Analyst/Designer at Open Text in Toronto, and he writes incredible posts sharing some innovative Apex, Visualforce, and AJAX code ideas. He has posts on proper test coverage for Apex (always a difficult topic, and one that salesforce.com has not addressed adequately in its documentation–hint, hint), on actionStatus tags, extensions, controllers, and more.
Check out this blog and subscribe to its feed; anyone even remotely interested in developing on the Force.com platform will find it a huge resource.
Thanks, Sam!
Apex - The Basics
Jon Mountjoy has written another super post over at developer.force.com. This one is titled An Introduction to Apex. It goes through some of the basics of the language and provides some examples.
Everyone should read this; beginners will get a better orientation than otherwise available, and experienced Apex developers will probably also learn a thing or two.
Winter 09 Full Training Orgs
Sure, prerelease orgs are nice, but something’s always lacking. We have to go in and enable all the cool features, which is nice in that we learn them better, but it’s also nice to get to play in a full-featured org. Salesforce CRM (the new name) has had Exercises to teach us what to do, and I’m sure they will again this time…
Meanwhile, I stumbled upon an even better treat: Winter 09 TRAINING orgs. Yes, orgs with tons of data and all the add-ons you could ever want:
Salesforce Content
Customer Portal
Partner Portal
Advanced Currency Management
Custom Fiscal Year
Translation Workbench (and international Apex features)
Outlook Connect 3.2.501 (new version)
Cool orange highlighting of fields I’m editing in the setup area
Recruiting App
QuotePDF App
Bug Tracking
Time Card (??)
A/R Invoice
…AND all the new stuff from Winter09
Where is this? I’ll tell you:
Standard Prerelease org: https://prerelwww.pre.salesforce.com/form/trial/prerelease_winter09.jsp
Premium Training org: https://prerelwww.pre.salesforce.com/form/trial/training_winter09.jsp
Absentee Voting Forms (Necessary for Dreamforce Attendees)
I realized a while ago that Dreamforce would be on Election Day. Somehow it took a while to register (no pun intended) that I needed to fill in an absentee ballot. But where to get one?
Thankfully, there is a website devoted to absentee ballots, http://www.longdistancevoter.org/. Please go to this site and do what is necessary to fulfill your civic duty.
If you want to vote early, which is slightly different, Reed College has a super website on early voting (updated regularly) with information on each state’s policies.
And if I may, I’ll get on my soapbox now: I was born in South Africa, a country where specific groups of people were not only denied the right to vote, but were denied the right to live in certain areas and pretty much every other right that we have in this country. I became a citizen at age 12 and promised my family that I would always do whatever it took to cast a vote in every election I could. Sadly, I broke my promise when I didn’t vote in the 2004 Presidential election. Yes, Kerry carried Illinois, so in retrospect my vote didn’t “matter,” but I still feel bad about it.
Of note, in Australia, not only is it one’s civic duty to vote, but all citizens are REQUIRED to vote. Yes, that’s right. If they don’t vote, they have penalties!
And this year, absentee ballots are predicted by some to be more important than ever.
So please do two things:
- Vote. If you’ll be at Dreamforce, vote absentee. Even if you live in San Francisco, if you don’t want to miss a minute of Dreamforce, you can still vote absentee. You can send in your application pretty much anytime in the month of October, and ballots are due, in general, on Election Day.
- Join me at one of the Ballots and Beer (my label, not theirs) parties Tuesday night in San Francisco. I’m planning to find the one with the most non-profit customers and consultants, as I bet we’ll all be cheering for the same candidate.
See you at Dreamforce, as none of us will see each other at the polls.




