function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
JackOdellJackOdell 

Can you convert an Account to a Person Account via a Trigger?

Hey folks.

 

Is it possible to convert an Account to a Person Account via a Trigger?  Or are Batch Apex and Data Loaders the only way?

Best Answer chosen by Admin (Salesforce Developers) 
JackOdellJackOdell

The Premiere Customer Support team was able to help me out.  As it turns out, there's a couple of hoops you need to jump through to make this work in the context of a trigger.  Here's some sample code:

 

trigger PersonAccountTesterTwo on Contact (before insert, after insert) {
	// This trigger walks you through the process of converting a new Contact into a Person Account.
	// 1) The first key element in making this work is that the Contact needs to be linked to the 
	//		target account before their record types are changed. This code handles this by 
	//  	associating the Account and Contact in "before insert".  After the "before insert" 
	// 		portion of the code runs, the Account and Contact will be linked together.
	// 2) The second key element in making this work is that when you change the record type of 
	// 		the Account, you need to query for a new version of the particular Account object in 
	//  	question.   And when you query for that object, you should only query for the id of 
	//		the Account. If you were to add another attribute to the query below (like say "Name") 
	// 		the code would fail.
	// 3) Make sure to change the query for the "Person Account" record type so that it returns a 
	// 		valid record type in your org.

	// That's it!  Good luck!
	
    private static RecordType PersonAccount = [SELECT id FROM RecordType WHERE DeveloperName = 'Seeker' and sObjectType = 'Account' and ispersontype = true and isActive = true limit 1];

	if (Trigger.isBefore && Trigger.isInsert){ 
		for (Contact newContact : Trigger.new){
			Account a = new Account(Name = 'TestAccountOne');
			insert a;

			newContact.accountid = a.id;
		}
	}

	if (Trigger.isAfter && Trigger.isInsert){
		Set<sObject> ObjectsToUpdate = new Set<sObject>();
	    Map<Id, Account> AccountsMap = new Map<Id, Account>([SELECT id FROM Account WHERE id IN (SELECT AccountId FROM Contact WHERE Id IN :trigger.newMap.keySet())]);
		for (id aId : AccountsMap.keySet()){
			Account a = AccountsMap.get(aId);
			a.RecordTypeId = PersonAccount.id;
			update a;
		}
	} 
}

 

All Answers

JackOdellJackOdell

Could an @future method do it?

mauro_offermannmauro_offermann

Yes, you should make an update to the account including ONLY the ID of the account and the corresponding RecordTypeId.

JackOdellJackOdell

I'm getting all sorts of errors which indicate this cannot be done.

 

Can you indicate in which trigger context that update worked for you?  Also, could you provide some sample code?

 

Here is sample code I whipped up based on your comment which throws an error.

 

trigger PersonAccountTester on Account (after update) {
    private static RecordType SeekerPersonAccount = [SELECT id FROM RecordType WHERE DeveloperName = 'Seeker' and sObjectType = 'Account' and isActive = true limit 1];

		for (Account newAccount : Trigger.new){
			if (newAccount.Name == 'ConvertMe'){
			    Account a = [SELECT id,RecordTypeId FROM Account WHERE id = :newAccount.id];
				a.RecordTypeId = SeekerPersonAccount.id;
				update a;
			}
		}
}

 

mauro_offermannmauro_offermann

Well, that code looks correct. What mistake throws?

JackOdellJackOdell

System.DmlException: Update failed. First exception on row 0 with id 001n0000001xsFfAAI; first error: INVALID_PERSON_ACCOUNT_OPERATION, account cannot be converted to person-account: []: Trigger.PersonAccountTester: line 12, column 1

mauro_offermannmauro_offermann

Ahh, I found your problem. It has a circular reference Update on the account.

Change the trigger event to "before update" and do not update the account at end.

JackOdellJackOdell

Doing it that way throws a different error (see below).  Are you 100% sure that you've converted an Account to a PersonAccount in a trigger?  Or are just guessing?  :-)  If you have, please post your code.

 

Apex trigger PersonAccountTester caused an unexpected exception, contact your administrator: PersonAccountTester: data changed by trigger for field Record Type ID: value not valid for the entity: Account

mauro_offermannmauro_offermann


Well I'm trying to help.

There is another problem to make this conversion in a trigger. As I indicated above the conversion will be successful only if you modify the field RecordTypeId. In a trigger instead is vulnerable to changes in the user enter other fields. I recommend you pass the Id of the account to a future method to perform the update specified.

JackOdellJackOdell

The Premiere Customer Support team was able to help me out.  As it turns out, there's a couple of hoops you need to jump through to make this work in the context of a trigger.  Here's some sample code:

 

trigger PersonAccountTesterTwo on Contact (before insert, after insert) {
	// This trigger walks you through the process of converting a new Contact into a Person Account.
	// 1) The first key element in making this work is that the Contact needs to be linked to the 
	//		target account before their record types are changed. This code handles this by 
	//  	associating the Account and Contact in "before insert".  After the "before insert" 
	// 		portion of the code runs, the Account and Contact will be linked together.
	// 2) The second key element in making this work is that when you change the record type of 
	// 		the Account, you need to query for a new version of the particular Account object in 
	//  	question.   And when you query for that object, you should only query for the id of 
	//		the Account. If you were to add another attribute to the query below (like say "Name") 
	// 		the code would fail.
	// 3) Make sure to change the query for the "Person Account" record type so that it returns a 
	// 		valid record type in your org.

	// That's it!  Good luck!
	
    private static RecordType PersonAccount = [SELECT id FROM RecordType WHERE DeveloperName = 'Seeker' and sObjectType = 'Account' and ispersontype = true and isActive = true limit 1];

	if (Trigger.isBefore && Trigger.isInsert){ 
		for (Contact newContact : Trigger.new){
			Account a = new Account(Name = 'TestAccountOne');
			insert a;

			newContact.accountid = a.id;
		}
	}

	if (Trigger.isAfter && Trigger.isInsert){
		Set<sObject> ObjectsToUpdate = new Set<sObject>();
	    Map<Id, Account> AccountsMap = new Map<Id, Account>([SELECT id FROM Account WHERE id IN (SELECT AccountId FROM Contact WHERE Id IN :trigger.newMap.keySet())]);
		for (id aId : AccountsMap.keySet()){
			Account a = AccountsMap.get(aId);
			a.RecordTypeId = PersonAccount.id;
			update a;
		}
	} 
}

 

This was selected as the best answer