To enable the cloning of custom (out-of-namespace) fields during the QuoteX cloning process for both Parent Quotes and Timeline (Child) records.
⚠️ Scope This approach applies only to custom fields you have added to the PSC Quote object. Native managed-package fields are handled internally by QuoteX and are outside scope.
Problem Statement
The QuoteX managed package cloning functionality only recognizes fields within its own namespace. Custom fields added to the PSC Quote object are ignored during the native clone operation. Additionally, the native process does not provide a direct hook to map these fields, requiring a workaround to identify the Source Record ID during the before insert execution context.
Logic & Workaround Strategy
To map custom fields, we must capture the Source Record ID, retrieve its custom field values, and inject them into the new record. We will utilize two existing fields as temporary "pass-through" containers for the Source ID:
For Parent Quotes: The deprecated Version Notes field.
For Timelines (Child Quotes): The standard Name field (pre-populated by the package as "Only for Timeline").
Record Identification Criteria
Record Type
psce__Is_Specific_To_Timeline__c
psce__Parent_Estimate__c
Identity Container
Parent Quote
False
null
Version_Notes__c
Timeline (Child)
True
NOT null
Name
Execution Logic (Apex Trigger / Flow)
▶ Phase A: Before Insert (Data Mapping)
Parent Quotes:
Check if Version_Notes__c contains a valid Salesforce 18-digit ID.
If valid, query the Source Quote record for all relevant custom field values.
Map these values to the current record instance (Trigger.new).
Timeline Records:
Check if the Name field contains a valid Salesforce 18-digit ID.
If valid, query the Source Timeline record for all relevant custom field values.
Map these values to the current record instance (Trigger.new).
▶ Phase B: After Insert (Field Cleanup)
To ensure data integrity and prevent the "pass-through" IDs from remaining in the system:
Parent Quotes: Update Version_Notes__c with the ID of the newly created record (or nullify if preferred).
Timeline Records: Update the Name field with the ID of the newly created record to overwrite the source ID reference.
Implementation Notes & Constraints
Namespace Awareness: Ensure the query for custom fields dynamically handles fields outside the psce__ namespace.
SOQL Optimization: When bulk cloning, ensure the "Source Record" queries are bulkified (Collection-based) to avoid Governor Limits.
Field Deprecation: Note that Version_Notes__c is deprecated as of v1.85 and is safe for re-purposing as a temporary ID container for Parent Quotes.
Timeline Hard-coding: The native package hard-codes the Name field for Timelines; our logic must override this in the After Insert phase to maintain record naming conventions.
Trigger Event
Condition
Action
Before Insert
Version_Notes__c contains valid record ID
Fetch source Quote, copy custom field values to new record
Before Insert
Name = valid record ID & Timeline condition met
Fetch source Timeline, copy custom field values to new record
After Insert
psce__Is_Specific_To_Timeline__c = false
Set Version_Notes__c = new record ID (via DML update)
After Insert
psce__Is_Specific_To_Timeline__c = true
Set Name = new record ID (via DML update)
Potential Risks & Enhancements
While the logic is solid, you should consider these technical nuances to ensure it is "100% correct":
The "Recursion" Trap: Since you are doing an After Insert update on the same object, ensure your trigger framework has Static Variable recursion control. Don't use Trigger.new rather create a new instance of object and update.
Governor Limits (Bulkification):
In the Before Insert, you must collect all IDs from the Version Notes/Name fields first.
Run one single SOQL query to get all custom field values for those Source IDs.
Map them using a Map<Id, PSC_Quote__c>.
Never query inside the loop.
The "Name" Field Sensitivity: Since you are using the Standard Name field for Timelines, ensure that any other automation (like Auto-numbering or other Flows) doesn't overwrite your Source ID before your Before Insert logic has a chance to read it. And it has to happen only for timelines and not for parent Quote because parent quote Name field is in use and populated by users.