Thursday, August 13, 2015

[Salesforce / Apex Formula] Help me testing my Apex Formula Algorithm!

This is a call to arms!

In the past months I have developed an implementation in Apex of Salesforce Formulas in order to have a way to use a formula result dynamically without the need to have a custom field on an object.

It has been a huge work and a lot has still to be done, but I need your help to create a big testbook of formulas, in order to point out bugs, errors, and wathever is bad in this implementation.

This implementation supports (syntax guide here):
  • Base object fields (e.g. MyField__c == 4)
  • Lookup fields (e.g. Relation__r.Account.Name == 'ACME')
  • Constants (e.g. $PI, EE, $TODAY, $NOW, $RANDOM
  • Logical operators in function style or inline (e.g. AND(true,false) ; true && false)
  • IF and CASE flow expressions (e.g. IF(true,1,0) )
  • Various String functions (e.g. LEFT("String",2) )
  • Various Math functions (e.g. POW(2,5) )
  • Type conversion functions (e.g. DATE("2015-05-23") )
  • DateTime functions (e.g. DATETIME(2015,12,01,0,0,0) ; ADDYEARS($TODAY, 10) )
  • Multiline comments
  • Access to Hierarchy Custom Settings (e.g. $Setup.HierarchyCS__c.Value__c)
  • Access to Hierarchy Custom Settings (e.g. $Setup.ListCS__c["aName"].Value__c)

You can set different return types:
  • DATE

For the NUMBER return type you can also set a Scale attribute.

Once released the method call will be something like:

String formula = 'IF(NumberOfEmployees > 15, NumberOfEmployees, NumberOfEmployees/2)';
String objectId = '001000000123456789AAA';
String objectType = 'Account';
String returnType = 'NUMBER';
String scale = 2;
ApexFormulaResult formulaResult = ApexFormulaParser.evaluate(formula, objectId, objectType, returnType, scale);

Here is the Apex Formula Playroom I've built with Salesforce Site.

I've create a custom object, TestObject__c, which you can select to try the algorithm, which has all kind of Salesforce fields.

This is the raw interface of the playroom:

  1. List of all custom objects you can use (if you need more tell me!). Click on the name to select it.
  2. These are the details (with the objects field API names) of the selected object
  3. You can also test custom settings as well
  4. You can select a built-in formula or you can set a specific Output Type and Scale
  5. Formula's body and any suggestion you want to give me, and the formula result as well

Every formula you input and calculate is stored in the Site, so please avoid using personal informations that you don't want to share!

Feel free to break down my code, I expect a lot of work in error handling, but the awesome Developer Salesforce Community< is here to help, isn't it?

And remember:

Tuesday, August 11, 2015

[Salesforce / Apex] Can I find out if the current user has access to a record?

Yes you can!

And this is quite simple!
Query the UserRecordAccess object to have instant access to the following informations about a record and an user:

  • HasDeleteAccess: user has delete access on the record
  • HasEditAccess: user has edit access on the record
  • HasTransferAccess: user has transfer access on the record
  • HasReadAccess: user has read access on the record
  • MaxAccessLevel: picklist that tells the maximum access level on the record (None, Read, Edit, Delete, Transfer, All)
  • HasAllAccess: user can share the record

Here is a simple query (on a Case object):

List<UserRecordAccess> accessToRecord = [SELECT RecordId, MaxAccessLevel FROM UserRecordAccess WHERE UserId = :UserInfo.getUserId()  AND RecordId = '500000000000001AAA'];

On API 29.0 and earlier we have few limitations on SOQL:
  • When the running user is querying a user's access to a set of records, records that the running user does not have read access to are filtered out of the results.
  • When filtering by UserId and RecordId only, you must use SELECT RecordId and optionally one or more of the access level fields:HasReadAccess, HasEditAccess, HasDeleteAccess, HasTransferAccess, and HasAllAccess. You may include MaxAccessLevel.
  • When filtering by UserId, RecordId, and an access level field, you must use SELECT RecordId only.

Quite simple, it has been added since plaftorm version 24.0 but I discovered it few days ago!

Friday, August 7, 2015

[Salesforce / Trailhead] Trailhead MEGA RELEASE (DF15 Edition)

Dreamforce '15 is coming and with it we expect awesome news from the event.

I won't be part of it, and this is a super duper sad thing (I REALLY wanted to watch the Foo Fighters live :( ), but this does not stop me from following the event from home.

If the online stuff is not enough, you can do the Get Ready for Dreamforce trailhead module, an interesting and funny module to discover the most important things of the event: agenda, places, social media infos (who to follow to be uptodate), where to get free gadgets (and swag) and some important details about San Francisco (weather, what to pack in your baggage).

I'm not gonna be preset at DF15 but doing this modulo I almost cried thinking of how cool it would be to be there! year Salesforce...I promise...

[sniff ... wipe away all tears ... pretending nothing happened...]

The next trailhead modules I've succesfully passed (I'm quite a maniac about those kinds of gamifications) are CRM Basics, Accounts & Contacts and Leads & Opportunities: these are super basic modules for Salesforce noobs that introduce you in an easy and funny way to the use of the basic standard entities of Salesforce CRM, that is Accounts, Contacts, Leads, Opportunities.

Even if you are an experienced Salesforce Admin/Dev, try these modules: as I always say, there is something new to learn, expecially in things you are sure you master!

The last module added to this MEGA RELEASE is a cool modulo about a feature I promised myself to study but I unfortunately had no time to get deep on: Event Monitoring.

This is a cool new feature that came with Summer '15 Platform Release: you can extract events that occur on your ORG, using the new EventLogFile object.

An event could be a login, logout, report exportation, Visualforce load, Sandbox creationg/update, API call, etc.

The events can be extracted via REST APIs: if you are not a DEV the modulo will teach you how to make a REST API call.

And if you don't want to make a REST API call at all, you can download every log files usign the Salesforce Event Log File Browser app:

Here are the supported events (29):

  • Apex Callout
  • Apex Execution
  • Apex SOAP
  • Apex Trigger
  • API
  • Async Report
  • Bulk API
  • Change Set Operation
  • Content Distribution
  • Content Document Link
  • Content Transfer
  • Dashboard
  • Document Attachment Downloads
  • Login
  • Login As
  • Logout
  • MDAPI Operation
  • Multiblock Report
  • Package Install
  • Queued Execution
  • Report
  • Report Export
  • Salesforce1 Adoption (UI Tracking)
  • Sandbox
  • Sites
  • Time-Based Workflow
  • URI
  • Visualforce

One of the best examples that the module points out is the "Monitor of data loss":
...Imagine that a sales representative leaves your company and joins a major competitor. Later, you find out that your organization is losing deal after deal to this other company. You suspect that your former employee downloaded a report containing leads and shared it with the competition. If you’d been using event monitoring, you could have caught this bad behavior before it cost your company sales.

Have you ever had loading problems with certain Visual Force pages? When you load it, it works like a charm, but when the customer loads it, it usually go timeout.
Now you can finally measure day by day how VisualForces are being rendered (times opened, viewstates, time required to load, ....).

EventLogFile are exposed 24h after their creation and are available only for 24 h: that is to say you can query / download EventLogFile of yesterday for 24h (till the platform releases the new EventLogFile files).

You can require a 30 days validity for EventLogFile objects (this is not a free feature).

A lot of stuff, uh?

Wednesday, August 5, 2015

[Salesforce / Revamp] Enable All Trusted IP Ranges for a Salesforce Org

DISCLAIMER: I've just understood you can do this on the profile (without range restrictions). See the "UPDATE" section of this post. This post is still valid as exercise.

Enabling all trusted IP ranges is a must do when developing on a Salesforce Developer ORG and you want to access via metadata API to your code from different locations where your IP can change during time (home, bar, pub, pizza shop, your parent's house, your parent's in law house, ...).

Thanks to Ray Dehler Enable All Trusted IP Ranges, I've done it several times in all Developer ORGs I've created since 2011...BTW thanks Ray, you saved me a lot of time!

Unfortunately with Summer '15 Release this awesome home page component does not work anymore: all home page components that use Javascript cannot work anymore, the Javascript code is blocked and you are forced to use a Visual Force page if you want dynamic behavior.

Apparently it is impossibile to reproduce this home page component using a Visual Force page, these are the main limitations I found while trying to update Ray's component:
  1. When using a Visual Force home page component with the same Javascript code, Salesforce reloads the loaded "Network Access" component of the iframe on the "parent" location, making it impossibile to load all iframes in one shot
  2. If you use the Visual Force outside the custom component (i.e. loading "/apex/PageName"), due to cross domain restrictions, the iframe is not loaded
  3. Even if you managed to load all iframes on point #1, the corss-domain restriction block you from loading the iframe's HTML content

Apparently this is impossibile to make it work same as old days.

That's why I created a simple update of the component to help adding (manually) all ranges:

Click on each "Click to load range" link to open, in a separate window, the "Network Access" page in Edit mode.

This is a way to help developers to load trusted range IPs, faster than writing all ranges by hand.

You can install this unmanaged package clicking on the following button:

Or by installing the following unmanaged package.

This is the GitHub repository with the code and other infos.

If you have a better solution / automation, please share!

UPDATE: I admit, I feel so dumb, but you can simply add the range in your Profile (no restrictions apply there), following this section: