Welcome to Zuora Product Documentation

Explore our rich library of product information

Compare Zuora managed package permission sets with custom permission sets

Learn how to compare Zuora managed package permission sets with custom permission sets using Apex code.

You can compare the Zuora managed managed package permission sets with custom permission sets by running the code provided in this article.
  1. Open the Developer Console and select File > New > Apex Class.
    Alternatively, go to Setup and create a new Apex class.
  2. Name the class PermissionSetCopyUtil.
    If you use a different name, ensure to update the class name in the code snippet provided in this article.
  3. Paste the code snippet provided in this article into the new class and click Save.
  4. In the Developer Console, click Debug > Execute Anonymous Window and paste the following code based on your requirement:
    • To view the comparison of the permission sets in the log, use the following code. In the following code, replace 'source' with the API name of the source permission set and 'target' with the API name of the target permission set.
      PermissionSetCopyUtil.copyPermissions('source','target',false);
    • To view the comparison of the permission sets in the log and update the changes, use the following code. In the following code, replace 'source' with the API name of the source permission set and 'target' with the API name of the target permission set.
      PermissionSetCopyUtil.copyPermissions('source','target',true);
    Note: In the above Replace 'source' with the actual API name of the source permission set and 'target' with the actual API name of the target permission set.
    Code snippet
    The following code may be run to compare the Zuora managedmanaged package permission sets with custom permission sets.
    /**
     * @description Utility class to copy permissions from one permission set to another
     */
    public with sharing class PermissionSetCopyUtil {
        
        /**
         * @description Copies permissions from source permission set to target permission set.
         * This utility only adds permissions to the target permission set and never removes any existing permissions.
         * @param sourcePermSetName API NAME  of the source permission set
         * @param targetPermSetName API NAME of the target permission set
         * @param performDML When False:Permissions can be reviewed in the log.Nothing will be updated. When True: Permissions will be updated.
         * @return Result containing success status and any error messages
         */
        public static CopyResult copyPermissions(string sourcePermSetName, string targetPermSetName,Boolean performDML) {
            CopyResult result = new CopyResult();
             try {
                // Validate input parameters
                if (String.isBlank(sourcePermSetName) || String.isBlank(targetPermSetName)) {
                    return new CopyResult(false, 'Permission Set names cannot be blank');
                }
                
                // Single optimized query to get both permission sets
                Map<String, PermissionSet> permSetMap = new Map<String, PermissionSet>();
                for (PermissionSet ps : [SELECT Id, Name FROM PermissionSet WHERE Name IN (:sourcePermSetName, :targetPermSetName)]) {
                    permSetMap.put(ps.Name, ps);
                }
                
                // Validate both permission sets exist
                PermissionSet sourcePermSet = permSetMap.get(sourcePermSetName);
                if (sourcePermSet == null) {
                    return new CopyResult(false, 'Source Permission Set not found: ' + sourcePermSetName);
                }
                
                PermissionSet targetPermSet = permSetMap.get(targetPermSetName);
                if (targetPermSet == null) {
                    return new CopyResult(false, 'Target Permission Set not found: ' + targetPermSetName);
                }
                
                // Prevent copying to the same permission set
                if (sourcePermSet.Id == targetPermSet.Id) {
                    return new CopyResult(false, 'Source and target permission sets cannot be the same');
                }
    
                // Copy object permissions
                result.objectPermissionResults = copyObjectPermissions(sourcePermSet.Id, targetPermSet.Id,performDML);
                
                // Copy field permissions
                result.fieldPermissionResults = copyFieldPermissions(sourcePermSet.Id, targetPermSet.Id,performDML);
                
                // Copy class access
                result.classAccessResults = copyClassAccess(sourcePermSet.Id, targetPermSet.Id,performDML);
                
               
                result.success = true;
                result.message = 'Permission copy completed successfully';
                System.debug(JSON.serialize(result));
            } catch (Exception e) {
                System.debug(e.getStackTraceString());
                System.debug(e.getMessage());
                result.success = false;
                result.message = 'Error copying permissions: ' + e.getMessage();
                System.debug(JSON.serialize(result));
            }
            return result;
        }
        
        /**
         * @description Copies object permissions from source to target permission set
         * @param sourcePermSetId Source permission set ID
         * @param targetPermSetId Target permission set ID
         * @param performDML When False:Permissions can be reviewed in the log.Nothing will be updated. When True: Permissions will be updated.
         * @return List of results for each object permission copied
         */
        private static List<PermissionResult> copyObjectPermissions(Id sourcePermSetId, Id targetPermSetId,Boolean performDML) {
            List<PermissionResult> results = new List<PermissionResult>();
            
            // Query source object permissions
            List<ObjectPermissions> sourceObjectPerms = [
                SELECT Id, SObjectType, PermissionsCreate, PermissionsRead, PermissionsEdit, 
                       PermissionsDelete, PermissionsViewAllRecords, PermissionsModifyAllRecords
                FROM ObjectPermissions
                WHERE ParentId = :sourcePermSetId
            ];
            
            // Query existing target object permissions for upsert operation
            Map<String, ObjectPermissions> targetObjectPermsMap = new Map<String, ObjectPermissions>();
            for (ObjectPermissions op : [
                SELECT Id, SObjectType, PermissionsCreate, PermissionsRead, PermissionsEdit, 
                       PermissionsDelete, PermissionsViewAllRecords, PermissionsModifyAllRecords
                FROM ObjectPermissions
                WHERE ParentId = :targetPermSetId
            ]) {
                targetObjectPermsMap.put(op.SObjectType, op);
            }
            
            // Prepare object permissions to upsert
            List<ObjectPermissions> objectPermsToUpsert = new List<ObjectPermissions>();
            
            for (ObjectPermissions sourceObjPerm : sourceObjectPerms) {
                // Check if object permission already exists in target
                ObjectPermissions targetObjPerm = targetObjectPermsMap.get(sourceObjPerm.SObjectType);
                
                if (targetObjPerm == null) {
                    // Create new object permission
                    targetObjPerm = new ObjectPermissions(
                        ParentId = targetPermSetId,
                        SObjectType = sourceObjPerm.SObjectType,
                        PermissionsCreate = sourceObjPerm.PermissionsCreate,
                        PermissionsRead = sourceObjPerm.PermissionsRead,
                        PermissionsEdit = sourceObjPerm.PermissionsEdit,
                        PermissionsDelete = sourceObjPerm.PermissionsDelete,
                        PermissionsViewAllRecords = sourceObjPerm.PermissionsViewAllRecords,
                        PermissionsModifyAllRecords = sourceObjPerm.PermissionsModifyAllRecords
                    );
                    results.add(new PermissionResult(sourceObjPerm.SObjectType, 'Created'));
                } else {
                    Boolean isUpdated = false;
                    if(sourceObjPerm.PermissionsCreate != targetObjPerm.PermissionsCreate){
                        System.debug('Object Name: ' + sourceObjPerm.SObjectType + ' Source Create Permission : ' + sourceObjPerm.PermissionsCreate + ' Target Create Permission : ' + targetObjPerm.PermissionsCreate);
                        targetObjPerm.PermissionsCreate = targetObjPerm.PermissionsCreate || sourceObjPerm.PermissionsCreate;
                        isUpdated = true;
                    }
                    if(sourceObjPerm.PermissionsRead != targetObjPerm.PermissionsRead){
                        System.debug('Object Name: ' + sourceObjPerm.SObjectType + ' Source Read Permission : ' + sourceObjPerm.PermissionsRead + ' Target Read Permission : ' + targetObjPerm.PermissionsRead);
                        targetObjPerm.PermissionsRead = targetObjPerm.PermissionsRead || sourceObjPerm.PermissionsRead;
                        isUpdated = true;
                    }
                    if(sourceObjPerm.PermissionsEdit != targetObjPerm.PermissionsEdit){
                        System.debug('Object Name: ' + sourceObjPerm.SObjectType + ' Source Edit Permission : ' + sourceObjPerm.PermissionsEdit + ' Target Edit Permission : ' + targetObjPerm.PermissionsEdit);
                        targetObjPerm.PermissionsEdit = targetObjPerm.PermissionsEdit || sourceObjPerm.PermissionsEdit;
                        isUpdated = true;
                    }
                    if(sourceObjPerm.PermissionsDelete != targetObjPerm.PermissionsDelete){
                        System.debug('Object Name: ' + sourceObjPerm.SObjectType + ' Source Delete Permission : ' + sourceObjPerm.PermissionsDelete + ' Target Delete Permission : ' + targetObjPerm.PermissionsDelete);
                        targetObjPerm.PermissionsDelete = targetObjPerm.PermissionsDelete || sourceObjPerm.PermissionsDelete;
                        isUpdated = true;
                    }
                    if(sourceObjPerm.PermissionsViewAllRecords != targetObjPerm.PermissionsViewAllRecords){
                        System.debug('Object Name: ' + sourceObjPerm.SObjectType + ' Source View All Permission : ' + sourceObjPerm.PermissionsViewAllRecords + ' Target View All Permission : ' + targetObjPerm.PermissionsViewAllRecords);
                        targetObjPerm.PermissionsViewAllRecords = targetObjPerm.PermissionsViewAllRecords || sourceObjPerm.PermissionsViewAllRecords;
                        isUpdated = true;
                    }
                    if(sourceObjPerm.PermissionsModifyAllRecords != targetObjPerm.PermissionsModifyAllRecords){
                        System.debug('Object Name: ' + sourceObjPerm.SObjectType + ' Source Modify All Permission : ' + sourceObjPerm.PermissionsModifyAllRecords + ' Target Modify All Permission : ' + targetObjPerm.PermissionsModifyAllRecords);
                        targetObjPerm.PermissionsModifyAllRecords = targetObjPerm.PermissionsModifyAllRecords || sourceObjPerm.PermissionsModifyAllRecords;
                        isUpdated = true;
                    }
                    if(isUpdated){
                        results.add(new PermissionResult(sourceObjPerm.SObjectType, 'Updated'));
                    }
                }
                
                objectPermsToUpsert.add(targetObjPerm);
            }
            
            // Upsert object permissions
            if (performDML && !objectPermsToUpsert.isEmpty()) {
                upsert objectPermsToUpsert;
            }
            
            return results;
        }
        
        /**
         * @description Copies field permissions from source to target permission set
         * @param sourcePermSetId Source permission set ID
         * @param targetPermSetId Target permission set ID
         * @param performDML When False:Permissions can be reviewed in the log.Nothing will be updated. When True: Permissions will be updated.
         * @return List of results for each field permission copied
         */
        private static List<PermissionResult> copyFieldPermissions(Id sourcePermSetId, Id targetPermSetId,Boolean performDML) {
            List<PermissionResult> results = new List<PermissionResult>();
            
            // Query source field permissions
            List<FieldPermissions> sourceFieldPerms = [
                SELECT Id, Field, PermissionsRead, PermissionsEdit, SobjectType
                FROM FieldPermissions
                WHERE ParentId = :sourcePermSetId
            ];
            
            // Query existing target field permissions for upsert operation
            Map<String, FieldPermissions> targetFieldPermsMap = new Map<String, FieldPermissions>();
            for (FieldPermissions fp : [
                SELECT Id, Field, PermissionsRead, PermissionsEdit, SobjectType
                FROM FieldPermissions
                WHERE ParentId = :targetPermSetId
            ]) {
                targetFieldPermsMap.put(fp.Field, fp);
            }
            
            // Prepare field permissions to upsert
            List<FieldPermissions> fieldPermsToUpsert = new List<FieldPermissions>();
            
            for (FieldPermissions sourceFieldPerm : sourceFieldPerms) {
                // Check if field permission already exists in target
                FieldPermissions targetFieldPerm = targetFieldPermsMap.get(sourceFieldPerm.Field);
                
                if (targetFieldPerm == null) {
                    // Create new field permission
                    targetFieldPerm = new FieldPermissions(
                        ParentId = targetPermSetId,
                        Field = sourceFieldPerm.Field,
                        SobjectType = sourceFieldPerm.SobjectType,
                        PermissionsRead = sourceFieldPerm.PermissionsRead,
                        PermissionsEdit = sourceFieldPerm.PermissionsEdit
                    );
                    
                    results.add(new PermissionResult(sourceFieldPerm.Field, 'Created'));
                } else {
                    Boolean isUpdated = false;
                    if(targetFieldPerm.PermissionsRead != sourceFieldPerm.PermissionsRead){
                        System.debug('Field Name: ' + targetFieldPerm.Field + ' Source Read Permission : ' + sourceFieldPerm.PermissionsRead + ' Target  Read Permission : ' + targetFieldPerm.PermissionsRead);
                        targetFieldPerm.PermissionsRead = targetFieldPerm.PermissionsRead || sourceFieldPerm.PermissionsRead;
    
                    }
                    if(targetFieldPerm.PermissionsEdit != sourceFieldPerm.PermissionsEdit){
                        System.debug('Field Name: ' + targetFieldPerm.Field + ' Source Edit Permission : ' + sourceFieldPerm.PermissionsEdit + ' Target  Edit Permission : ' + targetFieldPerm.PermissionsEdit);
                        targetFieldPerm.PermissionsEdit = targetFieldPerm.PermissionsEdit || sourceFieldPerm.PermissionsEdit;
                    }
                    // Update existing field permission - only add permissions, never remove them
                    if(isUpdated){
                        results.add(new PermissionResult(sourceFieldPerm.Field, 'Updated'));
                    }
                }
                
                fieldPermsToUpsert.add(targetFieldPerm);
            }
            
            // Upsert field permissions
            if (performDML && !fieldPermsToUpsert.isEmpty()) {
                Database.upsert(fieldPermsToUpsert,false);
            }
            
            return results;
        }
        
        /**
         * @description Copies Apex class access from source to target permission set
         * @param sourcePermSetId Source permission set ID
         * @param targetPermSetId Target permission set ID
         * @param performDML When False:Permissions can be reviewed in the log.Nothing will be updated. When True: Permissions will be updated.
         * @return List of results for each class access copied
         */
        private static List<PermissionResult> copyClassAccess(Id sourcePermSetId, Id targetPermSetId,Boolean performDML) {
            List<PermissionResult> results = new List<PermissionResult>();
            
            // Query source class access
            List<SetupEntityAccess> sourceClassAccess = [
                SELECT Id, SetupEntityId, SetupEntityType
                FROM SetupEntityAccess
                WHERE ParentId = :sourcePermSetId AND SetupEntityType = 'ApexClass'
            ];
            
            // Query existing target class access for upsert operation
            Map<Id, SetupEntityAccess> targetClassAccessMap = new Map<Id, SetupEntityAccess>();
            for (SetupEntityAccess sea : [
                SELECT Id, SetupEntityId, SetupEntityType
                FROM SetupEntityAccess
                WHERE ParentId = :targetPermSetId AND SetupEntityType = 'ApexClass'
            ]) {
                targetClassAccessMap.put(sea.SetupEntityId, sea);
            }
            
            // Query class names for better reporting
            Map<Id, String> classNames = new Map<Id, String>();
            for (ApexClass cls : [SELECT Id, Name FROM ApexClass WHERE Id IN (SELECT SetupEntityId FROM SetupEntityAccess WHERE ParentId = :sourcePermSetId AND SetupEntityType = 'ApexClass')]) {
                classNames.put(cls.Id, cls.Name);
            }
            
            // Prepare class access to insert
            List<SetupEntityAccess> classAccessToInsert = new List<SetupEntityAccess>();
            
            for (SetupEntityAccess sourceAccess : sourceClassAccess) {
                // Check if class access already exists in target
                if (!targetClassAccessMap.containsKey(sourceAccess.SetupEntityId)) {
                    // Create new class access
                    SetupEntityAccess targetAccess = new SetupEntityAccess(
                        ParentId = targetPermSetId,
                        SetupEntityId = sourceAccess.SetupEntityId
                        //SetupEntityType = 'ApexClass'
                    );
                    classAccessToInsert.add(targetAccess);
                    
                    String className = classNames.containsKey(sourceAccess.SetupEntityId) ? classNames.get(sourceAccess.SetupEntityId) : String.valueOf(sourceAccess.SetupEntityId);
                    results.add(new PermissionResult(className, 'Created'));
                }
            }
            
            // Insert class access
            if (performDML && !classAccessToInsert.isEmpty()) {
                insert classAccessToInsert;
            }
            
            return results;
        }
        
    
        /**
         * @description Class to hold the result of a permission copy operation
         */
        public class CopyResult {
            @AuraEnabled public Boolean success { get; set; }
            @AuraEnabled public String message { get; set; }
            @AuraEnabled public List<PermissionResult> objectPermissionResults { get; set; }
            @AuraEnabled public List<PermissionResult> fieldPermissionResults { get; set; }
            @AuraEnabled public List<PermissionResult> classAccessResults { get; set; }
            @AuraEnabled public List<PermissionResult> pageAccessResults { get; set; }
            
            public CopyResult() {
                this.success = false;
                this.objectPermissionResults = new List<PermissionResult>();
                this.fieldPermissionResults = new List<PermissionResult>();
                this.classAccessResults = new List<PermissionResult>();
                this.pageAccessResults = new List<PermissionResult>();
            }
            
            public CopyResult(Boolean success, String message) {
                this();
                this.success = success;
                this.message = message;
            }
        }
        
        /**
         * @description Class to hold the result of a single permission copy operation
         */
        public class PermissionResult {
            @AuraEnabled public String name { get; set; }
            @AuraEnabled public String status { get; set; }
            
            public PermissionResult(String name, String status) {
                this.name = name;
                this.status = status;
            }
        }
    }