---
schema_version: "1"
id: f1c6eb452d417ca04b1fde21d33a781d56a94ae08f5a48f88e27193c6626980f
title: Sample Apex Trigger for Visit and Inventory Access
collection: admin
version: current
locale: en-us
portal_url: https://docs.salesforce.com/admin/current/en-us/ind/264-0-0/admin_intelligent_sales_apex.md
canonical_url: https://help.salesforce.com/s/articleView?id=ind.admin_intelligent_sales_apex.htm&release=264.0.0&type=5
source_site: help.salesforce.com
content_type: documentation
content_hash: cec3885f899866f27aaddb560b949b33d8c701fc56fed067664b6430e871df2c
description: 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.
products:
  - Life Sciences
release: "264"
---
# Sample Apex Trigger for Visit and Inventory Access

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

<table class="slds-table slds-table_bordered slds-max-medium-table_stacked slds-m-bottom_small edition">
        <colgroup>
          <col>
        </colgroup>
        <tbody>
          <tr class="">
            <td class="slds-cell-wrap" style="vertical-align:top;">
              <p>Available in: Lightning Experience</p>
              <p style="margin-bottom:0;">Available in: <strong>Enterprise</strong> and <strong>Unlimited</strong> Editions with Health Cloud
                or Life Sciences Cloud</p>
            </td>

          </tr>
        </tbody>
      </table> <table class="slds-table slds-table_bordered slds-max-medium-table_stacked slds-m-bottom_small permission">
        <colgroup>
          <col style="width:50%">
          <col style="width:50%">
        </colgroup>
        <thead class="slds-text-title_caps ">
          <tr class="">
            <th scope="colgroup" class="slds-cell-wrap" colspan="2" style="text-align:center;vertical-align:top;" id="d185858e66">User
              Permissions Needed</th>
          </tr>
        </thead>
        <tbody>
          <tr class="">
            <td data-label="User Permissions Needed" class="slds-cell-wrap" style="vertical-align:top;" headers="d185858e66 ">To define, edit, delete, set security, and set version settings
              for Apex classes:</td>

            <td class="slds-cell-wrap" style="vertical-align:top;" headers="d185858e66 ">Author Apex</td>

          </tr>
          <tr class="">
            <td data-label="User Permissions Needed" class="slds-cell-wrap" style="vertical-align:top;" headers="d185858e66 ">To run Apex tests:</td>

            <td class="slds-cell-wrap" style="vertical-align:top;" headers="d185858e66 ">View Setup and Configuration</td>

          </tr>
        </tbody>
      </table>

![Important](https://sf-zdocs-cdn-prod.zoominsoftware.com/tdta-ind-life_sciences-264-0-0-production-enus/ebdafac5-c5fe-47a7-ac14-81533ab4e08f/images/icon_important.png)

Important The sample code Salesforce provides in this Help article for Apex Triggers and Apex Classes is: (1) made available solely as an example for Customers' reference purposes; and (2) is a Non-SFDC Application under any Main Services Agreement between a Customer and Salesforce. Customers can either choose to use this sample code as provided, or write their own code as appropriate for their own implementation of Salesforce's Services. This sample code is made available "AS-IS" and Salesforce makes no warranty of any kind regarding this sample code (whether express, implied, statutory or otherwise).

To set up Apex triggers, you must create a few utility classes first.

1. Click **Setup** and select **Developer Console**.
2. Create the `VisitAccess` utility class.
    1. Select **File** | **New** | **Apex Class**.
    2. For the Apex class name, enter VisitAccess.
    3. 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();
            }
        }
        ```
    4. Select **File** | **Save**.
3. Create the visit trigger.
    1. Select **File** | **New** | **Apex Trigger**.
    2. For the trigger name, enter VisitTrigger, and select **Visit** from the sObject picklist.
    3. 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');
                }
            }
        }
        ```
    4. Select **File** | **Save**.
4. Create the visitor trigger.
    
    1. Select **File** | **New** | **Apex Trigger**.
    2. For the trigger name, enter VisitorTrigger, and select **Visitor** from the sObject picklist.
    3. 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);
                }
            }
        }
        ```
    4. Select **File** | **Save**.
    
    Now, sales reps can see only the visits they’re assigned to.
5. Create the `ProductItemAccess` utility class.
    1. Select **File** | **New** | **Apex Class**.
    2. For the Apex class name, enter ProductItemAccess.
    3. 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;
            }
        }
        ```
    4. Select **File** | **Save**.
6. Create the `ProductFulfillmentLocationAccess` utility class.
    
    1. Select **File** | **New** | **Apex Class**.
    2. For the Apex class name, enter ProductFulfillmentLocationAccess.
    3. 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;
            }
        }
        ```
    4. Select **File** | **Save**.
    
    Now sales reps can see only the inventories they’re responsible for.