Pages

Sunday, October 19, 2014

Salesforce: Setup Landing Page & Force.com Quick Access Menu

Based on a best practice release by Salesforce on 2010, numbers of Salesforce administrator and business analyst depends on the size of your business, the complexity of your implementation, the volume of user requests, and so on. One common approach for estimating the number of administrators you need is based on the number of users.

Number of users Administration resources:
 001 – 030 users : < 1 full-time administrator  
 031 – 074 users : 1+ full-time administrator  
 075 – 149 users : 1 senior administrator; 1 junior administrator  
 140 – 499 users : 1 business analyst, 2–4 administrators  
 500 – 750 users : 1–2 business analysts, 2–4 administrators  
 > 750 users     : depends on a variety of factors  

For administrators who work a lot on Setup menu, here are 2 simple tips for you to access Setup menu faster (less click), both setting is available in your user detail.

Go to your user detail and activate this option:

1. Make Setup My Default Landing Page
When you enable this option for your user, once login to Salesforce, it will bring you directly to the Setup page rather than Home tab. Imagine if you mostly go to Setup page after login, how many clicks you save for a day, a week, a month... ?

2. Force.com Quick Access Menu
When you have this option enable to your user detail, you will see a small arrow at the right of the page when you click a tab, such as: Account Tab, or in page detail. Menu shown will be different in tab or page layout and also different based on the object.

Click the arrow and you will see the menu:

As admin, this will save you a lot of click as you can go directly to the Fields related to the object with one click, or go to the Object itself in Setup page, Record Type, Validation Rules, Edit Column, Edit Layout, Edit Tab until Import Data.

Note: if you override standard View page with visualforce page, Force.com Quick Access Menu will NOT shown up when you click object tab.



Wednesday, October 8, 2014

Salesforce: Related List in Page Layout

Background: we found out that Page Layouts have the same Last Modified Date by the same person, although we just update one of the Page Layout. The date shown is the latest date perform to update one of the Page Layout for that object.



Analysis
When you edit a page layout, select a Related List with Properties (tool icon) and click the icon. Many of us not aware that Apply column information to other page layouts: at below if you not scroll down.


When you scroll down, you will see all other page layouts available and they are selected by default.


Conclusion: make sure none of this checkbox is selected, otherwise it will effect:
  • Available fields, column order and Sort field asc/desc in other Page Layout selected will be overwritten
  • Last Modified Date and By in other Page Layout selected will be updated.



Friday, October 3, 2014

Salesforce: Custom Permission for Validation Rule

Custom Permission has been introduce on Summer '14 release as Developer Preview (only in Developer Edition organizations). Custom permissions let developer define access checks that can be assigned to users via permission sets or profiles, similar to how you assign user permissions and other access settings. For example, you can define access checks in Apex that make a button on a Visualforce page available only if a user has the appropriate custom permission.

You can query custom permissions to determine which users have access to a specific custom permission, use Salesforce Object Query Language (SOQL) with the SetupEntityAccess and CustomPermission sObjects.

On Winter '15 release, Custom Permission become Generally Available, and even better it is accessible via Validation Rule and Formula Field, admin should take most advantage of this enhancement.

Use Case:
Only a few people allowed to change Account Name when Type = Customer. This few people have different Profile or Role. Account OWD sharing setting is Public Read Only.

Solution: Create Validation Rule

1. Hardcode UserId or UserName
 AND(   
 $Profile.Name <> 'System Administrator',   
 $User.Id <> '00550000000rlrX',   
 $User.Username <> 'myname@mydomain.com',   
 OR(   
 ISPICKVAL(Type, "Customer"),   
 ISPICKVAL(PRIORVALUE(Type), "Customer")   
 ),   
 ISCHANGED(Name)   
 )  
** UserId = 15 characters, not 18 characters

Cons: Difficult to maintain, admin need to update each validation rules (if many) affected for maintenance.


2. Custom Setting
Create a new Text or Text Area custom field to store UserId separated by comma
 AND(  
 $Profile.Name <> 'System Administrator',  
 NOT CONTAINS($Setup.Special_User__c.UserId__c,$User.Id),  
 OR(  
 ISPICKVAL(Type, "Customer"),  
 ISPICKVAL(PRIORVALUE(Type), "Customer")  
 ),  
 ISCHANGED(Name)  
 )  
** UserId = 15 or 18 characters is fine, because we are using CONTAINS()


Setup | Develop | Custom Settings

Click Manage link | Edit button

Pros:
  • One place to store all UserIds
  • Can be used in multiple validation rules
  • Custom setting can be implement by User or Profile
Cons:
  • Admin need to keep updating User IDs in Custom Setting
  • Max length of Text or Text Area in Custom Setting is only 255 characters, so this can cover up to 16
  • IDs only.

3. Public Group
Ability to use Public Groups in Validation Rule would be ideal, but this is not exist yet. Here an idea in IdeaExchange Allow use of Public Groups from Validation Rules with 980 points right now.


4. Custom Permission
Compare to option 1 and 2, using Custom Permission would be better option. Here step-by-step to create Custom Permission and to implement it for Validation Rule.

i. Create Custom Permission
  • Setup | Develop | Custom Permissions
  • Click New button
  • Enter Label, Name and Description

ii. Create Permission Set
  • Setup | Manage Users | Permission Sets
  • Click New button
  • Enter Label, API Name, and Description
  • Click Save button
  • Click Custom Permissions link
  • Add Custom Permissions created from Step 1
  • Click Save button
  • Click Manage Assignments button
  • Click Add Assignments button, to add users
  • Select users as required
  • Click Assign button and Done

iii. Create Validation Rule
 AND(  
 $Profile.Name <> 'System Administrator',  
 NOT($Permission.Special_User),  
 OR(  
 ISPICKVAL(Type, "Customer"),  
 ISPICKVAL(PRIORVALUE(Type), "Customer")  
 ),  
 ISCHANGED(Name)  
 )  
Pros:
  • User management is control in Permission Set
  • No limitation on number of users


Reference: Custom Permissions Overview



Thursday, October 2, 2014

Chatter External license and feature

Each Salesforce org will get 5000 free Chatter Free license and 500 free Chatter External license, but I heard is possible to request for more if you purchase lot of Salesforce paid licenses.

Chatter External
This license is designed to invite customers to Chatter groups. Customers are users outside of a company’s email domain. Customers can access information and interact with users only in the groups they’re invited to. They have no access to Salesforce objects or data.

Chatter Free
The Chatter Free license is designed for users who don’t have Salesforce licenses but need access to Chatter. These users can access standard Chatter items such as people, profiles, groups, and files, but they can’t access any Salesforce objects or data. Chatter Free users can also be Chatter moderators. Chatter Free users don’t see tabs like other Salesforce users. Chatter Free users access Chatter feeds, people, groups, and files using the links in the sidebar of the Chatter page.

Chatter Only aka Chatter Plus
The Chatter Only license is also known as the Chatter Plus license. It is designed for users that don’t have Salesforce licenses but need access to some Salesforce objects in addition to Chatter. These users can access standard Chatter people, profiles, groups, and files, plus they can:
  •  View Salesforce accounts and contacts
  •  Use Salesforce CRM Content, Ideas, and Answers
  •  Access dashboards and reports
  •  Use and approve workflows
  •  Use the calendar to create and track activities
  •  Modify up to ten custom objects

Note: You can upgrade a Chatter Free license to a standard Salesforce or Chatter Only license at any time. You can’t convert a standard Salesforce or Chatter Only license to a Chatter Free license.

So, what is the difference between Chatter Free with Chatter External license in features? Here are few limitations of Chatter External license compare to Chatter Free license:

Feed
- No option for All Company feed
- Not able to Follow people

Groups
- Not able to create new Group
- Not able to see all Active Group and request to join

Topic
- Not able to search by Topic

See the difference in screenshot below:

Chatter External

Chatter Free

If you use Salesforce or Chatter Free and your business partner invite you to join their Chatter Group, you will receive email, by default, it will add guest in the username before domain name, example: yujohan@guest.gmail.com





Salesforce: Event Log Files

As of Winter '15 release, Event Log Files has been Generally Available. It contains useful information for assessing organizational usage trends and user behaviour.

However, there is no access through Salesforce user interface, you only can access the data through the Force.com REST API, this mean you can write visual force page with apex code for the UI, but fear not, I'll share few free app able to access the data.

Log files are generated asynchronous, one day after an event take place, but this should be good enough to understand your user usage. Log data is read-only, you can’t insert, update, or delete log data. It does NOT count towards org file storage.

For Production org (Enterprise, Unlimited, and Performance Edition), you need to purchase User Event Monitoring to get this feature fully activated, otherwise you will have free access to the login and logout log files with one-day data retention only. Once purchase, you can access all log file types with 30-day data retention.

Developer Edition (DE) organizations have free access to all log types with one-day data retention.
So, it is good idea to integrate this data to your back-end database for further analysis. Once it enabled, you will see object called EventLogFile from API.

Log Files have 29 event type:
• API
• Apex Callout
• Apex Execution
• Apex SOAP
• Apex Trigger
• Asynchronous Report Run
• Bulk API
• Change Set Operation
• Content Distribution
• Content Document Link
• Content Transfer
• Dashboard
• Document Attachment Downloads
• Login
• Login As
• Logout
• Metadata API Operation
• Multiblock Report
• Package Install
• Queued Execution
• Report
• Report Export
• REST API
• Sandbox
• Sites
• Time-Based Workflow
• UI Tracking
• URI
• Visualforce Request

Sample SOQL query:
Select Id, EventType, LogDate, LogFile, LogFileContentType from EventLogFile


As you can see in query result, it will create a record for each LogDate by EventType. The content is stored in LogFile and you need to read it with code, or you can use REST tool for testing. 

How to read the log file?

1. REST Explorer
Available for free from AppExchange. Once installed, you need to configure following: 
1) Configure Base URL as Custom Setting
 * Go to Setup | Develop | Custom Settings | Rest Explorer Configuration | Manage | New.
 * Set the name to 'baseUrl' and the value to your Salesforce instance, for example 'https://na1.salesforce.com'.

2) Configure a Remote Site Setting.
 * Go to Setup | Security Controls | Remote Site Settings | New Remote Site.
 * Set Remote Site Name to the name of your choice, and set Remote Site URL to the same value of the baseUrl above, for example 'https://na1.salesforce.com'.

Then you can access it through a new tab created REST Explorer. Enter LogFile value from query above to the textbox provided.


This is the result for API EventType
 Raw Response  
 Sforce-Limit-Info: api-usage=36/15000  
 Date: Wed, 01 Oct 2014 23:38:12 GMT  
 Transfer-Encoding: chunked  
 Expires: Thu, 01 Jan 1970 00:00:00 GMT  
 Set-Cookie: BrowserId=Ouz260FsTl6kC3LUW7VTQg;Path=/;Domain=.salesforce.com;  
 Expires=Sun, 30-Nov-2014 23:38:12 GMT  
 Content-Type: text/csv  
 "EVENT_TYPE","TIMESTAMP","REQUEST_ID","ORGANIZATION_ID","USER_ID","RUN_TIME","CLIENT_IP","URI","REQUEST_STATUS","API_TYPE","API_VERSION","CLIENT_NAME","METHOD_NAME","ENTITY_NAME","ROWS_PROCESSED","REQUEST_SIZE","RESPONSE_SIZE","QUERY"  
 "API","20140929223903.454","3tX96QXMYovdpU0CcVVk6-","00DB00000000Vgy","005B0000000ybnD","18","a.b.c.d","/services/data/v32.0/tooling/query/","S","","32.0","devconsole","query","UserPreference","0","","",""  
 "API","20140929223903.516","3tX96QRNJyk4QU0CcVgkAk","00DB00000000Vgy","005B0000000ybnD","105","a.b.c.d","/services/data/v32.0/tooling/sobjects/User/005B0000000ybnD","S","","32.0","devconsole","retrieve","User","1","","",""  
 "API","20140929223904.043","3tX96Se_dRhYFSHyqUDgI-","00DB00000000Vgy","005B0000000ybnD","34","a.b.c.d","/services/data/v32.0/tooling/query/","S","","32.0","","query","ApexExecutionOverlayAction","0","","",""  
 "API","20140929223904.444","3tX96U8AoglYZSHyqU0xdk","00DB00000000Vgy","005B0000000ybnD","38","a.b.c.d","/services/data/v32.0/tooling/query/","S","","32.0","","query","ApexLog","0","","",""  
 "API","20140929223905.164","3tX96WmjfEhYFhHyqUDgI-","00DB00000000Vgy","005B0000000ybnD","47","a.b.c.d","/services/data/v32.0/tooling/query/","S","","32.0","devconsole","query","IDEWorkspace","1","","",""  
 "API","20140929223905.441","3tX96Xv75g988xHyqUCmFF","00DB00000000Vgy","005B0000000ybnD","21","a.b.c.d","/services/data/v32.0/tooling/query/","S","","32.0","devconsole","query","TraceFlag","1","","",""  
 "API","20140929223905.671","3tX96YlO2KdYFhHyqUDgI-","00DB00000000Vgy","005B0000000ybnD","23","a.b.c.d","/services/data/v32.0/tooling/query/","S","","32.0","devconsole","query","MetadataContainer","1","","",""  
 "API","20140929223906.008","3tX96ZnGj1T88xHyqUCmFF","00DB00000000Vgy","005B0000000ybnD","84","a.b.c.d","/services/data/v32.0/tooling/sobjects/TraceFlag/7tfB00000000J0zIAE","S","","32.0","devconsole","update","TraceFlag","1","","",""  
 "API","20140929223906.032","3tX96Ywqmkt7BU0CcVFeSk","00DB00000000Vgy","005B0000000ybnD","337","a.b.c.d","/services/data/v32.0/tooling/sobjects/User/005B0000000ybnDIAQ","S","","32.0","devconsole","update","User","1","","",""  
 "API","20140929223906.475","3tX96a4QSch7BU0CcVFeSk","00DB00000000Vgy","005B0000000ybnD","206","a.b.c.d","/services/data/v32.0/tooling/query/","S","","32.0","devconsole","query","MetadataContainerMember","0","","",""  
 "API","20140929224424.784","3tX9P7Yw7Er2QxHyqUDeZk","00DB00000000Vgy","005B0000000ybnD","23","a.b.c.d","/services/data/v32.0/tooling/query/","S","","32.0","devconsole","query","ApexCodeCoverage","0","","",""  
 "API","20140929224425.792","3tX9P8CnQYT8ISHyqUCmFF","00DB00000000Vgy","005B0000000ybnD","856","a.b.c.d","/services/data/v32.0/tooling/sobjects/ApexClass/01pB0000000AJ6QIAW","S","","32.0","devconsole","retrieve","ApexClass","1","","",""  
 "API","20140929224426.238","3tX9PCh0VJnduE0CcVVk6-","00DB00000000Vgy","005B0000000ybnD","98","a.b.c.d","/services/data/v32.0/tooling/query/","S","","32.0","devconsole","query","ApexClass","10","","",""  
 "API","20140929224426.430","3tX9PCnNTY34WE0CcVgkAk","00DB00000000Vgy","005B0000000ybnD","262","a.b.c.d","/services/data/v32.0/tooling/query/","S","","32.0","devconsole","query","ApexClass","1","","",""  
 "API","20140929224512.669","3tX9RuvnfjKePE0CcVVMjk","00DB00000000Vgy","005B0000000ybnD","26","a.b.c.d","/services/data/v32.0/tooling/query/","S","","32.0","","query","ApexLog","1","","",""  
 "API","20140929224527.721","3tX9Sn1k6qKYfhHyqU0xdk","00DB00000000Vgy","005B0000000ybnD","17","a.b.c.d","/services/data/v32.0/tooling/query/","S","","32.0","","query","ApexLog","2","","",""  
 "API","20140929225015.272","3tX9iX7wbcq8TSHyqUCmFF","00DB00000000Vgy","005B0000000ybnD","47","a.b.c.d","/services/data/v32.0/tooling/sobjects/ApexPage/066B00000001YGXIA2","S","","32.0","devconsole","retrieve","ApexPage","1","","",""  
 "API","20140929225905.190","3tXACN8ylBSehU0CcVVMjk","00DB00000000Vgy","005B0000000ybnD","69","a.b.c.d","/services/data/v32.0/tooling/sobjects/TraceFlag/7tfB00000000J0zIAE","S","","32.0","devconsole","update","TraceFlag","1","","",""  
 "API","20140929230507.422","3tXAXSXhhkZ50U0CcVgkAk","00DB00000000Vgy","005B0000000ybnD","79","a.b.c.d","/services/data/v32.0/tooling/sobjects/IDEWorkspace/1deB00000000JIgIAM","S","","32.0","devconsole","update","IDEWorkspace","1","","",""  
CLIENT_IP has been masked.

This is the result for Report Event Type
 Raw Response  
 Sforce-Limit-Info: api-usage=37/15000  
 Date: Wed, 01 Oct 2014 23:46:38 GMT  
 Transfer-Encoding: chunked  
 Expires: Thu, 01 Jan 1970 00:00:00 GMT  
 Set-Cookie: BrowserId=Xcteq7xKS0uNZylaeBBafg;Path=/;Domain=.salesforce.com;  
 Expires=Sun, 30-Nov-2014 23:46:38 GMT  
 Content-Type: text/csv  
 "EVENT_TYPE","TIMESTAMP","REQUEST_ID","ORGANIZATION_ID","USER_ID","RUN_TIME","CLIENT_IP","URI","REQUEST_STATUS","ENTITY_NAME","DISPLAY_TYPE","RENDERING_TYPE","REPORT_ID","NUMBER_EXCEPTION_FILTERS","NUMBER_COLUMNS","SORT","NUMBER_BUCKETS"  
 "Report","20140929224335.668","3tX9MEjMd8xeOE0CcVVMjk","00DB00000000Vgy","005B0000000ybnD","520","222.165.97.180","/00OB0000000YEn2","S","","S","W","00OB0000000YEn2","0","10","","0"  
 "Report","20140929224340.773","3tX9MZQw71teOE0CcVVMjk","00DB00000000Vgy","005B0000000ybnD","68","222.165.97.180","/00OB0000000YEn2","S","","S","X","00OB0000000YEn2","0","10","","0"  
 "Report","20140929224344.199","3tX9MkwB0pk4Vz0CcVgkAk","00DB00000000Vgy","005B0000000ybnD","139","222.165.97.180","/00OB0000000YEn2","S","","S","W","00OB0000000YEn2","0","10","","0"  

Credit and thanks to Adam Torman for sharing sample code, how to access Event Log File via Visualforce and Apex code.


2. Developer Workbench
From https://workbench.developerforce.com login with API version 32.0 or beyond. Go to utilities | Rest Explorer, query with 
/services/data/v32.0/query?q=SELECT+Id+,+EventType+,+LogFile+,+LogDate+,+LogFileLength+FROM+EventLogFile
Click Execute button, it will show total record the same as you query from Developer Console.

From here, click Expand All link to see all record in detail, then click link at LogFile


It will display Raw Result the same as using Rest Explorer installed package above. You can copy and paste the result from header "EVENT_TYPE","TIMESTAMP" ... into Notepad and save as CSV file.

Sample CSV file for Event Type = ReportExport.


3. Salesforce Event Log File Browser
Go to URL https://salesforce-elf.herokuapp.com
This application is pretty simple, open the URL above, select login to Production or Sandbox and allow Salesforce Event Log File Browser to access your Salesforce data.
Once you are in, you can download each event log into CSV file.



Reference



Page-level ad