Quality Plus Contracting - New Business - September 2026
Account
Quality Plus Contracting
Stage
Booked
Entity Type
Single Entity
Total Net Miter ACV
$258,480
Total Team Members
800
Close Date
9/12/2026
Where this launches from. A quick action on the Opportunity, visible only when
Entity_Type__c is Single Entity or Contracted Entity and
StageName = "Booked". The record page keeps its normal layout; the wizard runs in a flow modal.
Break Out Sub-Entities
Step 1 of 6
Screen Flow · POC
Built from:Display TextData Table (read-only)Section, 2 columns
Read-only confirmation. Shows only the SKUs where the parent has team members, so the
calculator later stays narrow.
Reads Total_Miter_ACV__c. Its label reads "Total Net Miter ACV", so the API name and the label disagree.
Reads the 19 <SKU>_Team_Members__c and <SKU>_PEPM__c pairs, hides the zeros.
On Next, the parent is set to Entity_Type__c = "Contracted Entity".
i
This opportunity becomes the Contracted Entity. Its licence counts stay untouched
until the last screen, so the booked total stays visible the whole way through.
Contracted entity
Opportunity
Quality Plus Contracting - New Business - September 2026
Type
New Business
Close Date
9/12/2026
Onboarding Fee
$18,000
Licence counts on the parent 4 of 19 SKUs non-zero
SKU
Team Members field
Licences
PEPM
Annual
Built from:RepeaterTextDateCurrencyLong Text Area (paste box)
Collects the entity list only. No licence numbers yet.
The Repeater is the right native component here. It supports Text, Date and Currency children,
and allows up to 30 instances at run time, which covers Caroline's 19-entity worst case.
Go_Live_Date__c is optional. Caroline confirmed these dates are usually unknown at booking.
Entity-level Onboarding_Fee__c is optional and defaults to blank, because the full fee
normally sits on the parent.
The paste box is a Long Text Area plus an Apex invocable that splits on newlines. A Repeater cannot
be pre-populated from a collection natively, so the paste route needs that Apex step.
Website is Required (Dan, 9/15: "Website makes sense. I like that as a requirement").
It is also the match key: it normalises to HS_Normalized_Domain__c, which is the only
unique, case-insensitive Account key in the org.
The entity name is a Required Text child. That is what blocks Next on a blank row and prints
"Complete this field." It matters because Name is the only field Salesforce genuinely
requires on Account, so a blank row would fail the insert and roll back the whole batch.
i
Paste a column straight from the customer's spreadsheet, or add rows one at a time.
Entities
* Entity name
* Website
Go-live date
Entity onboarding fee
Built from:Data Table, multi-row selectDisplay TextApex invocable (the search)
Why this screen exists. 32% of the 610 sub-entity opportunities already in the org sit on an
Account that existed before the opportunity, and 185 of those were already customers. Creating blindly
would make the Account dupe problem worse.
The real hazard is not duplicates.Sales_Rep_Opportunity_Trigger_Account_Contact_owner_Update fires on ISNEW()
of an Opportunity and writes Account.OwnerId and every related
Contact.OwnerId from the opportunity owner. Linking a sub-entity opp to an existing
Account silently transfers that Account away from its current AE. That is why the owner column is on
this screen.
Matching keys. There is no EIN or tax-ID field on Account, even though the breakout is
EIN-level in practice. HS_Normalized_Domain__c is Text(255), External Id, Unique Case
Insensitive, and is the only reliable key. Name matching needs human confirmation, and
Website cannot be trusted on its own because 153 Accounts hold a free email domain there.
Why a Data Table and not a Repeater. A Repeater cannot contain a lookup or Record Picker, so
per-row account search is not possible inside one. A multi-select Data Table fed by an Apex search is
native, scales to 19 rows, and returns the selected rows as a collection.
Linking to an existing Account is normal, not an exception. A second sub-entity opportunity on one
Account is also legitimate: S+B James Construction and S+B James California are two entities on one
Account two months apart.
Caroline, 9/15: "we do see that the accounts often exist in SFDC already so the de-dupe
function is awesome". She rarely sees a sub-account already inside another hierarchy, so that case
is now a row flag only, not a banner.
Possible matches tick a row to use the existing Account
Entity you typed
Matching account
Matched on
Type
Account owner
Open opps
Ticked rows link to the existing Account. Unticked rows create a new Account.
No match found
Built from:Custom LWC, recommendednative fallback: Repeater of Number + a Check totals loop-back
Be honest about this screen. Two behaviours drawn here are not native Flow:
Live totals as you type. A Repeater's child components cannot react to other children of the
same Repeater. Natively, the variance can only recalculate when the screen is submitted, so the
pattern would be a "Check totals" button that loops back to this same screen.
The Apply remainder and Balance buttons. Flow screens have no arbitrary mid-screen action
buttons. These need either the same loop-back pattern or a custom LWC.
Recommendation: build this one screen as a custom LWC and leave every other screen native.
The arithmetic is the whole reason this wizard exists, so live feedback is worth the one component.
An inline-editable Data Table (Spring '26) gets close, but still cannot show a running remainder
as she types.
Why there is no Match badge:
Entity_Sum_Match__c compares the roll-up against the parent's own ACV. The
breakout zeroes the parent, so it reads "No Match" on every broken-out deal. Verified in prod and
in lldev. Do not surface it as a reconciliation signal.
No new field is needed to hold the pre-breakout total. Nothing downstream consumes it:
Booked_ACV_Account_Contribution__c already returns
Entity_Sum_Total_Net_Miter_ACV__c for a Contracted Entity and 0 for a Sub Entity, and
billing runs across the entities. The tie check only has to hold while the wizard is open, and the
parent is zeroed last, so its booked ACV is still readable then.
The maths, which is native either way:
Total TM per row is MAX() of that row's SKU counts, not the sum, because that is how
Total_Team_Members__c is defined.
Entity ACV = sum(licences × PEPM) × 12, the same maths
Gross_Miter_ACV_Update runs after insert. The wizard writes the licence counts and PEPM
rates only. It must not write Gross_Miter_ACV__c, or the flow overwrites it.
Distribute licences
Built from:Data Table (read-only)Display Text
What gets created, and what already blocks it.verified live, not from the repo
One insert, never two. Records must be created straight at StageName = "Booked"
in a single Create Records element. A create-at-Qualifying followed by an update to Booked trips
Opportunity_must_hit_all_stages, which only Cameron and Dan are exempt from.
Creating at Booked is allowed: Stage_Must_Start_in_Qualifying carves out Sub Entity, and
Opportunity_must_hit_all_stages is gated on ISCHANGED(StageName), false on insert.
Fill_in_Contracted_Entity_for_Sub_Entity needs Contracted_Entity__c in the
same insert as Entity_Type__c. No bypass, and it re-fires on every later save.
Booked_Details is the real blocker, and it is Dan's later-edit trap. No
ISCHANGED guard, so it re-fires on every save of a booked opportunity forever. It needs
both Win_Story__c and Miter_Use_Case__c, and Bypass_Validation__c
does nothing against it. The two flows that used to fill Miter_Use_Case__c are Obsolete.
Require_Complex_Tax_Fields_When_Booked needs
Operating_in_Complex_Tax_States__c and Number_of_Operating_States__c. It does
honour Bypass_Validation__c, set inside the Create element.
Two ways to solve both. Add NOT(ISPICKVAL(Entity_Type__c, "Sub Entity")) to each
rule, or run the creation as sfdc-access. Both rules exempt that user on $User.Idand on CreatedById, so its records stay exempt permanently, including later edits.
Record type. Stay on Standard. Sub_Entity has zero records and is not
available to the admin profile, so setting it would error.
Volume. 95 active Opportunity-triggered flows fire once per record, 47 of them Rattle.
Rocketlane fans out.RLSTAGEWH6463OPPORTUNITY publishes a platform event for every
row on insert with no filter. Confirm with the Rocketlane admin whether their project rule filters on
Entity_Type__c before this ships.
Row locks. Siblings share one parent. Sum_up_Miter_ACV_Fields runs per sibling and
each run writes the parent and every other sibling. UNABLE_TO_LOCK_ROW is expected, not remote.
Close date is not yours to set.Update_Close_Date_Automatically overwrites
CloseDate with today for a Booked record.
Caution: the local repo holds 26 rules, 20 active. Live holds 38, 30 active, and four
shared rules differ live. Build against the org.
Ready to create
#
Account
Opportunity (new)
Total TM
Entity ACV
Stage
Copied from the parent onto every sub-entity opportunity
Win Story Win_Story__c
Copied
Booked_Details requires it on every save, forever
Miter Use Case Miter_Use_Case__c
Copied
Booked_Details requires it; nothing auto-fills it any more
Complex tax states Operating_in_Complex_Tax_States__c
Copied
Require_Complex_Tax_Fields_When_Booked
Operating states Number_of_Operating_States__c
Copied
Require_Complex_Tax_Fields_When_Booked
Original target go-live Original_Target_Go_Live__c
Copied
no rule catches this at Booked, so it silently stays blank otherwise
Signature date Signature_Date__c
Copied
the stage-date flow blanks it on insert; it anchors the billing-start calculation
Lead source, type, close date
Copied
blank LeadSource breaks the downstream grouping flows
Also applied to the parent
Entity Type Entity_Type__c
Single Entity → Contracted Entity
Licence counts all 19 *_Team_Members__c
Zeroed, so the parent is not double-counted in the entity roll-up
Roll-ups Entity_Sum_* fields
Recalculated by Sum_up_Miter_ACV_Fields and
Sum_up_Total_Miter_Headcount_Field after insert
Built from:Display Text with merge fields
Not built in this POC. Re-running the wizard on a deal already broken out, and adding a single
entity after booking. Both are real needs; both are phase 2.
✓
Breakout complete.
Records created
Entity
Account
Opportunity
Entity ACV
Time
By hand today
~45–60 minutes
clone, build accounts, distribute in Scratchpad, push each opp through 7 stages
With the wizard
~3 minutes
measured on this run
Caroline offered to record a Loom of the manual process on her next multi-entity
booking, so these figures can be replaced with real ones.