Time for another change

It’s been almost two years since I threw the hat back over the wall and faced the challenge of leaving the comforts of my old job and community behind and join Salesforce as a Technical Architect in CSG (the Customer Success Group; our professional services division).

The last two years have flown by and I’ve become proficient and 6 times certified on Salesforce. I’ve spent loads of time at customer sites and learnt a lot from it and what challenges our customers are facing and why they’re choosing Salesforce. Although my time in CSG have been rewarding, challenging and educational it’s time for something new starting Monday 1 October.

Now I will not be leaving Salesforce as I’ve been able to find a really cool new position internally. Starting Monday I’ll leave CSG and switch to pre-sales and become a Cloud Architect. I’m very excited about this move. As a Cloud Architect I’ll be part of the greater pre-sales Solution Engineering team but instead of focusing on a specific cloud (Service Cloud, Sales Cloud, Marketing Cloud or Commerce Cloud) I’ll be part of a team that helps out with all the “technical stuff”. That means AppDev on our core Lightning Platform, Heroku, IoT, integration, security etc. It means helping out on sales opportunities and showing our customers or soon-to-be customers how they too can leverage the power of the Salesforce Platform to make them successful.

I’ve spent the last time dialling down my engagement with the customer I’ve been at since late April and only had sporadic contact with my new team. But although the contact have been sporadic I cannot wait for Monday and to get going. I already have public speaking engagements lined up and I’m looking very much forward to picking up public speaking again in my new role.

Wish me luck.


jq and multi-field output to CSV

jq is some of the most underrated tools out there I think. It’s a command line JSON parser that makes it super easy to work with JSON on the command line and in turn makes developing small SalesforceDX tools a breeze. Today I needed to generate a CSV file of all fields from different objects for the integration team that doesn’t have access to Salesforce. Doing the describe is easy using the Salesforce REST API but when using jq different are usually on different lines like below (-r is a nifty switch for getting raw, unquoted strings).

$ sfdx force:schema:sobject:describe -s Account -u myorg --json | jq -r ".result.fields[] | .label, .name"
PO Box
Postal Code Before City
Street No Before Street
Archived State

The output is almost what I wanted but really wanted not  to have to edit the file manually to build the output. Some quick googling and it appears that jq supports both CSV and tabular output from arrays. So fixing the issue was as simple as follows:

$ sfdx force:schema:sobject:describe -s Account -u myorg --json | jq -r ".result.fields[] | [.label, .name] | @csv"
"PO Box","PO_Box__pc"
"Postal Code Before City","Postal_Code_Before_City__pc"
"Street No Before Street","Street_No_Before_Street__pc"
"Archived State","Archived_State__pc"

This is so cool… Love it!!

Trying to explain Person Accounts in Salesforce

Person Accounts in Salesforce keeps confusing developers not at home on the platform due to their special behaviour. The purpose of the repo (https://github.com/lekkimworld/salesforce-personaccount-field-reference) is to hold some examples on how to work with Person Accounts in an org using Apex and the Bulk API to try and illustrate a few points.

What ARE PersonAccounts

First of knowing WHAT a Person Account is is important. In Salesforce we normally talk about Accounts and Contacts with the Account being the company entity (i.e. Salesforce.com Inc.) and the Contact being the people that we track for that company (i.e. Marc Benioff, Parker Harris etc.). It means that we have to have an Account and a Contact to track a person in Salesforce. But what if that doesn’t make any sense like when tracking individuals for B2C commerce or similar? Meet the PersonAccount.

Please Note: There is no such object as PersonAccount in Salesforce. There are only Account and Contact but in the following I’ll use PersonAccount to reference this special case for Account.

PersonAccount is a special kind of Account that is both an Account AND a Contact giving you the possibility to treat an individual using an Account. The secret to understanding PersonAccount is knowing that using a special record type and specifying it when you create the Account, Salesforce will automatically create both an Account AND a Contact record and automatically link them and thus create the PersonAccount. Salesforce automatically makes the fields that are normally available (including custom fields) on the Contact available on Account. Only thing you need to do is follow a few simple rules that are listed below.

Please Note: When using PersonAccounts you should always access the Account and never the associated Contact.

Referencing Fields

Because there is both an Account and a Contact for a PersonAccount there are some special rules to follow when referencing fields. This goes for any access whether that be using Apex, REST API and the Bulk API. The rules are pretty easy and are as follows:

  1. Always reference the Account object
  2. When creating a PersonAccount create an Account specifying the record type ID of the PersonAccount record type configured in Salesforce. Doing this makes the Account a PersonAccount.
  3. Fields from Account are available on Account (as probably expected):
    1. Standard fields from Account Referenced using their API name as usual (i.e. Site, Website, NumberOfEmployees)
    2. Custom fields from Account Referenced using their API name as usual (i.e. Revenue__c, MyIntegrationId__c)
  4. Fields from Contact are available directly on Account:
    1. Standard fields from Contact The API name of the field is prefixed with “Person” (i.e. Contact.Department becomes Account.PersonDepartment, Contact.MobilePhone becomes Account.PersonMobilePhone) UNLESS we are talking FirstName and LastName as they keep their names (i.e. Contact.FirstName becomes Account.FirstName, Contact.LastName becomes Account.LastName)
    2. Custom fields from Contact The field API name suffix is changed from __c to __pc (i.e. Contact.Shoesize__c becomes Account.Shoesize__pc)

Delete Sample Data

One of my pet peeves in Salesforce has been solved. There is now a “Delete Your Sample Data” action under “View All” in Recommended Setup in “Service Setup” in Salesforce orgs. It’s no secret that I find it strange that we pollute new customer production orgs with sample data by default instead of asking the customer whether to add it. So I’m very happy that the process of removing it has become easier and we do no longer leave it to the customer to figure out the correct sequence for data deletion.


Issue with importing keystore into Salesforce

When attempting to import a certificate from a Java keystore (JKS) into Salesforce using “Security | Certificate and Key Management” under Setup the following error is encountered:

Data Not Available
The data you were trying to access could not be found. It may be due to another user deleting the data or a system error. If you know the data is not deleted but cannot access it, please look at our support page.

Resolving the issue is easy once you know how:

  1. Go To Setup | Identity Provider
  2. Press “Enable Identity Provider” button (Enabling this option will not affect any existing functionality in the Org. The full Identity Provider setup would need several other steps as well so enabling simply under — Setup | Identity Provider– will not make any difference so it can be enabled safely.)
  3. Once Identity Provider is enabled in the Org, it will create a self-signed certificate in your Org under — Setup | Certificate and Key Management
  4. Try to import the certificate from your JKS through “Import from keystore” option and it should be successful.
  5. (This is optional step) You may disable the Identity Provider again and then delete the automatically created Self-Signed certificate (via step 3) under ‘Certificate and Key Management’. This will turn your Org setup to its original state.


Life at Salesforce Through a Techie’s Eyes

I’ve been profiled in a post on Salesforce.com in a post titled Life at Salesforce Through a Techie’s Eyes. The post outlines how I see Salesforce as an employer and how I got to work for Salesforce. Sweet!

Only thing I saw that was stripped is the last sentence from the “Quick facts about me” section. It was “Even though I work under a blue cloud I continue to bleed yellow”. Oh well… 🙂

Using SalesforceDX to perform Bulk API operations

As noted the other day (Using SalesforceDX to automate getting Apex class test coverage percentages) SalesforceDX is great for many things but one of the ways is automate some operations that are time consuming or just takes a lot of manual work each time. One of these things are Bulk API operations which in of by themselves are not hard but there is no UI for them besides the DataLoader and no console API when using the DataLoader when not on Windows.

The customer I’m working for currently has a monster data load to perform and one of the things I’ve done is writing  script to split the data into data sets. One set per country – 91 sets all in all. All sets consists of 3 files to support the data load. One file for Accounts and two additional files for custom objects that needs to be loaded as well. All in all it’s a lot of clicking in the DataLoader and it doesn’t really scale for testing. That’s a lot of clicking in DataLoader when testing.

But I’m lucky as SalesforceDX receives new functionality all the time and at some point some data Bulk API features had snuck by me so I was pleasantly surprised to discover force:data:bulk:upsert and force:data:bulk:delete today. They we just what I needed. SalesforceDX to the rescue yet again…

So today I grabbed by IDE by the horns (#vscode in my case) and wrote some wrappers around the Bulk API capabilities of SalesforceDX. The fact that all SalesforceDX commands takes an optional –json argument makes it easy to script and parse responses. This combined with select-shell from npm I now have a nice CLI interface to doing Bulk data loads. The script looks as the available data sets and asks me what country to load data for and then what export timestamp to process (the data sets may exists in multiple versions). Then it goes and does its thing UPSERTing all 3 times in turn and reports status. So nice. The Bulk API is asynchronous so  the script also handles polling for job status and only proceeds once the job has completed successfully.

$ ./upsert mheisterberg@example.com.appdev
SFDX - Org for mheisterberg@example.com.appdev is connected...

Select country code:
 ▸ it

Select timestamp:
 ▸ 2018-04-16T08:34:14Z

Will process following data
Country : it
Timestamp: 2018-04-16T08:34:14Z
UPSERT for Account data...
Issued UPSERT bulk request to object (Account) - id 7516E000002DckQQAS, jobId 7506E000002QQ3zQAG - state: Queued
SFDX - asking for bulk status for id 7516E000002DckQQAS, jobId 7506E000002QQ3zQAG
SFDX - received bulk status for id 7516E000002DckQQAS, jobId 7506E000002QQ3zQAG - state: Completed
Issued UPSERT bulk request to object (MarketRelation__c) - id 7516E000002DckkQAC, jobId 7506E000002QQ4JQAW - state: Queued
SFDX - asking for bulk status for id 7516E000002DckkQAC, jobId 7506E000002QQ4JQAW
SFDX - received bulk status for id 7516E000002DckkQAC, jobId 7506E000002QQ4JQAW - state: Completed
Issued UPSERT bulk request to object (Consent__c) - id 7516E000002DckuQAC, jobId 7506E000002QQ4OQAW - state: Queued
SFDX - asking for bulk status for id 7516E000002DckuQAC, jobId 7506E000002QQ4OQAW
SFDX - received bulk status for id 7516E000002DckuQAC, jobId 7506E000002QQ4OQAW - state: Completed
Finished upsert of data

Once I’m done testing a particular data set I can use the –delete-accounts flag to my script to delete data using the Bulk API as well. Here I actually combined force:data:soql:query and force:data:bulk:delete to first retrieve the ID’s of the records I need to delete and then kick off the required Bulk API delete requests. Again easy peasy. And repeatable…

$ ./upsert mheisterberg@example.com.appdev --delete-accounts
SFDX - Org for mheisterberg@example.com.appdev is connected...

Are you sure?
 ▸ No

Received 32463 records
Issued DELETE bulk request to object (Account) - id 7516E000002DckLQAS, jobId 7506E000002QQ3uQAG - state: Queued
SFDX - asking for bulk status for id 7516E000002DckLQAS, jobId 7506E000002QQ3uQAG
SFDX - received bulk status for id 7516E000002DckLQAS, jobId 7506E000002QQ3uQAG - state: InProgress
SFDX - asking for bulk status for id 7516E000002DckLQAS, jobId 7506E000002QQ3uQAG
SFDX - received bulk status for id 7516E000002DckLQAS, jobId 7506E000002QQ3uQAG - state: Completed
Performed delete...

Only issue I had here really was that node.js has a maximum buffer size of 200kb to stdin so I could not simply read the stdin response from the SOQL query as it may be pretty big. Instead I pipe to a tmp-file and read that back in and parse as JSON. Not ideal but it gets the job done.

The code of the script itself is for the customers eyes only but the source for the helpers is available as sfdx-bulk-helper on Github and sfdx-bulk-helper on npm.