Homeowners in Salesforce without Person Accounts, NPSP, or a single line of Apex
Person Accounts are irreversible and NPSP is a managed package you inherit forever. The household model needs neither — but it turns Lead.Company into the whole problem, and there is an order-of-execution trap waiting.
Doorvana sells to builders, dealers and commercial facilities — and to homeowners. Three of those four are companies. The fourth is a person, and Salesforce has opinions about people.
The two standard answers are Person Accounts and NPSP. We used neither, and the model that replaced them is simple. Getting a lead into it is where the actual work turned out to be.
Why not Person Accounts
Person Accounts merge Account and Contact into one record for individuals, which is exactly the shape a homeowner wants.
The problem is the word that follows: enabling Person Accounts is irreversible. It cannot be turned off. It changes Account behaviour org-wide, permanently, including in places you have not built yet — reporting, integrations, managed packages that may or may not have been written with Person Accounts in mind.
For an org where most accounts genuinely are businesses and homeowners are one customer type among four, that is a permanent change to everything in order to accommodate a quarter of the data. NPSP gets you a household shape without the irreversibility, but it is a large managed package with its own object model and its own upgrade cadence, adopted for one feature.
The model
- Account = the household, named
{First} {Last} Household— “Smith Household” — withCustomer_Type__c = Residential - Contact = the person. A spouse is a second Contact on the same household.
- Location = the property, exactly as it is for every other customer type
Household and property are deliberately orthogonal. A household that moves keeps its Account and gains a new Location. A Location outlives the household that occupied it. Neither fact overwrites the other, which is the same reasoning that separated the builder from the owner on the property record.
No Apex. No managed package. Nothing irreversible.
Then the lead form asks for a company
Here is where it gets interesting.
With Person Accounts off, Company is universally required on Lead, and standard
conversion maps Lead.Company → Account.Name. So household naming reduces entirely to
putting the right string in Company before save. That is good news — no conversion
override, no Apex, no custom conversion screen.
It also means the existing flow was actively working against us. Service_Lead_Stamp_Company
set Company = Business_Name__c, falling back to the street address — which produces
accounts named “1234 Oak St”.
That is wrong twice. It conflates the customer with the property, which the model puts on a Location. And it collides the day a second person at that address calls.
The replacement keys off customer type rather than off whether a business name happens to be filled:
Service_Lead_Stamp_Company — before-save flow logic
IF Customer_Type__c = "Residential"
Company = TRIM(FirstName & " " & LastName) & " Household"
ELSE
Company = Business_Name__c The TRIM is not decoration — a null FirstName would otherwise produce a leading space.
And a validation rule requires Business Name when Customer_Type__c != Residential, so the
else branch can never stamp a blank.
The order-of-execution trap
This is the part that cost a day, and the plan we had written down for it was wrong.
The before-save flow populates Company fine for leads arriving from web-to-lead, the API,
or Flow. For those sources, system validation runs after before-save record-triggered
flows.
It does not rescue the standard UI New Lead page, where validation runs before the flow. A receptionist typing a homeowner lead gets:
Company: You must enter a value.
…for a field the automation was about to fill in a moment later. Identical record, identical rules, opposite outcome — decided entirely by where the record came from.
Three ways to fix it at the layout, all refused
The written plan was to make Company read-only on the layout, on the reasoning that a
read-only field is not required at the layout level. It is a tidy theory. The platform
rejects it, and it rejects the two obvious fallbacks as well:
| What was tried | What came back |
|---|---|
| Set the layout behavior to Readonly | Field:Company must not be Readonly |
| Remove it from the layout | Layout must contain an item for required layout field: Company |
| Leave it editable but not required | must be Required |
Required is the only behavior the platform permits. There is no arrangement of layout settings that solves this, which is not something any amount of reading would have told us — it took three deploys.
That is a heavier fix than a checkbox, and it is worth being honest that it is the only fix. If your model needs a universally required field to be populated by automation for records a human types, the standard page cannot be part of that path.
What conversion does, and the one thing it does not
Lead.Customer_Type__c shares the same global value set as Account.Customer_Type__c, so
standard lead field mapping carries it across. Conversion then produces the household
Account, the Contact, and optionally the Opportunity, with no automation at all.
What it does not do is create the Location.
The lead carries a service address. Under this model that address belongs on a Location, not on the Account. Nothing in standard conversion knows that. Without an after-save flow that creates or matches a Location from the lead’s address and stamps it on the Opportunity, every converted residential lead lands with no property record — and the Field Service chain has nothing to hang a Work Order on.
The household-to-property link itself is standard and worth knowing about:
AssociatedLocation is the stock Account-to-Location junction, and almost nobody mentions
it. No add-on, no custom junction object. A test of the matching path was reassuring — a
second, unrelated household at an address already on file attached to the existing Location
rather than creating a duplicate property.
That is the kind of gap that does not show up in testing, because the tester creates the Location by hand without noticing they did it.
The known weakness, stated rather than hidden
Duplicate households. The spouse calls three months later, a new lead comes in, and you get a second household account for the same address.
This cannot be prevented under this model, only detected. Matching rules on Account (Name + BillingStreet) and Contact (email, phone), plus the conversion screen’s “attach to existing account” path, catch most of it.
The more reliable signal is the service address, not the household name. Two people at the same house may not share a surname; they do share an address. Matching on the property is what actually works, which is another small argument for the property being its own record rather than a field on the account.
Would Person Accounts have been easier?
For this one customer type, yes. That is worth admitting.
The trade was a permanent, org-wide, irreversible change against a handful of flow rules and a matching strategy. For an org that is three-quarters business accounts and just moved to Enterprise, the reversible answer was the right one — and if homeowners ever become the majority of the business, Person Accounts are still available. That door only opens one way, which is exactly why it stays shut until something forces it.