Wednesday, June 10, 2009

To Visualforce or not to Visualforce

Visualforce is a wonderful thing. User interface requests that used to be impossible or at the least very complex to implement in Salesforce are now quite do-able. The end users at my organization look at my latest Visualforce creations with eyes wide and mouths agape, dreaming of the new world of possibilities open to them. But with great power comes great responsibility, and I feel it my duty to caution people of the disadvantages of Visualforce.

There are two major down-sides to replacing standard Salesforce page layouts with Visualforce pages to be aware of going in. These don't apply to VF pages created to supplement the standard SF pages, which have no down-side that I can think of and I'll soon post about some rather nifty pages my developer-in-training and I have come up with. The first is the loss of on-demand configuration. The days of calling your SF admin, requesting a new field and having it magically appear 5 minutes later are over once you become dependent on VF for creating/editing records. Gone also are the days of non-technical power users being able to go in and quickly add or change fields. Adding new and changing existing fields, as in olden times (e.g. 10 years ago), will require a developer to make the changes in the Visualforce page, possibly in a related controller/extension as well, in the development environment, test the changes and then deploy those changes to production. If any development is already ongoing in that page, you may find yourself having to wait for that development to be completed before the developer is willing to make and deploy the change you want. Companies with larger Salesforce implementations are no doubt employing development best practices and scheduling releases of new code into production. This also applies to changes in the VF page layout; there is no dragging and dropping of elements on a VF page around as you please (not yet, anyway!).

The second down-side is that end users will become detached from the design of Salesforce objects, which is going to make report creation more difficult. As much as my users have complained that they've been forced to enter data for 3 different objects into 3 separate forms, it has at least forced them to gain a certain understanding of how all of those objects are related. That understanding is invaluable when creating SF reports. Users that are presented with a single, wondrous VF page that allows them to create and edit records across two or more objects may not even realize which objects they're interacting with, and therefore won't know where to start to create a report on that information.

The point is, Visualforce pages will make users more dependent on developers. Often, the benefits of a slick VF page far outweigh that cost, just be sure to understand that it is a cost when deciding whether or not to implement a new VF page.

Tuesday, May 26, 2009

Ding Dong, the Lotus Witch is Dead

I've known for awhile that I'd be migrating us off of Lotus Notes and into Gmail, or more specifically, Google Apps education edition, which is free for non-profits with 7 GBs of space per user. Why pay for Lotus and a Blackberry Enterprise Server and deal with all of the headaches associated with both, when Gmail more than meets our needs for free? I know there are some die-hard Lotus defenders out there, and if any happen to come across this blog, I'm really not interested in any pro-Lotus rants. All the security you've convinced yourself is there because of the mind-numbingly complex interface, it ain't there. If you've built some complex application using it, more power to you, but for anyone looking for just basic email functionality, Lotus is a poor choice.

But I didn't write this just to pick on Lotus, I thought I'd share a bit about the migration. If you talk to anyone at Google, they'll assure you that it's easy to migrate from Lotus to Gmail, that the users can do it themselves. But you know nothing's easy with Lotus. It took a lot of trial and error, but I eventually figured out how to transfer emails. What I did was to create an Email Account in Outlook that pulls from the Domino server using IMAP (don't use POP, or you'll only get emails marked as new). Connecting to Domino using IMAP didn't become available until some version of Release 6, so you're mail files will all need to be that version or later. The password to connect to IMAP is the Internet Password. Once you've created the account in Outlook, right-click on the root of the IMAP mail folder and subscribe to all of the folders. I had to create a new folder in Lotus called Sent Mail and copy everything from their Sent mail there to get it via the IMAP connection. It ends up in Sent Mail in Google. Then you can use the Google Email Uploader to transfer everything from Lotus via Outlook into Gmail.

Google Apps does provide a function to import using IMAP, but I could not get it functioning with Lotus. I kept getting an unknown error message in Google, which didn't give me much to go on, and I tried tweaking every variable that I thought might affect it. If you can get that to work, definitely go that route instead. The Outlook route works and for our organization, with only ~90 users, it was feasible to go around one by one and transfer that way, but any org with more users will probably not want to go this route. One thing we did which eased the transition was to set up users Google accounts to pull their new email from Lotus using pop3, which for some reason did work from Google to Lotus, and then transfer their historical mail with the Outlook trick. That way we were able to start moving people into Google even before our email was actually re-directed there. By the time we officially switched our MX records, a lot of people were already migrated and I was feeling pretty confident about the change.

Well that's my overview of the transition process. Not everyone will even have Outlook to use like this, and if so, you might want to try Thunderbird instead, which I believe is freeware. If anyone is considering or in the process of moving to Google and looking for more details, feel free to contact me and I'll help if I can.

Wednesday, February 11, 2009

Re-directing Salesforce users to another page

I did this awhile back and know that other organizations have similar requirements. This is an S-Control, so I'll need to re-do it in Visualforce at some point, but it works for now. What my client wanted to do was this: on saving a record, re-direct the user to a record other than the one that was just saved. In some cases, this can be accomplished by overriding the Edit button to pass the record ID you want the user to land on into the retURL parameter. But that wasn't an option here, because they wanted the user to go to a record that was being created by Apex code on save. So, I created the S-Control below and pass the S-Control's ID to the retURL parameter. It obviously needs to be tweak for use in any other Salesforce instance, but this should give anyone with a similar requirement a good starting point:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>

<script type="text/javascript" src="/js/functions.js"></script>
<script src="/soap/ajax/12.0/connection.js"></script>

<script type="text/javascript">
function initPage() {
var newid = "{!$Request.newid}";
var strSQL;
var strRe;

//Redirecting after matching child case to AP case
if (newid.substring(0,3) == "a0V"){
strSQL = "Select Id, Child_Case__c from Match_Child_Case__c where Id = '" +newid +"'";
}

//Redirecting after creating child/case
if (newid.substring(0,3) == "003"){
strSQL = "Select Id from Child_Case__c where Contact__c = '" +newid +"'";
}


if (strSQL != null){
var result = sforce.connection.query(strSQL);
var records = result.getArray("records");

i=0;

while ( i<records.length) {
var rec = records[i];

if (newid.substring(0,3) == "a0V"){
strRe = rec.Child_Case__c;
}

if (newid.substring(0,3) == "003"){
strRe = rec.Id +"/e";
}
i++;
}
}

if (strRe != null){
window.parent.location.href = "/" +strRe;
} else {
//window.parent.location.href = "/" +newid;
}
}
</script>

</head>

<body onLoad="javascript:initPage();">

</body>
</html>

Thursday, January 15, 2009

Google Maps in Visualforce

So as I go to write this, I see a project up on the Salesforce code share site for Google Maps and Earth in Visualforce. Perhaps this will still be useful to someone though, so I'll forge on. My organization tracks interviews (as a custom object) that we send our participants on and generally our Job Developers generate directions from Hopstop.com to give to them. This seemed like a good candidate for what I thought was a quick Visualforce page. I went down a few avenues trying to accomplish this, but I'll start with the path I ultimately chose and then review the options I gave up on.

What I ended up using was Google Maps for mobile devices. Why the mobile version? I wanted the maps and route in a frame because I was also including information from Salesforce about the interview. The full site was unwieldy in the frame and didn't print properly. And also because I found the parameter options for the mobile version that could easily be passed via a URL to generate the route. So here's the code that I ended up with; you'll notice some if statements in the parameters because the address used can come from two different places, but the concept should still come through:

<apex:iframe id="hopstop" height="1400px" width="600px" frameborder="true" src="http://www.hopstop.com/pda?address1=32+Broadway&county1=Manhattan&address2={!if(IsNull(Interview__c.Opportunity__r.Address__c),Interview__c.Opportunity__r.Account.BillingStreet, Interview__c.Opportunity__r.Address__c)}&county2={!if(IsNull(Interview__c.Opportunity__r.Borough__c),Interview__c.Opportunity__r.Account.Borough__c, Interview__c.Opportunity__r.Borough__c)}&language=en&mode=a&transfer_priority=1&day=1&time=50400&city1=newyork&city2=newyork&submitted=y&sid=&sub_action=" >

That frame is inside of a table with details about the interview. We're always using the same starting point since people are leaving from our office. The format for the mobile device works well for printing, the only unfortunate aspect is that the height of the frame couldn't be dynamic (100% set it to the height of the table, not the content inside the frame) so it can potentially have unnecessary space at the end.

So this ended up being pretty simple, but now for an overview of the other attempts I made just in case anyone else considers trying them. I started out playing with Hopstop.com. I was able to find some parameters that I could pass in in the URL that would set the To and From fields, but didn't actually execute the search. It was also too much having the Hopstop header, sidebar, ads and everything else included on the page that was returned, even if I could get it to execute.

Next attempt, the Hopstop API. To use the API, you have to sign up and get a key which will only work with 1 IP address. That ruled out using the API in Apex, since Salesforce could make the calls from a number of IPs and there would have been legal issues anyway. So I considered making the calls in Javascript on the Visualforce page, since it would always be called from our office here from 1 IP address. The issue there was that the API returns XML files, and Firefox (our primary browser here) has security restrictions regarding XML file transfers being called from a page on one domain to another. There's a way around this, but it involves not only changing settings in Firefox, but updating (or inserting) a config file on the user's machine. Well, we're using Salesforce so that we have a web-based application, so I wanted to avoid that method. It also just didn't seem like the best idea to be making people's browsers less secure just to display a route.

Google API, same issues as Hopstop. So I finally stumbled on the Google Mobile wiki and went with that. As is often the case when first playing with new technologies, I spent a great deal of time coming up with a rather simple solution.