Chatter and the CLM
I love Chatter. I love the way that it is a game-changer. I think that Chatter is a powerful tool. But as Peter Parker's Uncle Ben said, "With great power comes great responsibility," and with the possibility of great rewards from Chatter comes great risks.
First I'll list my conclusions, just so there's no misunderstanding. Then I'll explain some of the possible pitfalls that Chatter presents.
- Chatter is amazing. It lets users share information in ways never seen before.
- Chatter should be enabled in an org as an all-or-nothing switch - as it is now. Allowing it to be disabled for some users goes against its core purpose.
- As a single-opt-in system, the risk of Chatter-Spam is huge, but responsibility falls to each user to self-police, and probably to each company to educate its users in appropriate chatting.
Let's compare Chatter, Facebook, and Twitter in terms of what is necessary for a conversation between two people to appear in my activity stream.
Facebook is a double-double opt-in system. To see a wall post from one person to another in my stream, I must be friends with both of them, and each friendship-connection is a double opt-in, meaning that one person requests and the other approves.
Twitter is a double-single opt-in system. To see one person's reply to another, I must be following both of them. But unless one of them decides to block me, the default is that I will see the entire exchange in my twitter feed.
Chatter
Chatter is a single-single opt-in system. This means that if I post something to anyone in the org, everyone following that person will see. Here's an example: Let's assume that every user at salesforce.com follows Marc Benioff. One user posts a photo of his son's graduation to Marc. Everyone following Marc will see it.
Sounds innocuous, right? Probably. But if a user keeps posting silly things to Marc, and enough people see it, other users could become annoyed.
Take it down a level, and imagine that everyone on a sales team follows each other. A junior AE keeps sending silly stuff to the strongest seller in the group, and all the sales people have to see it. This could clog their streams.
This is called a CLM: A Career-Limiting Move. As great power requires great responsibility, we must ask who should shoulder this responsibility.
- The company: Training for users and a quick eye to bring inappropriate chatters into line.
- Individuals: Just be careful. This is the Facebook public-posting dilemma. Don't forget that you have no control with whom you are connected, so anyone who wants to follow you will see anything you post, and anyone who follows someone you post to will see it as well.
The solution is NOT to turn off Chatter for certain people - Chatter is about the free-flow of data across an org, organized into forms that make it useful information. By putting information at the fingertips of every user, productivity will be increased.
Blocking people is also not a good solution.
Chatter Groups (Safe Harbor Statement!) will help, but will attenuate, not completely remove, the chances that this will happen.
Salesforce CRM should be a "sticky" app - that is, it should provide services in one place so that users see it as their central point of information. The best way to ensure the free-flow of information is to prevent blocking of certain users.
Sophisticated DateTime “Formula Fields” with Apex and Field-Level Security
What do you do when you want to calculate a formula-like field but a regular formula won't work?
Salesforce CRM's formulas handle dates very well. If you want to enter a date value and have formula fields display, for instance, mydate__c + 21 days, that's simple. Just use mydate__c + 21.
Side note: If you try going the long way around and use DATE( YEAR( mydate__c ), MONTH( mydate__c ), DAY( mydate__c ) + 21 ) and mydate__c = 09/17/2010, Salesforce returns #Error! because there's no date 09/38/2010. Similarly, adding three months to a date like 1/31/2010 will also give an error. More about this in a future post.
DateTime fields are like Date fields, but they include... wait for it... a time component (and can be created in the running user's local time zone or in GMT).
Here's a use-case for a DateTime formula field:
A photography studio schedules photo shoots, and different packages include different durations. Similarly, we could use a hair salon which offers different services, each with a different duration, a dentist... you get the idea.
Requirements:
- Enter a DateTime for an appointment start time (
starttime__c) - Enter a duration (though in a production system, I'd include a value on the
Product2sObject, we'll just enter a value here) (minutes__c) - Display a read-only DateTime field with the end time (
endtime__c) - The end time must be read-only to all users, like any formula field
Here's what won't work:
- A formula field won't work because there are no MINUTE(), HOUR(), SECOND() formula functions
- Workflow won't work because it depends on formulas to fill new values for date/datetime fields
That leaves Apex. First, the configuration:
- Create DateTime field
starttime__c - Create DateTime field
endtime__c - Set
endtime__cfield-level security to Read-Only for all profiles - Create Number (18,0) field
minutes__c - Create a trigger on the sobject
Here's the trigger:
trigger timeTrigger on TestObject__c (before insert, before update) {
for (TestObject__c t : Trigger.New){
if(t.StartTime__c != null && t.minutes__c != null){
datetime myDateT = t.StartTime__c;
double d = t.minutes__c;
Integer shootmins = d.intValue();
if(mydateT != null && shootmins != null)
t.EndTime__c = myDateT.addminutes(integer.valueof(shootmins));
}
}
}
Regular readers will note that I do usually split triggers into a trigger and a class, but I've not done so here purely for the sake of brevity.
Here's the test code:
public without sharing class shootTimesTriggerTest {
private static testMethod void ShootCalculateEndTime_PositiveTestCases() {
TestObject__c to;
TestObject__c l;
test.starttest();
l = new TestObject__c (name = 'test');
datetime myDateTime = datetime.newInstance(2008, 12, 1, 12, 30, 2);
l.StartTime__c = myDateTime;
l.minutes__c = 90;
insert l;
to = [SELECT id, EndTime__c FROM TestObject__c WHERE id = :l.id];
datetime newDateTime = datetime.newInstance(2008, 12, 1, 14, 0, 2);
system.assertequals(to.EndTime__c, newDateTime);
l.minutes__c = 45;
update l;
to = [SELECT id, EndTime__c FROM TestObject__c WHERE id = :l.id];
newDateTime = datetime.newInstance(2008, 12, 1, 13, 15, 2);
system.assertequals(to.EndTime__c, newDateTime);
test.stoptest();
}
private static testMethod void OppCalculateEndTime_NegativeTestCases() {
test.starttest();
TestObject__c l = new TestObject__c (name = 'test');
l.minutes__c = null;
insert l;
system.assertequals(l.EndTime__c, null);
test.stoptest();
}
}
A few points about how this works:
- Triggers run in System mode, so they don't respect field-level security. Thus, we can set a field to read-only for all profiles, and the EndTime__c field will still be updated.
- The test code runs in System mode as well, avoiding any potential problems if the field were set to invisible to a profile and we used System.RunAs() to test for various profiles.
- Although I'm not a fan of using SOQL queries this often, I used these in the interest of saving time. Keep in mind that if you had quite a few queries in your regular code, adding these two might put you over the limit, so use queries sparingly!
- This is the only way I know of to add minutes to a DateTime.
Did I miss anything? Please let me know in the comments.
Extended NA1 Maintenance Next Weekend (3/20)
Next weekend, March 20, 2010, Salesforce NA1 will be down for an extended (8-hour) maintenance window - the longest in memory - from 7pm 3/20 to 3am 3/21 (All times PST).
Overlapping this is another 8-hour window for NA0 (SSL) starting two hours earlier.
Also starting at 7pm PST, EU0 (EMEA) will be down for 2.5 hours.
All other instances will be down for 30 minutes, from 9pm PST.
As the email from salesforce.com explains:
![]() |
|
Dear Salesforce Administrator, At salesforce.com, customer success through system availability and reliability is our top priority. As part of our ongoing plan to deliver high availability and reliability, we are enhancing our service infrastructure on our NA1 instance. Please be aware that salesforce.com will be performing scheduled maintenance that will extend beyond standard system
maintenance windows. The current scheduled window is: Saturday, March 20th, 2010 from 7:00pm PST to Sunday, March 21st at 3:00am PST During this time, the salesforce.com NA1 service will be unavailable. Users attempting to access the service during this time will be presented with a scheduled maintenance notification page.We appreciate your patience during this maintenance window. Best regards, |
Copyright 2000-2010 salesforce.com - All rights reserved - Various trademarks held by their respective owners Salesforce.com, One Market Street, Suite 300, San Francisco, CA 94105 |
|
New Opportunity Page Layout – With Highlights Panel!
Yesterday, I enabled the new Opportunity page layout in my Developer Spring ’10 Preview org, and it took a few steps, so I thought I’d share them with you.
Firstly, you’ll need to contact salesforce.com to get this feature enabled.
Then be patient. It takes a minute or two for the update to propagate. Clearly, something was churning in the Force.com platform background!
Now we’ll navigate NOT to the Setup | Customize | User Interface screen (where this should be enabled). Instead, we’ll go to the Opportunity Page Layout screen.
Follow the cool prompts. They make it so easy, a … well, you know what I mean.
Note: You can only show fields in the Highlights Panel if they are in the page layout. (I have a feeling this has to do with Professional Edition or printable layouts, but I’m just guessing.)
Once you’ve done this for each page layout, click on the big button.
At this point, each user can enable the bar. I have no idea why the admin can’t just force this on all users – or maybe I missed something – but it seems to be an opt-in feature.
Here’s the link to enable the feature. Of course, you may wish to watch a video as well!
And here it is!
It’s interesting that if you have this enabled, certain user interface settings (yes, at Setup | Customize | User Interface) cannot be changed:
Here’s my prediction: We will start to see two major mistakes during Salesforce demos:
- We will continue to see the link asking if we want more information on inline editing (after more than a year, it’s time to turn that off, people).
- At the top of the Opportunity detail page, we will see this link.
And I will continue to think less of all demonstrators who make these mistakes.
Happy Spring 2010!
Get Documents and Attachments out of Salesforce
As Content will be included in all Salesforce licenses (for completeness, I'll add 'to some degree') with the Spring '10 release, orgs will be faced with the daunting prospect of getting their documents and attachments out of Salesforce and into Content.
I had this problem when Content was first released and I was asked to be one of the first SysAds to use it. At the time, we used Solution 1 (below), but since then, other products have been released to help with this.
Why is it even an issue?
- Surely we can download each file? Yes, but who wants to?
- Can't we do a Data Export and then upload those to Content? Yes, but all the files are renamed with their 15-character Ids, making renaming them all-but-impossible.
salesforce.com and DreamFactory to the rescue!
Solution 1
Summary: Use a script to rename all exported files. A (wonderful!) salesforce.com employee, Nick Marcantonio, wrote a Perl script to perform the transformation. Here it is, in all its glory:
# Nick Marcantonio
# nmarcantonio at salesforce.com
# 08/07
$file = 'Attachment.csv';
open (F, $file) || die ("Could not open $file!");
$line = <F>; #read first line which is nothing but column headers
while ($line = <F>)
{
($id,$name) = split ',', $line;
chomp($id);
$id =~ s/\"//g;
chomp($name);
$name =~ s/\"//g;
#print "$id : $name\n";
$result = rename($id, $name);
#print "$result\n";
}
close (F);
The instructions:
If you've done a data export you've noticed that all attachments are placed in the Attachments subfolder and named with their salesforce ID, not the actual file name or extension. One must then consult the Attachment.csv file included in the data export to find the name associated with the ID and rename the file. Attached to this solution is a Perl script that will rename all of the exported attachments to their proper names. Please follow these steps to run this: 1. Perform a data export and unzip the resulting zip file 2. Launch the data loader and export from the Attachments table ONLY the Id and Name column. This file must be named Attachment.csv. 3. Install ActivePerl. This will allow perl scripts to be run on a Windows machine. ActivePerl is available here (http://www.activestate.com/activeperl). 4. Copy the Attachment.csv file and the attached AttachmentParser.pl file to the Attachments subdirectory of the data export. 5. Double-click on AttachmentParser.pl. All of the files named with their salesforce IDs will be renamed with their proper names and file extensions. (This solution will work for documents as well. Follow the same procedure and be sure to name the extract from the Documents table Attachment.csv)
Note: This will not preserve folders, as far as I know. You may be able to recreate this by exporting the Folder table and doing some work on that, as the Document table does include a FolderId column.
A heartfelt thank-you to Nick Marcantonio for his help!
Solution 2
Install DreamFactory's FREE DreamTeam Document Management application from the AppExchange to drag-and-drop your Documents to your desktop.
This doesn't work with Attachments, though, so you may need to use another method for them.
Please let us know how it goes - good luck and enjoy Content!














