Friday, 18 December 2015

UserRecordAccess - Check what level of access a user has to a record

Confirming Record Access Level

There are many considerations for User and Record security in Salefsorce. You have to set your Organisation Wide Defaults, Sharing Rules, Profile Access, and Field Level Security.

With all of these settings, it can get be quite complex to debug a user access issue.

I believe that every Salefsorce Administrator has at some point heard from a user who cannot see a particular record (you won't very often hear from users who can access things that they shouldn't).

I recently discovered a way to help with security questions like these. Salesforce allows you to query against any user's ID and any specified record and get a concrete Yes/No response on whether the user in question has Read/Write access to it.

Sunday, 13 December 2015

Report on Activities by Historic Opportunity Stage

Report on Activities by Opportunity Stage

One regularly asked question that I've seen on the Salesforce Success Community and other Salesforce forums is: 
"How do I report on activities made at different stages of the Sales process?"
You would be forgiven for thinking that there was a simple out of the box report that would show this. However, the standard Activity reports in Salesforce all have a look up to the Object they are reporting on. That means that as the Opportunity object progresses through the sales stages, so does the reference on the Activity.

For example - 

  1. on the 1st April I made a call whilst Opportunity was in "Discovery"
  2. on the 2nd April I made another call whilst the Opportunity was "Closed Won"
A standard Opportunity with Activity report in Salesforce will show you 2 Activities related to an Opportunity with "Closed Won" as the status for BOTH activities.

So, how do you solve this?

Sunday, 6 December 2015

Apex lastindexOf string manipulation

Apex String Manipulation

Apex has several powerful String manipulation features.

You can search for values in Strings, replace matching words, count matching string entries, capitalise letters, remove spaces, and much much more.

There's a good overview of all of the String manipulation methods available here: Apex String methods on Developer Force

On this particular occasion I needed to find the last instance of a few matching characters in a long text field and populate a new field with its value.

Wednesday, 25 November 2015

Copying multiple related records into a single text field

Copying multiple related records into a single text field

I was recently working with a customer who had an object with multiple records related to it.

They wished to copy all of the text from all child records and populate a single text box with the combined results.

The related call notes linked to the Task record

Thursday, 19 November 2015

Simple solutions first - Test Class on User object

Test Class

Do you really need to create that new user in your Apex Test class?

This is just a short blog post on an "ah ha" moment I had the other day whilst coding.

After I had nearly finished creating lines of code to create a few user records in the Test Class I realised that I could have just used a $User global variable instead.

Friday, 13 November 2015

Task Due Date populating

Pre-Populate the Due Date field in Salefsorce Task Object

I was recently working with a customer who wanted to automatically the ActivityDate or Due Date field on the Task Object automatically.

Unfortunately, at this moment in time (Winter '16) you cannot access the ActivityDate or "Due Date" via Formula or Workflow so this solution required an Apex Trigger.

Sunday, 8 November 2015

Data Nirvana: phone number accuracy in Salesforce

How accurate are your Account & Contact phone numbers in Salesforce?

Thanks to everyone who voted on my poll relating to this new app idea. In this post I wanted to share a bit more background on where the idea for the app came from.

If you haven't yet voted, here's a quick link to the post.

Vote on new AppExchange idea - automatic phone cleansing/validation app

Vote on new Salesforce App idea

How useful would a Phone Number cleaning/validating app for Salesforce be to you? For more information about the new app, click here. Thank you for voting!

Monday, 2 November 2015

SOQL with Child Records - a loop within a loop

SOQL and Child Records

A lot of posts regarding Apex coding focus on reducing down the number of SOQL statements you make during a Trigger.

One way to achieve this which is recommended by David Liu on his blog is to:
  1. query all possible records
  2. build up a map to store all the query results
  3. when looping through the Trigger records, query against the map rather than the database each time
  4. perform a single update at the end of the Trigger - no matter how many records you are working with

Friday, 16 October 2015

Copy items between objects


A recent project had the requirement of copying all new values from one custom object to another.

This was an interesting use case so I captured the Trigger for future use here.

Thursday, 15 October 2015

4000 character limit on Case object - debugging a Trigger issue

What was the problem?

You may or may not know that there is currently (as of Winter 16) a 4,000 character limit on the Case Comments field on the case object.

4,000 characters can be very quickly filled up when dealing with complex queries, or if you set up a process to copy the content of your email to case responses into the case comments (a very common customisation).

I recently encountered an issue where a Trigger set up to copy any new email to case into a case comment. Here's the background and eventual fix.

Friday, 2 October 2015

Cleared my Salesforce Certified Service Cloud Consultant (SU15) exam!

Salesforce Certified Service Cloud Consultant (SU15) 

I recently passed my Service Cloud Consultant exam (hurrah!).

I used a lot of great material available on various blogs/websites for revision, and I just wanted to share those resources here for anyone else working towards this.

Why should you study for the Salesforce Certifications?

There's a great post on David Liu's website SFDC99 which gives a great overview of why you should consider working through the qualifications.

For me, I just wanted to develop my knowledge of further and also benchmark my level of knowledge against each Salesforce accreditation.

Good luck in your own exam, I hope you find these resources useful!

Thursday, 24 September 2015

Dynamic telephone number presentation based on Apex Trigger


During a recent Computer Telephony Integration (CTI) project with a customer we had a requirement that the outbound (or presented telephone number) should be selected dynamically for each call made using a custom Apex Class.

Luckily, NewVoiceMedia's CTI solution features a hook which allows for a custom Apex Class that would handle this logic and alternate the presented number.

This write up covers the Trigger and Class, stored for prosperity.

Thursday, 17 September 2015

Error message: System.QueryException: Non-selective query against large object type (more than 100000 rows)

Debugging the error message: System.QueryException: Non-selective query against large object type (more than 100000 rows). Consider an indexed filter or contact about custom indexing.

Also known as - too many rows in your database table and no index fields

During a recent project I kept seeing the error below in the Salesforce Debug log. This was a new error to me so it took a long time to work out why my code was failing. 
System.QueryException: Non-selective query against large object type (more than 100000 rows). Consider an indexed filter or contact about custom indexing.
Having found the cause of the issue I wanted to write it up to hopefully save anyone else facing this problem some time.

Tuesday, 25 August 2015

Dialler Issues: A Custom Button to the Rescue


Sometimes the simplest solution in Salesforce can really be the best.

I was recently working with some custom software that created Dial Lists within Salesforce for a caller to navigate through.

For example, the person would start at Call 1, make the call, navigate to Call 2 and so on.

Thursday, 13 August 2015

Javascript and Visualforce to build dynamic Table - Part Deux


I recently worked on a app that generated a list of timed activities for their employees.

These times were displayed in a bar chart running from 09:00 to 17:00 across the day. So, for Employee A you might see a record like the one below visualising a day's activity.

Agent timeline
This graphic was great but quickly built up and could be occasionally hard to follow. One client asked for both this graphic table and a simpler table to follow each activity.

Wednesday, 12 August 2015

Javascript and Visualforce to build dynamic Table

Using JavaScript to dynamically render HTML Table within a Visualforce page


A customer recently asked for a nicer representation of a text field in their Salseforce page. This text field was an activity log for their employees and was being saved as a long text string within Salesforce with the | or "Pipe" character serving as the seperator between each row.

Here's an example of a single day's activity.
03121Ready:0|03121Busy Inbound:45|03166Wrap Up (Auto):13|03179Ready:1|03180Busy Inbound:8|03188Ready:0|03188Busy Inbound:91|03279Wrap Up (Auto):3|03282Busy Inbound:22|03304Wrap Up (Auto):4|03308Ready:1|03309Busy Inbound:12|03321Wrap Up (Auto):52|03373Custom State 320:418|03791Logged Out:25009|28800Logged Out:86400|

Saturday, 8 August 2015

Workflow and Formula fun

Workflow to Copy Phone field Values as Number

I was recently working on an integration with a Computer Telephony Integration (CTI) piece of Software.

The customer wanted a flow where a customer would call in, enter a series of digits (in this case their telephone number) and then when the call was answered Salesforce would display the matching record to the agent answering the call.

Formula checks that the Routing Number field is blank or whether the Phone number has changed

Wednesday, 5 August 2015

Trigger with Custom States - text manipulation

Trigger with Custom States

I've written about this text manipulation requirement before in previous blogs, but most recently I've had to replicate the Trigger for multiple clients.

To help with this, I've revisited the code and have started using Custom Settings to store some of the detail and make the Trigger more easily customisable.

Utilising Custom Settings had great promise, it was a good learning curve for me as well to work out how to create the Custom Settings within the Test Class to ensure coverage.

Tuesday, 4 August 2015

Cloning records in Salesforce

7 ways (at least) to Clone records in Salesforce 

I had a call from a customer last week asking me to look into an issue. The reported problem was that the "Clone" button in Salesforce was no longer working correctly for them.

This surprised me as the Clone function in Salesforce is completely standard, and to my knowledge I had not made any customisations to it.

After digging into this further I learnt a lot more about the Clone function.

Tuesday, 21 July 2015

Sales Cloud Consultant Exam (CON 201) preparation notes

The Sales Cloud Consultant (CON 201) Certification

The quest for more Salesforce certifications continues!

I'm just about to sit this next exam and after finding so many great resources online to help with the revision I wanted to list them all out for anyone else about to sit the test.

Good luck to you all, please feel free to add any other great resources that you find in the comments below - I still have a few more hours of revision left :)

Sunday, 14 June 2015

Bulk Deleting Reports - The best way?

One of this week's many Salesforce challenges was to clear out 2,000+ old reports from a client's ORG which were not longer required and were just taking up space. None of the reports had been run in over a year and were seriously cluttering up the place.

It turns out that there are multiple ways of accomplishing this so I thought I'd write up the various options.

Wednesday, 13 May 2015

Salesforce Advanced Developer DEV 501 Course Notes

I recently attended the Advanced Developer DEV 501 course in Staines.

The course was taken with Winter '15 and was delivered by the excellent MVP Simon Goodyear.

I've just finished tidying up my course notes and just wanted to share them for anyone out there starting on their Dev 501 journey.

I hope you find them useful:

Wednesday, 15 April 2015

Counting Open and Closed Activities in Salesforce

Counting Open and Closed Activities in Salesforce

The problem: I needed to log how many open Activities there were on Leads, Contacts, Opportunities, and Accounts as well as Activity History. 

I have similar triggers in the past but in this case I wanted a more flexible approach that would work across multiple objects.

Using standard reporting you can report on Objects with or without Activity records. You could also explore solutions such as Rollup Helper but in this case the customer wanted to see an easy count total on the top level of the object.

Before I wrote any code I had a look around the wonder-web and found a great bit of code that took me 60% of the way there.

A huge thank you goes out to rjpalombo for his initial work on Counting Open Activities. The blog below takes his example code and adds counting of closed Activities.

The following code example just expands on rjpalombo's code so that I could count Activity History as well as Open Activities.

Friday, 10 April 2015

License Management App

License Management Application

I recently deployed the License Management Application for a customer.

The customer found it to be a really useful too to support customer's who had installed their managed app from the AppExchange so I thought I'd write up an overview and installation guide.

Tuesday, 31 March 2015

Cleared my ADM 211 Salesforce Certified Advanced Administrator (SP15) exam!

ADM 211 Salesforce Certified Advanced Administrator (SP15)

Tackling ADM 211

I recently completed my ADM 211 Advanced Administrator exam. I used a lot of great material available on various blogs/websites for revision, and I just wanted to share those resources here for anyone else working towards this.

Good luck in your own exam.

Wednesday, 25 March 2015

Count Activities against an Opportunity

Counting Activities logged against an Opportunity

Whenever I get a request for a new Trigger I usually hit Google first to see whether some developer has kindly shared a similar challenge and code solution.

On this occasion I was asked to display a count of all activities logged against an Opportunity record. This should answer the question of "how much work did we do for this?".

I found this first example of a class which would perform roll up summary type triggers for Open Activities across Account, Lead, Contact, and Opportunity and started looking at the structure.

Thursday, 19 March 2015

Extracting Values from a Delimited File Part Deux

Extracting Values from a Delimited File Part Deux

Since working on this Trigger last I've been reading a lot about Trigger best practice.

I particularly like the requirement of having a single Trigger per Object in Production environments and will move to this model over time.

With that set, here is v2 of this trigger.

trigger TaggedState on NVMStatsSF__NVM_Agent_Summary__c (before insert, before update) {
    NVMStatsSF__NVM_Agent_Summary__c[] agentSummaries =;

and the class that now contains all of the logic:

Extracting values from a pipe delimited text file

A Trigger to extract key value pairs from a pipe delimited text file

This Trigger is incomplete. I just wanted to keep it for nostalgic purposes as it's the most complex/annoying one I've worked on so far.

I had a requirement to break down a field called Key Event String into a list of values. Then, to loop through the values searching for specific terms and adding up the totals for each.

It all sounded so simple but this particular trigger kept bringing up totals from one value and listing them against another. So Custom State 1 would actually be the total of Custom State 2.

I spent hours debugging but eventually decided to rewrite it. I'm pretty sure the answer lay where I was setting the value variable but rewriting gave me an opportunity to tidy it up and move the handling into a class.

Monday, 16 March 2015

Checking for Working Days and Company Holidays

Checking for Working Days and Company Holidays

In this post I talk through a Trigger I wrote to check whether a Custom Activity record was created on a weekday, or during a public holiday.

The Problem

My customer was storing their work activity in a Custom Object called Project Time Log.

At the end of the month they would run a report showing how much activity had taken place.

The problem was that doesn't seem to have any way out of the box of excluding Weekends and Public Holidays out of report criteria so the customer's reports were alwaysinaccurate.
Therefore I had to develop a Trigger to check each submitted activity log and decide whether the activity was on a working day/or on a scheduled public holiday.


Saturday, 14 March 2015

Conditional count of Related List

Counting items in related list

Following on from my previous blog where I mentioned that some things in look complicated at first but actually have a really easy solution this requirement sounded easy but required a trigger in the end to solve it.

The problem

My customer wanted to count have many Activity Records with a given criteria were linked to a Case record up to the point where the case was closed.

This count would be populated on a number field on the Case Object called: Number_of_Calls__c

This field would show how many interactions took place from Case Open to Case Close.

Unfortuantely, buried within the activity history on the case there were other non-relevant activities so a way to count specific tasks was required.

At this point, if Activity History was a Master Detail relationship under the Case then I could have added a Roll Up summary, but as it's a Lookup there's currently no easy way to do this out of the box.

Your 2 options are to either install a 3rd party app like Rollup Helper or Code a custom trigger.

For complete flexibility I went down the trigger route - here's the code.

Friday, 13 March 2015

analytics:reportChart Embedding Salesforce Charts in Visualforce

Embedding Salesforce Charts in Visualforce

So many updates get added to all of the time that I'll quite often find a new feature that passed me by.

The problem

I was asked to make some improvements to a set of Reports & Dashboards on a customer ORG. Based on the requirements, I knew that I would  have to create Visualforce pages to give me full flexibility over the layout, but I wasn't looking forward to recreating all of the reports.

Today's bonus feature is the Visualforce analytics:reportChart tag that lets you grab the URL or any report that has a chart/graphic in it and then drop that chart into any Visualforce page.

Step 1

Build a normal report and add a graph to it

Step 2

Grab the ID of the report you just made from the URL

Step 3

Go to your Visualforce page and add the following code

                <analytics:reportChart reportId="URL OF YOUR REPORT"/>

Step 4

Preview your Visualforce page - you should see the same report Chart appearing in the content. As an additional bonus, the Analytics tag includes a timestamp of the last refresh and is clickable through back to the source report.

Any error messages?

I experienced one error message when setting this up for the first time. As the Visualforce page could potentially be accessed by anyone you need to ensure that the source report is also publically accessible.

Friday, 6 March 2015

Trigger that posts to Chatter automatically

The problem

Posting to Chatter via Apex Trigger

This requirement comes up fairly regularly now - saving users time by automatically posting to Chatter if an update happens within Salesforce that needs calling out.

Examples could be - An urgent case has come in - a customer account has gone Red - there is a service issue etc.

This particular chatter trigger looks for any cases marked with a skill of "Escalation" and automatically posts it out on Chatter with a Topic tag marked "Escalation".

To implement this trigger in your ORG you would need to add a field called "Skills__c" on your Case object and populate it with "Escalation" when you insert a new case.

trigger EscalationPost on Case (after insert) {
//Only firing trigger on initial case creation - amend if requirement to before update etc
    for(Case myCase:{
//Change criteria of trigger if required
            FeedItem post = new FeedItem();
            post.ParentId =;
//Change body of Chatter post in between single speech marks below
            post.Body = 'Escalated Complaint Case! Retention team need to engage. [#Escalation]';
            insert post; 
        } //end if
    } //end for loop
} // end trigger

Thursday, 5 March 2015

Change of record owner after Approval Process

The problem

Change of record owner after Approval Process

I wanted to write a 2 step approval process.

One where you would send a record through for transfer, but would have to be accepted by the new person.

Salesforce is very good at 1 way approval process. (I.e., I send the record to you, but then you have send it somewhere else if you don't want it). However, in this instance it was important that the record was accepted before transfer.

This example needs an approval process set up where approval updates ChangeManagerApproved to true. We also need 2 owner fields - Escalation_Manager__c and New_Escalation_Manager__c.
// Comment
* Reassigns Escalation Manager on Escalation after approval process is complete
* Output of approval process is ChangeManagerApproved = True
* If ChangeManagerApproved = True and yet the Escalation Manager and 
* New Escalation Manager fields then trigger should fire
* Only to fire on Update
trigger reassignEscalationManager on Escalation__c (before update) {
    try {
        Set<Id> accountIds = new Set<Id>();
        Map<Id, Id> accountOwnerIdMap = new Map<Id, Id>();
        // all the accounts whose owner ids to look up
        for ( Escalation__c c : ) {
            if (c.ChangeManagerApproved__c == True && (c.Escalation_Manager__c <> c.New_Escalation_Manager__c)) {
                System.debug('Change of manager approved and new/old manager different - trigger firing');
                //Final action needs to be changing ChangeManagerApproved__c to False to prevent re-fire
                c.Escalation_Manager__c = c.New_Escalation_Manager__c;
                c.ChangeManagerApproved__c = False;
                c.New_Escalation_Manager__c = Null;
            } //end if
        } //end for        
    } //end try
    catch(Exception e) 
    { //catch errors
        System.Debug('reassignEscalations failure: '+e.getMessage()); 
        //write error to the debug log
} //end trigger

Reassigning Contact Owner in Salesforce to Account Owner

Salesforce Snippets

On this blog I'll share any code snippets that I develop in It'll be a good reminder for me, and I hope it helps other people out there who might come across similar challenges.

Getting started

Right, first challenge of the day - setting up to handle code snippets and posting a test trigger.

That turns out to be quite straightforward thanks to a great post from Geektalkin - thanks!

Right, now that I can copy in Trigger code and maintain it's formatting here's the first example:

What does this trigger do?

This trigger changes the ownership of any Contact record in Salesforce that is added or updated. The trigger ensures that all of the Contacts relating to an account are owned by the Account Owner.

Original source:

This is a slightly modified version of an example trigger posted on the success community.

//Reassigns Contact to Account Owner

trigger reassignContact on Contact (before insert, before update) {
   try {

        Set<Id> accountIds = new Set<Id>();
        Map<Id, Id> accountOwnerIdMap = new Map<Id, Id>();
        // all the accounts whose owner ids to look up
        for ( Contact c : ) {
            if(c.accountId <> null){
             accountIds.add( c.accountId );
        // look up each account owner id
        for ( Account acct : [ SELECT id, ownerId FROM account WHERE id IN :accountIds ] ) {
            accountOwnerIdMap.put(, acct.ownerId );
        // change contact owner to its account owner
        for ( Contact c : ) {
            if(c.AccountId <> null){
             c.ownerId = accountOwnerIdMap.get( c.accountId );
    } catch(Exception e) { //catch errors
        System.Debug('reassignContacts failure: '+e.getMessage()); //write error to the debug log