1

I have created two fields Assign Rep and Sales Manager which is having lookup with User in Account Object. I am sharing records using Apex. I have written one trigger for that. Now the problem is if I update the value of Sales Manager it is deleting previous sharing record for Sales Manager user which is fine but it is also deleting the Assign rep sharing record.

Code for Update Trigger

if (Trigger.isUpdate) {
        set < ID > setChangesSalesRep = new set < ID > ();
        set < ID > setChangesAssignRep = new set < ID > ();
        Map < String, String> mapSalesRep;
        String SalesManager;
        String Assignrep;
        for (Account objAcc: Trigger.new) {
            Account oldAcc = Trigger.Oldmap.get(objAcc.id);

            if (oldAcc.Sales_Manager__c != objAcc.Sales_Manager__c) {
                system.debug('>>>>>>> If Sales Manager');
                mapSalesRep=new Map< String, String>();
                mapSalesRep.put(oldAcc.Sales_Manager__c+'_'+oldAcc.Id,objAcc.id);
                System.debug('Sales Rep Map is'+mapSalesRep);
                System.debug('Sales Rep Map is >>>>>>>'+mapSalesRep.get(oldAcc.Sales_Manager__c+'_'+oldAcc.Id).contains(objAcc.id));

                if(mapSalesRep.get(oldAcc.Sales_Manager__c+'_'+oldAcc.Id).contains(objAcc.id)) //null pointer Exception
                {
                    System.debug('>>>>>>>>'+mapSalesRep);
                    setChangesSalesRep.add(objAcc.id);

                    salesShr = new AccountShare();
                    salesShr.AccountId = objAcc.Id;
                    salesShr.UserOrGroupId = objAcc.Sales_Manager__c;
                    salesShr.AccountAccessLevel = 'Edit';
                    salesShr.CaseAccessLevel = 'Edit';
                    salesShr.OpportunityAccessLevel = 'Edit';
                    SalesManager = objAcc.Sales_Manager__c;

                    if (!setUserIds.CONTAINS(objAcc.Sales_Manager__c)) {
                        lstShareToInsert.add(salesShr);
                        setUserIds.add(objAcc.Sales_Manager__c);
                    }


                }               


            }

            if (oldAcc.Assigned_Rep__c != objAcc.Assigned_Rep__c) {
                system.debug('>>>>>>> If Assigned Rep');
                setChangesAssignRep.add(objAcc.id);
                system.debug('>>>>>>>>' + setChangesAssignRep);

                assignShr = new AccountShare();
                assignShr.AccountId = objAcc.Id;
                assignShr.UserOrGroupId = objAcc.Assigned_Rep__c;
                assignShr.AccountAccessLevel = 'Edit';
                assignShr.CaseAccessLevel = 'Edit';
                assignShr.OpportunityAccessLevel = 'Edit';
                Assignrep = objAcc.Assigned_Rep__c;


                system.debug('**************Assigned Rep' + objAcc.Assigned_Rep__c);

                if (!setUserIds.CONTAINS(objAcc.Assigned_Rep__c)) {
                    lstShareToInsert.add(assignShr);
                    setUserIds.add(objAcc.Assigned_Rep__c);
                }

            }

        }

        List < AccountShare > lstShareToDeleteSales = [Select ID, AccountID, UserorGroupID from AccountShare where AccountID IN: setChangesSalesRep AND RowCause='Manual'];
        List < AccountShare > lstShareToDeleteAssign = [Select ID, AccountID, UserorGroupID from AccountShare where AccountID IN: setChangesAssignRep AND RowCause='Manual'];

        system.debug('>>>>>>>>> Size lstShareToDeleteSales ::' + lstShareToDeleteSales);
        system.debug('>>>>>>>>> Size lstShareToDeleteAssign ::' + lstShareToDeleteAssign);


        if (SalesManager != null && lstShareToDeleteSales.size() > 0) {
            Database.Delete(lstShareToDeleteSales, false);
            Database.insert(lstShareToInsert, false);
        }
        if (Assignrep != null) {
            Database.Delete(lstShareToDeleteAssign, false);
           Database.insert(lstShareToInsert, false);
        }

    }
1

As above discussed by 'Stygon' for point 1 you can create a map which hold the Id of old Sales Manager and Account like this:

if (oldAcc.Sales_Manager__c != objAcc.Sales_Manager__c)

 {

 mapOfOldSalesRep=new Map< String, String>();
 mapOfOldSalesRep.put(oldAcc.Sales_Manager__c,objAcc.id);

.....//here come other code

And then before delete the accountShare records you can check which record you want to delete using below code:

 List < AccountShare > lstFinalDeleteSalesRep= new List < AccountShare >();

for(AccountShare accShare :lstShareToDeleteSales){

    if(mapOfOldSalesRep.get(accShare.UserorGroupID) ==   accShare.AccountID){
            lstFinalDeleteSalesRep.add(accShare );
            }
        }

And use lstFinalDeleteSalesRep list to perform delete operation.

Please let me know if this helps!!!

| improve this answer | |
3

The share records are entries in the sharing tables for records present in the database. So you cannot have duplicate share records i.e. You can't create two share records for the same account and user(there is an exception, lets wait for it!). So you are creating acountShare records for both 'Sales Manager' and 'Assign Rep' users. The apex share records you are creating for exposing the account record to 'Sales Manager' and 'Assign Rep' look identical to the system right. System doesn't have a way to distinguish between the sharing records created for these 2 different purposes. Thus during the procedure of deleting accountShare records you delete the share record and the corresponding user completely loses access to the account record - irrelevant of whether he should still have access to the account or not.

There are two ways to tackle this:

  1. Before deleting the accountShare records, pass them through an utlity method that will determine if that accountShare record is required, if yes dont delete it.
  2. Use different apex sharing reasons(RowCause) for the share records of 'Sales Manager' and 'Assign Rep' users. Now you can create multiple share records for an account and an user provided they user different rowcauses. At the time of deletion of the share records when 'Sales Manager' field is changed, delete only the share records with the correct rowcause(filter in query or code). Likewise for 'Assign Rep' field too. See : https://help.salesforce.com/apex/HTViewHelpDoc?id=security_apex_sharing_reasons.htm

Hope this helps.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.