Set Up Apex Triggers for Visit and Inventory Access
You can use these Apex triggers with profile-based permissions and organization-wide
sharing settings to make sure that users access just their visits and
inventories.
|
Available in: Lightning Experience Available in: Enterprise and Unlimited Editions with Health Cloud or Health Cloud for Life Sciences |
| User Permissions Needed | |
|---|---|
| To define, edit, delete, set security, and set version settings for Apex classes: | Author Apex |
| To run Apex tests: | View Setup and Configuration |
To set up Apex triggers, you must create a few utility classes first.
- Click Setup and select Developer Console.
-
Create the VisitAccess utility class.
- Select .
- For the Apex class name, enter VisitAccess.
-
Delete the auto-generated content and paste the following code.
1public class VisitAccess { 2 3 static Set<String> accessLevels = new Set<String>{'read', 'edit'}; 4 5 public static void insertVisitAccess(Visit visit, User user, String accessType) { 6 insertVisitAccess(visit, new List<User>{user}, accessType); 7 } 8 9 public static void insertVisitAccess(Visit visit, Id objectId, String accessType) { 10 if(isUser(objectId)) { 11 insertVisitAccess(visit, new User(id=objectId), accessType); 12 } 13 } 14 15 public static void insertVisitAccess(Visit visit, List<User> users, String accessType) { 16 if(visit==null || visit.Id==null || users==null || users.isEmpty()) { 17 return; 18 } 19 List<VisitShare> shareVisitList = new List<VisitShare>(); 20 for(User user: users) { 21 if(user==null) 22 continue; 23 VisitShare shareVisit = New VisitShare(); 24 shareVisit.ParentId=visit.Id; 25 shareVisit.UserOrGroupID = user.Id; 26 shareVisit.AccessLevel = accessType; 27 shareVisitList.add(shareVisit); 28 } 29 try{ 30 Database.insert(shareVisitList); 31 } catch(Exception e) { 32 System.debug('Unexpected exception : ' + e); 33 } 34 } 35 36 public static void updateVisitAccess(Visit visit, List<Id> oldUsers, List<Id> newUsers, String access) { 37 if(visit==null) { 38 return; 39 } 40 if(oldUsers!=null) { 41 for(Id userId : oldUsers) { 42 if(isUser(userId)) { 43 deleteVisitAccess(visit, new User(id=userId)); 44 } 45 } 46 } 47 if(newUsers!=null) { 48 for(Id userId : newUsers) { 49 if(isUser(userId)) { 50 insertVisitAccess(visit, userId, access); 51 } 52 } 53 } 54 } 55 56 public static void updateVisitAccess(Visit oldVisit, Visit updatedVisit, String access) { 57 //Comment this condition if for any update visit need to be shared 58 if(oldVisit.VisitorId==updatedVisit.VisitorId) { 59 return; 60 } 61 updateVisitAccess(oldVisit, oldVisit!=null?new List<Id>{oldVisit.VisitorId}:new List<Id>(), updatedVisit!=null?new List<Id>{updatedVisit.VisitorId}:new List<Id>(), access); 62 } 63 64 //remove user from oldVisit if user does not have any more access to oldVisit, and link user to newVisit 65 public static void updateVisitAccess(Visit oldVisit, Visit newVisit, List<User> users, String access) { 66 if(users==null || users.isEmpty()) { 67 return; 68 } 69 if(access==null||!accessLevels.contains(access)) { 70 access='edit'; 71 } 72 for(User user : users) { 73 if(oldVisit!=null) 74 deleteVisitAccess(oldVisit, user); 75 if(newVisit!=null) 76 insertVisitAccess(newVisit, user, access); 77 } 78 } 79 80 81 //remove user from oldVisit if user does not have any more access to oldVisit, and link user to newVisit 82 public static void updateVisitAccess(Visit oldVisit, Visit newVisit, Id objectId, String access) { 83 if(isUser(objectId)) { 84 updateVisitAccess(oldVisit, newVisit, new List<User>{new User(id=objectId)}, access); 85 } 86 } 87 88 public static void deleteVisitAccess(Visit visit, List<User> users) { 89 List<VisitShare> visitShareList = new List<VisitShare>(); 90 for(User user : users) { 91 if(isUserLinkedToVisit(user, visit)) 92 continue; 93 List<VisitShare> visitShare = [select Id from VisitShare where ParentId = :visit.Id and UserOrGroupID = :user.Id and RowCause='Manual']; 94 if(!visitShare.isEmpty()) { 95 visitShareList.add(visitShare.get(0)); 96 } 97 } 98 delete visitShareList; 99 } 100 101 public static void deleteVisitAccess(Visit visit, User user) { 102 deleteVisitAccess(visit, new List<User>{user}); 103 } 104 105 public static void deleteVisitAccess(Visit visit, Id objectId) { 106 if(isUser(objectId)) { 107 deleteVisitAccess(visit, new User(id=objectId)); 108 } 109 } 110 111 public static Boolean isUser(Id objId) { 112 if(objId==null) 113 return false; 114 List<User> users = [select Id from User where Id = :objId]; 115 return !users.isEmpty(); 116 } 117 118 public static Boolean isUser(Object obj) { 119 if(obj==null) 120 return false; 121 try { 122 User user = (User)obj; 123 } catch(TypeException e) { 124 return false; 125 } 126 return true; 127 } 128 129 public static Boolean isUserLinkedToVisit(User user, Visit visit) { 130 List<Visit> visits = [select Id from Visit where VisitorId = :user.Id and Id=:visit.Id]; 131 List<Visitor> visitors = [select Id from Visitor where AssigneeId = :user.Id and VisitId=:visit.Id]; 132 return !visits.isEmpty() || !visitors.isEmpty(); 133 } 134} - Select .
-
Create the visit trigger.
- Select .
- For the trigger name, enter VisitTrigger, and select Visit from the sObject picklist.
-
Delete the auto-generated content and paste the following sample.
1trigger VisitTrigger on Visit (after insert, after update) { 2 List<VisitShare> visitShares = new List<VisitShare>(); 3 for(Visit visit : trigger.new) { 4 if(trigger.isUpdate) { 5 Visit oldVisit = trigger.oldMap.get(visit.Id); 6 VisitAccess.updateVisitAccess(oldVisit, visit, 'edit'); 7 } 8 if(trigger.isInsert) { 9 VisitAccess.insertVisitAccess(visit, visit.VisitorId, 'edit'); 10 } 11 } 12} - Select .
-
Create the visitor trigger.
- Select .
- For the trigger name, enter VisitorTrigger, and select Visitor from the sObject picklist.
-
Delete the auto-generated content and paste the following sample.
1trigger VisitorTrigger on Visitor (after insert, after update, after delete) { 2 3 if(trigger.isInsert) { 4 for(Visitor visitor : trigger.new) { 5 VisitAccess.insertVisitAccess(new Visit(id=visitor.VisitId), visitor.AssigneeId, 'edit'); 6 } 7 } 8 9 if(trigger.isUpdate) { 10 for(Visitor visitor : trigger.new) { 11 Visitor oldVisitor = trigger.oldMap.get(visitor.Id); 12 VisitAccess.updateVisitAccess(new Visit(id=oldVisitor.VisitId), new Visit(id=visitor.VisitId), visitor.AssigneeId, 'edit'); 13 } 14 } 15 16 if(trigger.isDelete) { 17 for(Visitor visitor : trigger.old) { 18 VisitAccess.deleteVisitAccess(new Visit(id=visitor.VisitId), visitor.AssigneeId); 19 } 20 } 21} - Select .
Now, sales reps can see only the visits they’re assigned to. -
Create the ProductItemAccess utility class.
- Select .
- For the Apex class name, enter ProductItemAccess.
-
Delete the auto-generated content and paste the following sample.
1public class ProductItemAccess { 2 3 public static void insertAccess(List<ProductItem> productItems, List<Id> users, String access) { 4 5 if(productItems==null || productItems.isEmpty() || users==null || users.isEmpty()) { 6 return; 7 } 8 productItems = getProductItemsWithId(productItems); 9 List<ProductItemShare> shareList = new List<ProductItemShare>(); 10 for(Id user: users) { 11 if(user==null) 12 continue; 13 for(ProductItem item : productItems) { 14 ProductItemShare share = New ProductItemShare(); 15 share.ParentId=item.Id; 16 share.UserOrGroupID = user; 17 share.AccessLevel = access; 18 shareList.add(share); 19 } 20 } 21 try{ 22 Database.insert(shareList); 23 } catch (Exception e) { 24 System.debug(e); 25 } 26 } 27 28 public static void deleteAccess(List<ProductItem> productItems, List<Id> users) { 29 List<ProductItemShare> shareList = new List<ProductItemShare>(); 30 for(Id userId : users) { 31 for(ProductItem productItem : productItems) { 32 List<ProductItemShare> shares = [select Id from ProductItemShare where ParentId = :productItem.Id and UserOrGroupID = :userId and RowCause='Manual']; 33 if(!shares.isEmpty()) { 34 shareList.addAll(shares); 35 } 36 } 37 } 38 delete shareList; 39 } 40 41 public static List<ProductItem> getProductItems(ProductFulfillmentLocation fulfillLocation) { 42 return [select Id from ProductItem where Product2Id=:fulfillLocation.ProductId and LocationId=:fulfillLocation.FulfillmentLocationId]; 43 } 44 45 private static List<ProductItem> getProductItemsWithId(List<ProductItem> productItems) { 46 List<ProductItem> productItemsWithId = new List<ProductItem>(); 47 for(ProductItem item : productItems) { 48 if(item==null) 49 continue; 50 if(item.id==null) { 51 List<ProductItem> itemList = [select Id from ProductItem where Product2Id=:item.Product2Id and LocationId=:item.locationId]; 52 productItemsWithId.addAll(itemList); 53 } 54 } 55 return productItemsWithId; 56 } 57} - Select .
-
Create the ProductFulfillmentLocationAccess utility
class.
- Select .
- For the Apex class name, enter ProductFulfillmentLocationAccess.
-
Delete the auto-generated content and paste the following sample.
1public class ProductFulfillmentLocationAccess { 2 3 static Set<String> accessLevels = new Set<String>{'read', 'edit'}; 4 5 /** 6 * Gives access to users on all product fulfillment locations 7 */ 8 public static void insertAccessToAllLocations(ProductFulfillmentLocation locationToInsert, String accessType) { 9 List<ProductFulfillmentLocation> fulfillLocations = [select Id, ProductId, FulfillmentLocationId from ProductFulfillmentLocation]; 10 insertAccess(fulfillLocations, getAllResponsibleUsers(), accessType); 11 insertProductItemAccess(new List<ProductFulfillmentLocation>{locationToInsert}, new List<Id>{locationToInsert.UserId}, accessType); 12 } 13 14 public static void insertAccess(List<ProductFulfillmentLocation> fulfillLocations, List<Id> users, String accessType) { 15 if(fulfillLocations==null || fulfillLocations.isEmpty() || users==null || users.isEmpty()) { 16 return; 17 } 18 List<ProductFulfillmentLocationShare> shareList = new List<ProductFulfillmentLocationShare>(); 19 for(Id user: users) { 20 if(user==null) 21 continue; 22 for(ProductFulfillmentLocation location : fulfillLocations) { 23 if(location==null || location.Id==null) 24 continue; 25 ProductFulfillmentLocationShare share = New ProductFulfillmentLocationShare(); 26 share.ParentId=location.Id; 27 share.UserOrGroupID = user; 28 share.AccessLevel = accessType; 29 shareList.add(share); 30 } 31 } 32 try{ 33 Database.insert(shareList); 34 } catch (Exception e) { 35 System.debug(e); 36 } 37 } 38 39 public static void updateAccess(ProductFulfillmentLocation oldLocation, ProductFulfillmentLocation updatedLocation, String access) { 40 deleteAccess(oldLocation); 41 insertAccessToAllLocations(updatedLocation, access); 42 } 43 44 public static void deleteAccess(List<Id> users) { 45 List<ProductFulfillmentLocationShare> shareList = new List<ProductFulfillmentLocationShare>(); 46 for(Id userId : users) { 47 if(isUserLinkedTofulfillLocation(userId)) 48 continue; 49 List<ProductFulfillmentLocationShare> shares = [select Id from ProductFulfillmentLocationShare where UserOrGroupID = :userId and RowCause='Manual']; 50 if(!shares.isEmpty()) { 51 shareList.addAll(shares); 52 } 53 } 54 delete shareList; 55 } 56 57 public static void deleteAccess(ProductFulfillmentLocation fulfillLocation) { 58 deleteAccess(new List<Id>{fulfillLocation.UserId}); 59 deleteProductItemAccess(fulfillLocation); 60 } 61 62 public static Boolean isUserLinkedTofulfillLocation(Id userId) { 63 List<ProductFulfillmentLocation> fulfillLocations = [select Id from ProductFulfillmentLocation where UserId = :userId]; 64 return !fulfillLocations.isEmpty(); 65 } 66 67 public static void deleteProductItemAccess(ProductFulfillmentLocation fulfillLocation) { 68 ProductItemAccess.deleteAccess(ProductItemAccess.getProductItems(fulfillLocation), new List<id>{fulfillLocation.UserId}); 69 } 70 71 public static void insertProductItemAccess(List<ProductFulfillmentLocation> fulfillLocations, List<Id> users, String access) { 72 List<ProductItem> productItems = new List<ProductItem>(); 73 for(ProductFulfillmentLocation location : fulfillLocations) { 74 productItems.add(new ProductItem(Product2Id=location.ProductId, LocationId=location.FulfillmentLocationId)); 75 } 76 ProductItemAccess.insertAccess(productItems, users, access); 77 } 78 79 public static List<Id> getAllResponsibleUsers() { 80 List<Id> users = new List<Id>(); 81 List<ProductFulfillmentLocation> fulfillLocations = [select UserId from ProductFulfillmentLocation]; 82 for(ProductFulfillmentLocation location : fulfillLocations) { 83 users.add(location.UserId); 84 } 85 return users; 86 } 87} - Select .
Now sales reps can see only the inventories they’re responsible for.