Jun 27, 2018
by Jaswinder RattanpalThis is the final blog in the series on how to support Person Accounts in your ISV Solution. In this blog, we will talk about how to create a managed package that will support Person Accounts in Financial Services Cloud, and that can be installed in any org, whether Person Accounts have been enabled or not.
The first part of my blog series explained person account-related considerations for managed packages, and a design pattern for ensuring that a managed package can be deployed to an org, even if person accounts have not been enabled (i.e. an org that is using the default business accounts). Now lets see how that design pattern is implemented in practice.
Scenario
Consider an external system with customer birthdates. We need to make an on-demand API call to get an individual's birthdate from that system, and then save the result in the Salesforce field “Account.PersonBirthDate.” We will ensure that code is written in a way that doesn't require Person Accounts to have been enabled in advance.
For this use case, we will create a Lightning component and embed it on the Account record page's sidebar. This component will display a button if the record is a PersonAccount. When the button is pressed, and if the record is a Person Account, then information will be fetched with an API callout and the record updated.
With that, let's get started.
Development
The following Apex class will return a birthdate.
public with sharing class AccountAPI { @AuraEnabled public static boolean isFSCPersonAccountEnabled(){ //Check if FSC Person Account is enabled //Requires install of FSC FinServ__UsePersonAccount__c fscpa = FinServ__UsePersonAccount__c.getInstance('Use Person Account'); return (fscpa != null)?fscpa.FinServ__Enable__c:false; } @AuraEnabled public static APIWrapper fetchAccountInfo(Id AccountId){ APIWrapper apiw = new APIWrapper(); //Confirm that ID is correct AccountId = String.escapeSingleQuotes(AccountId); String query = 'Select Id, PersonBirthDate from Account where Id=\'' + AccountId + '\''; try{ sObject a = Database.query(query); //Make PRETEND API call //FetchAccountInfo(AccountId) apiw.BirthDate = date.newInstance(1990, 11, 21); }catch(Exception e){ } return apiw; } //Wrapper class to return Data public class APIWrapper{ @AuraEnabled public Date BirthDate; } }
Lightning component to use above Apex class, fetch BirthDate and save record.
<aura:component controller="AccountAPI" implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" > <aura:attribute name="account" type="Object"/> <aura:attribute name="simpleAccount" type="Object"/> <aura:attribute name="accountError" type="String"/> <force:recordData aura:id="accountRecordLoader" recordId="{!v.recordId}" layoutType="FULL" targetRecord="{!v.account}" targetFields="{!v.simpleAccount}" targetError="{!v.accountError}" mode="EDIT" /> <aura:attribute name="isFSCPersonAccountEnabled" type="boolean" default="false" /> <aura:handler name="init" value="{!this}" action="{!c.doInit}"/> <!-- If no loading errors then proceed --> <aura:if isTrue="{!empty(v.accountError)}"> <aura:if isTrue="{!v.isFSCPersonAccountEnabled}"> <aura:if isTrue="{!v.simpleAccount.IsPersonAccount}"> <lightning:button label="Fetch & Save Data" onclick="{!c.fetchAndSave}" class="slds-m-top_medium" /> <aura:set attribute="else"> This is not a Person Account </aura:set> </aura:if> <aura:set attribute="else"> This is not a Person Account </aura:set> </aura:if> </aura:if> </aura:component>
({ doInit: function(component, event, helper) { //Check if FSC Person account is enabled from custom settings var action = component.get("c.isFSCPersonAccountEnabled"); action.setCallback(this, function(response){ if(component.isValid() && response !== null && response.getState() == 'SUCCESS'){ //Store if FSC Person Account is Enabled component.set("v.isFSCPersonAccountEnabled", response.getReturnValue()); } }); $A.enqueueAction(action); }, fetchAndSave: function(component, event, helper){ //Fetch BirthDate via API to update the record var action = component.get("c.fetchAccountInfo"); var acc = component.get('v.simpleAccount'); action.setParams({"AccountId": acc.Id}); action.setCallback(this, function(response){ if(component.isValid() && response !== null && response.getState() == 'SUCCESS'){ var obj = response.getReturnValue(); component.set("v.simpleAccount.PersonBirthdate ", obj.BirthDate); component.find("accountRecordLoader").saveRecord(function(saveResult) { if (saveResult.state === "SUCCESS" || saveResult.state === "DRAFT") { var toastEvent = $A.get("e.force:showToast"); toastEvent.setParams({ title: "Success!", message: "BirthDate Updated!", type: "success" }); toastEvent.fire(); } else if (saveResult.state === "INCOMPLETE") { console.log("User is offline, device doesn't support drafts."); } else if (saveResult.state === "ERROR") { console.log('Problem saving contact, error: ' + JSON.stringify(saveResult.error)); } else { console.log('Unknown problem, state: ' + saveResult.state + ', error: ' + JSON.stringify(saveResult.error)); } }) } }); $A.enqueueAction(action); } })Packaging
The next step, after development, is to package the solution. Packaging follows the same standardized process that you know and love. I have packaged the above code and installed it in orgs with and without Person Accounts enabled. There were no installation errors and the code worked without any issues.
You can test it by installing this package from https://login.salesforce.com/packaging/installPackage.apexp?p0=04t1I000003cqto
Security Review
The standard Security Review Process should be followed. Make sure to add CRUD/FLS checks (at the very least) in the code above. As it is, the package above will fail Security Review because I haven't implemented any CRUD/FLS checks when running the query.
Conclusion
With this, you should be able to developer and package your functionality to support Person and Business Account in the same package.
Resources
- Supporting Person Accounts in Your ISV Solution
- Hands-On with Financial Services Cloud: Introducing A Three-Part Blog Series for ISVs
- Hands-On with Financial Services Cloud: Building and Extending with Custom Functionality
- Myth Busting: Five Common Misconceptions about Person Accounts
- Considerations for Using Person Accounts
- About Managed Packages
- Publishing Extensions to Managed Packages
- Account Object Reference for Salesforce
- Dynamic DML
- Dynamic SOQL
- Dynamic SOSL
- Financial Services Cloud Administrator Guide: Enable Person Account
- Person Accounts for FSC FAQs - Partners
- Health Cloud Implementation Guide: Enable Person Accounts