Extending QuoteX Cloning Logic
Published on May 8, 2026 QuoteX
Extending QuoteX Cloning Logic
Technical Design Guide
Objective
| Goal: Enable 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. The native process also provides no direct hook to map these fields, so a workaround is required to identify the Source Record ID during the before insert execution context.
Logic & Workaround Strategy
To map custom fields, capture the Source Record ID, retrieve its custom field values, and inject them into the new record. Two existing fields act as temporary pass-through containers for the Source ID:
- Parent Quotes: the deprecated
Version Notesfield. - Timelines (Child Quotes): the standard
Namefield (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__ccontains 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
Namefield 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__cwith the ID of the newly created record (or nullify if preferred). - Timeline Records: Update the
Namefield with the ID of the newly created record to overwrite the source ID reference.
Trigger Summary
| 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 and 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) |
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:
Version_Notes__cis 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
Namefield for Timelines; our logic must override this in the After Insert phase to maintain record naming conventions.
Potential Risks & Enhancements
Consider these technical nuances to keep the solution robust:
| Recursion Trap: Since you perform an After Insert update on the same object, use static variable recursion control. Do not update Trigger.new directly; create a new instance of the object and update that. |
| Governor Limits (Bulkification): | In Before Insert, 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. |
Name Field Sensitivity: Since the standard Name field is used for Timelines, ensure no other automation (auto-numbering, Flows) overwrites the Source ID before your Before Insert logic reads it. Apply this only to Timelines, never to Parent Quotes, because the Parent Quote Name is populated by users. |
Knowledge Article Number: KA-00240