Implement appropriate Apex Classes and Triggers in your org to control how visit and inventory access is shared with your users. You can write these classes and triggers in any way that best suits your organization's requirements. Here are some sample Apex classes and triggers to help you get started. The Visit trigger provides sharing access to the Visit object and related objects at the time a visit is created or updated. The Visitor trigger provides access to the user who is assigned to a visit. 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.
Required Editions
|
Available in: Lightning Experience Available in: Enterprise and Unlimited Editions with Health Cloud or Life Sciences Cloud |
| 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
VisitAccessutility class.- Select File | New | Apex Class.
- For the Apex class name, enter VisitAccess.
-
Delete the auto-generated content and paste the following code.
public class VisitAccess { static Set<String> accessLevels = new Set<String>{'read', 'edit'}; public static void insertVisitAccess(Visit visit, User user, String accessType) { insertVisitAccess(visit, new List<User>{user}, accessType); } public static void insertVisitAccess(Visit visit, Id objectId, String accessType) { if(isUser(objectId)) { insertVisitAccess(visit, new User(id=objectId), accessType); } } public static void insertVisitAccess(Visit visit, List<User> users, String accessType) { if(visit==null || visit.Id==null || users==null || users.isEmpty()) { return; } List<VisitShare> shareVisitList = new List<VisitShare>(); for(User user: users) { if(user==null) continue; VisitShare shareVisit = New VisitShare(); shareVisit.ParentId=visit.Id; shareVisit.UserOrGroupID = user.Id; shareVisit.AccessLevel = accessType; shareVisitList.add(shareVisit); } try{ Database.insert(shareVisitList); } catch(Exception e) { System.debug('Unexpected exception : ' + e); } } public static void updateVisitAccess(Visit visit, List<Id> oldUsers, List<Id> newUsers, String access) { if(visit==null) { return; } if(oldUsers!=null) { for(Id userId : oldUsers) { if(isUser(userId)) { deleteVisitAccess(visit, new User(id=userId)); } } } if(newUsers!=null) { for(Id userId : newUsers) { if(isUser(userId)) { insertVisitAccess(visit, userId, access); } } } } public static void updateVisitAccess(Visit oldVisit, Visit updatedVisit, String access) { //Comment this condition if for any update visit need to be shared if(oldVisit.VisitorId==updatedVisit.VisitorId) { return; } updateVisitAccess(oldVisit, oldVisit!=null?new List<Id>{oldVisit.VisitorId}:new List<Id>(), updatedVisit!=null?new List<Id>{updatedVisit.VisitorId}:new List<Id>(), access); } //remove user from oldVisit if user does not have any more access to oldVisit, and link user to newVisit public static void updateVisitAccess(Visit oldVisit, Visit newVisit, List<User> users, String access) { if(users==null || users.isEmpty()) { return; } if(access==null||!accessLevels.contains(access)) { access='edit'; } for(User user : users) { if(oldVisit!=null) deleteVisitAccess(oldVisit, user); if(newVisit!=null) insertVisitAccess(newVisit, user, access); } } //remove user from oldVisit if user does not have any more access to oldVisit, and link user to newVisit public static void updateVisitAccess(Visit oldVisit, Visit newVisit, Id objectId, String access) { if(isUser(objectId)) { updateVisitAccess(oldVisit, newVisit, new List<User>{new User(id=objectId)}, access); } } public static void deleteVisitAccess(Visit visit, List<User> users) { List<VisitShare> visitShareList = new List<VisitShare>(); for(User user : users) { if(isUserLinkedToVisit(user, visit)) continue; List<VisitShare> visitShare = [select Id from VisitShare where ParentId = :visit.Id and UserOrGroupID = :user.Id and RowCause='Manual']; if(!visitShare.isEmpty()) { visitShareList.add(visitShare.get(0)); } } delete visitShareList; } public static void deleteVisitAccess(Visit visit, User user) { deleteVisitAccess(visit, new List<User>{user}); } public static void deleteVisitAccess(Visit visit, Id objectId) { if(isUser(objectId)) { deleteVisitAccess(visit, new User(id=objectId)); } } public static Boolean isUser(Id objId) { if(objId==null) return false; List<User> users = [select Id from User where Id = :objId]; return !users.isEmpty(); } public static Boolean isUser(Object obj) { if(obj==null) return false; try { User user = (User)obj; } catch(TypeException e) { return false; } return true; } public static Boolean isUserLinkedToVisit(User user, Visit visit) { List<Visit> visits = [select Id from Visit where VisitorId = :user.Id and Id=:visit.Id]; List<Visitor> visitors = [select Id from Visitor where AssigneeId = :user.Id and VisitId=:visit.Id]; return !visits.isEmpty() || !visitors.isEmpty(); } } - Select File | Save.
-
Create the visit trigger.
- Select File | New | Apex Trigger.
- For the trigger name, enter VisitTrigger, and select Visit from the sObject picklist.
-
Delete the auto-generated content and paste the following sample.
trigger VisitTrigger on Visit (after insert, after update) { List<VisitShare> visitShares = new List<VisitShare>(); for(Visit visit : trigger.new) { if(trigger.isUpdate) { Visit oldVisit = trigger.oldMap.get(visit.Id); VisitAccess.updateVisitAccess(oldVisit, visit, 'edit'); } if(trigger.isInsert) { VisitAccess.insertVisitAccess(visit, visit.VisitorId, 'edit'); } } } - Select File | Save.
-
Create the visitor trigger.
- Select File | New | Apex Trigger.
- For the trigger name, enter VisitorTrigger, and select Visitor from the sObject picklist.
-
Delete the auto-generated content and paste the following sample.
trigger VisitorTrigger on Visitor (after insert, after update, after delete) { if(trigger.isInsert) { for(Visitor visitor : trigger.new) { VisitAccess.insertVisitAccess(new Visit(id=visitor.VisitId), visitor.AssigneeId, 'edit'); } } if(trigger.isUpdate) { for(Visitor visitor : trigger.new) { Visitor oldVisitor = trigger.oldMap.get(visitor.Id); VisitAccess.updateVisitAccess(new Visit(id=oldVisitor.VisitId), new Visit(id=visitor.VisitId), visitor.AssigneeId, 'edit'); } } if(trigger.isDelete) { for(Visitor visitor : trigger.old) { VisitAccess.deleteVisitAccess(new Visit(id=visitor.VisitId), visitor.AssigneeId); } } } - Select File | Save.
Now, sales reps can see only the visits they’re assigned to. -
Create the
ProductItemAccessutility class.- Select File | New | Apex Class.
- For the Apex class name, enter ProductItemAccess.
-
Delete the auto-generated content and paste the following sample.
public class ProductItemAccess { public static void insertAccess(List<ProductItem> productItems, List<Id> users, String access) { if(productItems==null || productItems.isEmpty() || users==null || users.isEmpty()) { return; } productItems = getProductItemsWithId(productItems); List<ProductItemShare> shareList = new List<ProductItemShare>(); for(Id user: users) { if(user==null) continue; for(ProductItem item : productItems) { ProductItemShare share = New ProductItemShare(); share.ParentId=item.Id; share.UserOrGroupID = user; share.AccessLevel = access; shareList.add(share); } } try{ Database.insert(shareList); } catch (Exception e) { System.debug(e); } } public static void deleteAccess(List<ProductItem> productItems, List<Id> users) { List<ProductItemShare> shareList = new List<ProductItemShare>(); for(Id userId : users) { for(ProductItem productItem : productItems) { List<ProductItemShare> shares = [select Id from ProductItemShare where ParentId = :productItem.Id and UserOrGroupID = :userId and RowCause='Manual']; if(!shares.isEmpty()) { shareList.addAll(shares); } } } delete shareList; } public static List<ProductItem> getProductItems(ProductFulfillmentLocation fulfillLocation) { return [select Id from ProductItem where Product2Id=:fulfillLocation.ProductId and LocationId=:fulfillLocation.FulfillmentLocationId]; } private static List<ProductItem> getProductItemsWithId(List<ProductItem> productItems) { List<ProductItem> productItemsWithId = new List<ProductItem>(); for(ProductItem item : productItems) { if(item==null) continue; if(item.id==null) { List<ProductItem> itemList = [select Id from ProductItem where Product2Id=:item.Product2Id and LocationId=:item.locationId]; productItemsWithId.addAll(itemList); } } return productItemsWithId; } } - Select File | Save.
-
Create the
ProductFulfillmentLocationAccessutility class.- Select File | New | Apex Class.
- For the Apex class name, enter ProductFulfillmentLocationAccess.
-
Delete the auto-generated content and paste the following sample.
public class ProductFulfillmentLocationAccess { static Set<String> accessLevels = new Set<String>{'read', 'edit'}; /** * Gives access to users on all product fulfillment locations */ public static void insertAccessToAllLocations(ProductFulfillmentLocation locationToInsert, String accessType) { List<ProductFulfillmentLocation> fulfillLocations = [select Id, ProductId, FulfillmentLocationId from ProductFulfillmentLocation]; insertAccess(fulfillLocations, getAllResponsibleUsers(), accessType); insertProductItemAccess(new List<ProductFulfillmentLocation>{locationToInsert}, new List<Id>{locationToInsert.UserId}, accessType); } public static void insertAccess(List<ProductFulfillmentLocation> fulfillLocations, List<Id> users, String accessType) { if(fulfillLocations==null || fulfillLocations.isEmpty() || users==null || users.isEmpty()) { return; } List<ProductFulfillmentLocationShare> shareList = new List<ProductFulfillmentLocationShare>(); for(Id user: users) { if(user==null) continue; for(ProductFulfillmentLocation location : fulfillLocations) { if(location==null || location.Id==null) continue; ProductFulfillmentLocationShare share = New ProductFulfillmentLocationShare(); share.ParentId=location.Id; share.UserOrGroupID = user; share.AccessLevel = accessType; shareList.add(share); } } try{ Database.insert(shareList); } catch (Exception e) { System.debug(e); } } public static void updateAccess(ProductFulfillmentLocation oldLocation, ProductFulfillmentLocation updatedLocation, String access) { deleteAccess(oldLocation); insertAccessToAllLocations(updatedLocation, access); } public static void deleteAccess(List<Id> users) { List<ProductFulfillmentLocationShare> shareList = new List<ProductFulfillmentLocationShare>(); for(Id userId : users) { if(isUserLinkedTofulfillLocation(userId)) continue; List<ProductFulfillmentLocationShare> shares = [select Id from ProductFulfillmentLocationShare where UserOrGroupID = :userId and RowCause='Manual']; if(!shares.isEmpty()) { shareList.addAll(shares); } } delete shareList; } public static void deleteAccess(ProductFulfillmentLocation fulfillLocation) { deleteAccess(new List<Id>{fulfillLocation.UserId}); deleteProductItemAccess(fulfillLocation); } public static Boolean isUserLinkedTofulfillLocation(Id userId) { List<ProductFulfillmentLocation> fulfillLocations = [select Id from ProductFulfillmentLocation where UserId = :userId]; return !fulfillLocations.isEmpty(); } public static void deleteProductItemAccess(ProductFulfillmentLocation fulfillLocation) { ProductItemAccess.deleteAccess(ProductItemAccess.getProductItems(fulfillLocation), new List<id>{fulfillLocation.UserId}); } public static void insertProductItemAccess(List<ProductFulfillmentLocation> fulfillLocations, List<Id> users, String access) { List<ProductItem> productItems = new List<ProductItem>(); for(ProductFulfillmentLocation location : fulfillLocations) { productItems.add(new ProductItem(Product2Id=location.ProductId, LocationId=location.FulfillmentLocationId)); } ProductItemAccess.insertAccess(productItems, users, access); } public static List<Id> getAllResponsibleUsers() { List<Id> users = new List<Id>(); List<ProductFulfillmentLocation> fulfillLocations = [select UserId from ProductFulfillmentLocation]; for(ProductFulfillmentLocation location : fulfillLocations) { users.add(location.UserId); } return users; } } - Select File | Save.
Now sales reps can see only the inventories they’re responsible for.