Wednesday, August 28, 2013

Salesforce Sandbox Organization ID

Do you aware when you refresh your Salesforce sandbox (Developer, Developer Pro, Partial, Full), the instance Organization Id will be changed? It mean, when we refresh a sandbox, Salesforce will create a new sandbox with new Organization Id. When we activate the refresh sandbox, old sandbox will be deleted.

The same for the instance name (cs1, cs2, etc...) in the refresh sandbox, you may get the same instance or different instance, it depends on when you refresh it, remember Sandbox preview window.

In previous blog, we discuss using $Organization.Id in validation rule to make sure the rule only run in production instance.

BUT, be aware that Salesforce will automatically change the value of Organization Id in Validation Rule and Workflow formula when you use $Organization.Id formula of production instance.

Formula example:
Website = '' && $Organization.Id = '00D90000000KY45'

In the new sandbox refresh or create, Salesforce will update all Validation Rules and Workflows in the new sandbox to:
Website = '' && $Organization.Id = '00D90000000OWqj'

This mean, you need to update $Organization.Id value in the validation rules and workflows with Production Org Id again if you plan to make the rule or workflows not work for sandbox.

ReferenceSandbox Setup Tips and Considerations.

Salesforce: Close Date and relation with Current Quarter

In some organizations, Sales Ops team need to control that Close Date for Closed Won opportunity, user should not able to enter any date or change it after Closed Won, because it will effect to forecast, report, and maybe commission.

Here are few use cases related to Close Date with Closed Won opportunity.

1. When user change Opportunity Stage to Closed Won, Close Date must be Current Quarter or after.
Use validation rule below. Of course, you can add exception to the rule not valid for particular profiles.

ISCHANGED(StageName) &&
TEXT(StageName) = "Closed Won" &&
IF (
( YEAR( CloseDate ) < YEAR( TODAY() )) ||
((YEAR( CloseDate ) = YEAR( TODAY() )) && (( MONTH( TODAY() ) >= 4) && ( MONTH( TODAY() ) <= 6) && ( MONTH( CloseDate ) < 4))) ||
((YEAR( CloseDate ) = YEAR( TODAY() )) && (( MONTH( TODAY() ) >= 7) && ( MONTH( TODAY() ) <= 9) && ( MONTH( CloseDate ) < 7))) ||
((YEAR( CloseDate ) = YEAR( TODAY() )) && (( MONTH( TODAY() ) >= 10) && ( MONTH( TODAY() ) <= 12) && ( MONTH( CloseDate ) < 10)))

2. Once the Opportunity has been update to Closed Won, user is not allowed to change the Stage OR change Close Date to different Quarter with stored Close Date.
Same as above, you can add expection to particular profiles.

(ISCHANGED ( StageName ) &&
ISPICKVAL (PRIORVALUE ( StageName ), "Closed Won"))
(ISPICKVAL (StageName, "Closed Won") &&
AND( MONTH(PRIORVALUE( CloseDate )) <= 3, MONTH( CloseDate )<=3, YEAR(PRIORVALUE( CloseDate )) = YEAR( CloseDate )), FALSE,
AND( MONTH(PRIORVALUE( CloseDate )) > 3, MONTH(PRIORVALUE( CloseDate )) <= 6, MONTH( CloseDate ) > 3, MONTH( CloseDate) <= 6, YEAR(PRIORVALUE( CloseDate )) = YEAR( CloseDate )), FALSE,
AND( MONTH(PRIORVALUE( CloseDate )) > 6, MONTH(PRIORVALUE( CloseDate )) <= 9, MONTH( CloseDate ) > 6, MONTH( CloseDate) <= 9, YEAR(PRIORVALUE( CloseDate )) = YEAR( CloseDate )), FALSE,
AND( MONTH(PRIORVALUE( CloseDate )) > 9, MONTH(PRIORVALUE( CloseDate )) <= 12, MONTH( CloseDate ) > 9, MONTH( CloseDate ) <= 12, YEAR(PRIORVALUE( CloseDate )) = YEAR( CloseDate )), FALSE,

3. Similar  with point 2, once the Opportunity has been update to Closed Won, user is not allowed to change the Stage OR change Previous Quarter Close Date OR change Close Date to Previous Quarter.

(ISCHANGED ( StageName ) && ISPICKVAL (PRIORVALUE ( StageName ), "Closed Won"))
TEXT(StageName) = "Closed Won" &&
AND(MONTH(Today()) <=3, CloseDate>=DATE(YEAR( today()),1,1), PRIORVALUE(CloseDate)>=DATE(YEAR( today()),1,1)), FALSE,
AND(MONTH(Today()) >3, MONTH(Today()) <=6, CloseDate>=DATE(YEAR( today()),4,1), PRIORVALUE(CloseDate)>=DATE(YEAR( today()),4,1)), FALSE,
AND(MONTH(Today()) >6, MONTH(Today()) <=9, CloseDate>=DATE(YEAR( today()),7,1), PRIORVALUE(CloseDate)>=DATE(YEAR( today()),7,1)), FALSE,
AND(MONTH(Today()) >9, MONTH(Today()) <=12, CloseDate>=DATE(YEAR( today()),10,1), PRIORVALUE(CloseDate)>=DATE(YEAR( today()),10,1)), FALSE,

Monday, August 26, 2013

Salesforce: Activities Tab and View (Event or Task)

Question: do we have Activity tab in Salesforce? or Activity view in Salesforce?

The answer is YES, but not Out-of-the-box, you need to create it. Here are few options you can create Activity tab / view.

1. Custom Link
I just discuss on Custom Link in previous blog. So, you can create a new Custom Link and add it into Home Page Components then to Home Page Layout. remember you can create multiple Home Page Components with type = Links with different Links as the need. Create a new Custom Link:
- Set the Behavior = "Display in existing window without sidebar or header"
- Button or Link URL =  (change xxx to your Salesforce instance, e.g. na1 or ap1, etc)
So, instead of click tab, user need to click a link in left sidebar. Using this option will save you 1 tab usage, unless you are on Unlimited Edition or Performace Edition, you only can create maximum of  25 tabs for Enterprise, 10 tabs for Professional and 5 tabs for Group Edition.

  • You can enable "Show Custom Sidebar Components on All Pages" from Setup - Customize - User Interface to enable each tab showing the same sidebar component.
  • You can use as well, this will show view without New Event button or for view without both New Event and New Task button.

2. Web Tab
You can create Web Tab from Setup - Create - Tabs, Scroll to Web Tabs related list and click New button
But, there is NO option to hide header, so you will see double Salesforce header, this is not a good option, and we need to avoid this option actually.

3. Visualforce Tab
Same with option 2 above, but we need to create a very simple visualforce page (don't be afraid if you are not a Salesforce developer, just copy scripts from below). Go to Setup - Develop - Pages, click New button, enter the label and name, then copy and paste script below and click Save button.
<apex:page >
<apex:enhancedList type="Activity" height="600" />
Then go to Setup - Create - Tabs, scroll to Visualforce Tabs related list and click New button, select visualforce page just created in dropdown list to create a tab for Activity.

Note: you need to enable Visualforce page to all Profiles will use this tab or add in Permission Sets for particular users. This will also count to 1 usage of Custom Tab.

If you notice, using visualforce page, you will not see Calendar buttons above Activities view, it only appears when direct access to URL (example: using custom link)

Using both options, you can create and edit View the same as other objects view usage.

Thursday, August 22, 2013

Salesforce: Custom Links in Home

If you are looking at Salesforce Setup menu, there is a sub menu under Home called Custom Links.

When you click that menu, you can add or edit existing custom links. You need to select content source of custom links from: URL, Custom S-Control (depreciated), onclick Javascript or Visualforce page.

If you create new custom link, once done, click Save button and it will show you a message "The new custom link will not be displayed to users until you create a custom links component and then add that component to a home page layout."

What is above this message mean?
1. Go to Home Page Components in Home setup menu.
Click New button, select Type = Links, and give a name, example: Johan's Custom Link. You should see the custom link label just added, select it and click "Add" arrow button.

2. Go to Home Page Layouts in Home setup menu.
Select any layout needed, click Edit button and tick component you just added in Narrow Components to Show, then arrange the order.

3. How it will be shown in Salesforce?
Click Home tab. You should see a component of custom links.

Summary: by using Custom Links in Home within a component, you can add many useful links for your Salesforce users if the links do not need to be a tab.

Monday, August 19, 2013

Salesforce: Lookup Filter

Lookup relationship is one of the best feature in Salesforce, you can easily link one object to other object. Furthermore, you can create filter in lookup field using Lookup Filters.

Lookup Filters are administrator settings on lookup, master-detail, and hierarchical relationship fields that restrict the valid values and lookup dialog results for the field.

As of now, Salesforce supports lookup filters on relationship fields that point to:
  • Accounts
  • Assets
  • Contacts
  • Entitlements
  • Quotes
  • Service contracts
  • Users
  • Custom objects

For example, you can define a lookup filter on opportunities that points to accounts, but not vice-versa.
In coming Spring '14, Salesforce add support for lookup filters on relationship fields that point to the following objects: Campaigns, Cases, Contracts, Ideas, Leads, Opportunities, Products, and Social Personas. Also added a Related Lookup Filters node to all newly supported objects in Setup menu.

Sample: User would like to see Contact only from same selected Account in the Opportunity.
You can easily using Lookup Filter to achieve this. Add Filter Criteria, Filter Type, Lookup Window Text and option to Active the filter.

If you edit page layout, you will see Contact here will depend on Account.

Here is screenshot when user click Edit in page detail, see Account name, when Account change, Contact will become not valid and user have to select Contact from new Account selected.

Related Lookup Filters
You can easily identify if an object is filtered by other object. In sample above, Contact is filtered in Opportunity object. Instead go to Opportunity field or any other object one-by-one, you can check all in Contact object Related Lookup Filters; go to Setup - Customize - Contacts - Related Lookup Filters

Thursday, August 15, 2013

Salesforce: How to Make Validation Rule only effect for Production Instance

Background: how to make certain Validation Rule only effect for Production instance, but not in sandbox instances?

1. Deactivate the validation rule in sandbox
This is very basic and simple solution, it works, but not really nice if you have many validation rules need to deactivate in sandbox, admin need to deactivate each validation rule in all objects.
Also, when sandbox refresh, admin need to re-deactivate all validations rule again.

2. Modify the validation rule only work in Production instance
Step 1. Get your Salesforce Production Organization Id
Go to Setup - Administration Setup - Company Profile - Company Information
Look for Organization ID

Step 2. Add Organization ID into validation rule
Example, your current Validation Rule error formula:
Type__c = "A" & Amount < 1000
Modify this to:
Type__c = "A" && Amount < 1000 && $Organization.Id='00D300000000SHq'

Done, but see this blog that Salesforce will automatically change the value of Organization Id in Validation Rule and Workflow formula when you use $Organization.Id formula of production instance.

Tuesday, August 13, 2013

How to check Record Type enabled for Salesforce Profiles easily?

To check if a record type is enabled for specific profile is easy, just open the profile and scroll to "Record Type Settings" sections. You can see and edit record type for specific standard or custom object. But, hang on, how about if I have 100 profiles? It mean, you need to open all 100 profiles and check it one by one. Hmm, not a good idea.

As of now (Summer '13 Release), there is no way to check this in Salesforce easily - which profiles are enable to specific record type. Admin have to manually open each profiles, then scroll to "Record Type Settings" section to check if the record type is enable for that profile. Can you imagine manual work if you have 100 profiles?

There is an idea posted in IdeaExchange, you are welcome to vote it

Use IDE to identify which profiles have record type enable in specific object easier.

Here we go:
1. Open IDE (assume you have install IDE, if not Google it)

2. Add objects and profiles related into IDE
Make sure to include ALL objects you want to check into Project Contents in IDE, otherwise you will not see the record type information in the profile.

3. Open the Profile
Yes, you need to open all profiles in IDE, but of course this is faster and easier than open each profile in Salesforce. Look for <recordTypeVisibilities> tag, and you will see <visible> and <default> tags inside. Record Type with visible = true is Enabled for that profile; and for default = true is default record type when user create new record in Salesforce

Next, can we update using IDE?
Yes, you can just simply change the value from false to true; or from true to false. Once you save in IDE, it will save in Salesforce instantly.

Have fun....

Sunday, August 11, 2013

Mass update Chatter user Email Setting

With CollaborationGroupMember object, you can mass add users using API tools, such as: Data Loader. We discussed on how to add users to Chatter group in this blog.

By default, email setting for each user in a group will be Daily Digest, whether you create using API tool or add users manually in

But, is there anyway to mass update email setting, let's to Weekly Digest, Every Post or even Turn Off?

YES, you can use the same object CollaborationGroupMember with API tool. When you insert users to a group with field: CollaborationGroupId (for Chatter Group) and MemberId (for User). There is another field  NotificationFrequency in the same object, this field use to set email alert for each user in a Chatter group.

CollaborationGroupMember object is available in API version 19.0 and later. This field can only be set by the member or users with the “Modify All Data” permission. The valid values are:
• D - Daily
• W -Weekly
• N - Never
• P -  On each post

Done, hope this blog help.

Tuesday, August 6, 2013

Salesforce: FeedTrackedChange

In previous blog, we touch on FeedTrackedChange object, this object is use to store individual field change, with information: FieldName, OldValue, NewValue. A FeedTrackedChange is a child object of a record feed, such as AccountFeed, ContactFeed, etc. This object is available in API version 18.0 and later.

Although this object is query-able as it said in the SOAP API Developer's Guide.

But, if you look at IDE, there is no access to this object.

What does it mean? Meaning you cannot query this object directly. See this query:
SELECT FieldName, OldValue, NewValue FROM FeedTrackedChanges
Above query will throw error 'sObject type FeedTrackedChanges is not supported'.

FeedTrackedChange records for standard feeds can only be queried via the parent feed object. A standard feed is a record feed, such as AccountFeed. Sample:

SELECT Id, ParentId, (Select FieldName, OldValue, NewValue FROM  FeedTrackedChanges), CreatedDate FROM AccountFeed WHERE ParentId = '0015000000o0WUd' 


SELECT Id, ParentId, (Select FieldName, OldValue, NewValue FROM  FeedTrackedChanges), CreatedDate FROM FeedItem WHERE ParentId = '0015000000o0WUd'

Reference: FeedTrackedChange

Monday, August 5, 2013

Salesforce: ISBLANK() or ISNULL()

To determine if an expression has a value or not, you can use ISBLANK() function in Salesforce. It will  returns TRUE if it does not and if it contains a value, this function returns FALSE. You can use this function in formula field, validation rule, and workflow.

Syntax: ISBLANK(expression) -- replace expression with the expression you want evaluated, sample: IF(ISBLANK(Main_Amount__c), 0, 1)

A field is not considered as empty if it contains a character, blank space, or zero. For example, a field that contains a space inserted with the spacebar is not empty.

When using this function with a numeric field (currency, number, and percent field type) for a formula field, choose Treat blank fields as blanks in the Blank Field Handling section. Otherwise, if you choose Treat blank fields as zeroes, it will gives the blank field value with zero, so none of them will be null. While it will work in validation rule and workflow without exception as in Formula field.

ISBLANK() work with following fields type: Text, Email, Text Area, Picklist (Multi-Select)NumberCurrency, and Percent.
But, it does not work directly with fields type: Picklist, Long Text Area, and Rich Text Area.

For Picklist field, we can use TEXT() function before ISBLANK(), example: ISBLANK( TEXT(Ini_Picklist__c) ) or ISPICKVAL(Ini_Picklist__c, "").

For Long Text Area and Rich Text Area field, instead of using ISBLANK(), use LEN() function, example: LEN(Ini_Long_Text_Area__c) = 0, but not for formula field.

** Long Text Area and Rich Text Area field is not supported in Formula field.

You also can use BLANKVALUE() function to determine if an expression has a value and returns a substitute expression if it does not. If the expression has a value, returns the value of the expression.
BLANKVALUE(Payment_Due_Date__c, StartDate +5)
Use the same data type for both the expression and substitute_expression.

How about ISNULL() ?
Use ISBLANK instead of ISNULL in new formulas. ISBLANK has the same functionality as ISNULL, but also supports text fields. Salesforce will continue to support ISNULL, so you do not need to change any existing formulas.

The same goes for NULLVALUE(), it is similar with BLANKVALUE(), with exception:
  • Avoid using NULLVALUE with text fields because they are never null even when they are blank. Instead, use the BLANKVALUE function to determine if a text field is blank.
  • Don’t use NULLVALUE for date/time fields.

Sunday, August 4, 2013

Salesforce: Enable Feed Tracking versus Set History Tracking

Few months back, I wrote a blog on Chatter feed item and the structure, that blog explain on "Feed Tracking" and the data structure. When selected fields are enable for feed tracking, any changes to those fields will be shown in the record Feed. You can find this feed at top of page layout,

If user change value of more than 1 field in one update, it will be captured into only one feed (no matter how many fields are changed).

You can hide feed by click "Hide Feed" link or click "Fewer Updates" in Show: to show only feed created manually (Feed automatically created by Feed Tracking will not shown).

Feed Tracking is stored in a new object, end with suffix Feed (for Standard object) or __Feed (for Custom object). If you dig further, records created by feed tracking have API Type = TrackedChange, for other Type:
  • ContentPost - an uploaded file on a feed
  • LinkPost - a URL posting on a feed
  • PollPost - a poll posted on a feed
  • TextPost - a direct text entry on a feed
You also can find the exact same value in FeedItem object (with API version 23.0 or later).
SELECT Id, CreatedDate, CreatedById, CreatedBy.FirstName, CreatedBy.LastName, ParentId, Type, Parent.Name, Body,
(SELECT ID, FieldName, OldValue, NewValue FROM FeedTrackedChanges ORDER BY ID DESC)
FROM FeedItem
From above query, you can see FeedTrackedChange is linked to FeedItem object (using FeedItemId field) and use to store field name, old and new value. FeedTrackedChange object start with prefix 0D6 and FeedItem start with prefix 0D5. 

While for Set History Tracking, it have almost the same function with feed tracking to track field change, but it stored in different object and for different purpose.

1. Record end with prefix History (for Standard object) or __History (for Custom object).

2. Every field change will have own record in history object, and directly linked to the ParentId.

3. User can easily run History report to display values change related to the object.