Name

global.AccountsCacheUtil

Description

Helper functions for caching accounts that login user has access in private cache

Script

var AccountsCacheUtil = Class.create();
AccountsCacheUtil.prototype = {
  initialize: function() {},

  /*
   * Initialize cache
   */
  initPrivateCache: function(name) {
      if (!name)
          return;

      if (GlideCacheManager.get(name, "_created_") === null) {
          GlideCacheManager.addPrivateCacheable(name);
          GlideCacheManager.put(name, "_created_", new GlideDateTime().getNumericValue());
      }
  },

  /*
   * Partner accounts having relationship with more than max_partner_account_rel_limit of customer accounts
   * max_partner_account_rel_limit is configurable as per customer requirement.
   */
  getLargeAccountRelPartners: function() {
  	var max_account_rel_limit = parseInt(GlideProperties.get('max_partner_account_rel_limit', '500'));

      var partners = [];
      var ga = new GlideAggregate("account_relationship");
      ga.addEncodedQuery("relationship_label=Is Partner Of^from_company!=NULL^to_company!=NULL");
      ga.addAggregate("COUNT", "to_company");
      ga.groupBy("from_company");
      ga.addHaving('COUNT', '>', max_account_rel_limit);
      ga.orderByAggregate('COUNT', 'to_company');
      ga.query();

      while (ga.next()) {
          if (ga.getAggregate("COUNT", 'to_company') > max_account_rel_limit) {
              partners.push(ga.getValue('from_company'));
          }
      }
      return partners;
  },

  /*
   * Check if the account that the user belongs to exists in LARGE_PARTNER_CACHE
   */
  isMyAccountALargePartnerAccount: function() {
      this.initPrivateCache('LARGE_PARTNER_ACCOUNTS');
      var largeAccounts = [];
      largeAccounts = GlideCacheManager.get('LARGE_PARTNER_ACCOUNTS', 'large_partner_accounts');
      if (gs.nil(largeAccounts) || largeAccounts == 'NIL') {
          largeAccounts = this.getLargeAccountRelPartners();
          largeAccounts = (largeAccounts.length > 0) ? largeAccounts.join(',') : 'NIL';
          GlideCacheManager.put("LARGE_PARTNER_ACCOUNTS", 'large_partner_accounts', largeAccounts);
      }

      var userAccount = gs.getUser().getCompanyID() + "";
      return (largeAccounts.includes(userAccount));
  },

  /*
   * Check if the account has more than max_sub_accounts_limit of children accounts in the hierarchy
   * max_sub_accounts_limit is configurable as per customer requirement.
   */
  isLargeParentAccount: function(userAccount) {
      var max_sub_accounts_limit = parseInt(GlideProperties.get('max_sub_accounts_limit', '500'));

      var account_path = new global.CSQueryBRUtil().getAccountPath(userAccount);
      var ga = new GlideAggregate('customer_account');
      ga.addEncodedQuery("account_pathSTARTSWITH" + account_path);
      ga.addAggregate('COUNT');
      ga.query();

      if (ga.next() && ga.getAggregate('COUNT') > max_sub_accounts_limit) {
          return true;
      }
      return false;
  },

  /*
   * Cache LARGE_PARENT_ACCOUNTS to improve performance
   */
  isMyAccountALargeParentAccount: function() {
      this.initPrivateCache('LARGE_PARENT_ACCOUNTS');
      var largeAccounts = j2js(GlideCacheManager.get('LARGE_PARENT_ACCOUNTS', 'large_parent_accounts'));
      var userAccount = gs.getUser().getCompanyID() + "";

      if (gs.nil(largeAccounts))
          largeAccounts = [];

      if (!gs.nil(largeAccounts) && largeAccounts.includes(userAccount)) {
          return true;
      }

      if (this.isLargeParentAccount(userAccount)) {
          if (!gs.nil(largeAccounts) && largeAccounts.length > 0) {
              largeAccounts = largeAccounts.split(',');
          }
          largeAccounts.push(userAccount);
          largeAccounts = (largeAccounts.length > 0) ? largeAccounts.join(',') : 'NIL';
          GlideCacheManager.put("LARGE_PARENT_ACCOUNTS", 'large_parent_accounts', largeAccounts);
          return true;
      }

      return false;
  },

  isPrivateCachingEnabledForAccounts: function() {
      return (gs.getProperty("use_accounts_private_cache") == 'true');
  },

  /*
   * Accounts that login user has access need to be cached in a private cache instead of session cache if,
   * 1. Role - Partner and Partner account is having relationship with more than max_account_rel_limit of customer accounts
   * 2. Role - customer_admin and the account has more than max_sub_accounts_limit in the account hierarchy
   */
  useAccountsPrivateCache: function(table) {
      if (gs.hasRole('sn_customerservice.partner') && (table != 'sn_customerservice_case' && table != 'csm_order_case' && table != 'wm_order') && this.isMyAccountALargePartnerAccount()) {
          return true;
      }

      if (gs.hasRole('sn_customerservice.customer_admin') && this.isMyAccountALargeParentAccount()) {
          return true;
      }

      return false;
  },

  isInPrivateCache: function(cacheName, key) {
      var accounts = GlideCacheManager.get(cacheName, key);
      return !gs.nil(accounts);
  },

  isInSessionCache: function(key) {
      var data = gs.getSession().getClientData(key);
      return !gs.nil(data);
  },

  /*
    Flush MY_ACCESSIBLE_ACCOUNTS and LARGE_PARENT_ACCOUNTS private cache entries, so that they can be rebuilt.
    Example hierarchy: A->B->C->D->500 children accounts. Covered usecases:
    
    UseCase 1: Insert a child account with parent as D. Flush the MY_ACCESSIBLE_ACCOUNTS cache for immediate parent D 
    and C, B, A (parent accounts of D).
    
    UseCase 2: Delete a child account of D. Flush the MY_ACCESSIBLE_ACCOUNTS cache for the deleted account, 
    immediate parent D and C, B, A (D's parent accounts in the hierarchy)
    
    UseCase 3: Update an account where old parent is empty and new parent is D.
    Flush the MY_ACCESSIBLE_ACCOUNTS cache for new parent D and C, B, A (parent accounts in the hierarchy of D)
    
    UseCase 4: Update an account old parent is D and new parent is empty
    Flush the MY_ACCESSIBLE_ACCOUNTS cache for old parent D and B, C, A (D's parent accounts in the hierarchy)
    
    UseCase 5: Update an account old parent is D and new parent is E.
    Flush the MY_ACCESSIBLE_ACCOUNTS cache for current account, old parent D and B, C, A (parent accounts of D)
    Also Flush the MY_ACCESSIBLE_ACCOUNTS cache for new parent E and it's parent accounts in the hierarchy
    
    Always Flush LARGE_PARENT_ACCOUNTS cache. Improvise the code to conditionally flush this cache entry.
  */
  
  flushLargeParentAccountsCache: function(current, previous) {
      if (!gs.nil(current.account_parent)) {
          this.flushCacheEntry(current.account_parent, current.account_path);
          this.flushCacheEntry(current.account_parent, current.account_path, "child_accounts_", global.CSMBaseConstants.CACHE_CATALOG_CHILD_ACCOUNTS);
      }

      if (current.operation() == "update" && !gs.nil(previous)) {
          this.flushCacheEntry(previous.account_parent, previous.account_path);
          this.flushCacheEntry(previous.account_parent, previous.account_path, "child_accounts_", global.CSMBaseConstants.CACHE_CATALOG_CHILD_ACCOUNTS);
      }
  },

  flushCacheEntry: function(parent, path, keyPrefix, cacheName) {
      if (gs.nil(keyPrefix)) {
          keyPrefix = "my_accessible_accounts_";
      }
      var key = keyPrefix + parent;
      if (gs.nil(cacheName)) {
          cacheName = "MY_ACCESSIBLE_ACCOUNTS";
      }
      var accounts = GlideCacheManager.get(cacheName, key);
      if (!gs.nil(accounts)) {

          // Get all the parent accounts in the hierarchy
          var parentAccounts = [];
          var accountPaths = path.split("/");
          var acctGr = new GlideRecord("customer_account");
          acctGr.addQuery("account_code", "IN", accountPaths.toString());
          acctGr.query();
          while (acctGr.next()) {
              parentAccounts.push(acctGr.getUniqueValue());
          }

          parentAccounts.forEach(function(account) {
              gs.log("Flushing " + cacheName + " cache entry for account " + account);
              key = keyPrefix + account;
              GlideCacheManager.prefixFlush(cacheName, key);
          });

          // Improvise the code to conditionally flush this cache entry
          if (cacheName == "MY_ACCESSIBLE_ACCOUNTS")
              GlideCacheManager.flush('LARGE_PARENT_ACCOUNTS');
      }
  },

  // The private cacheName is different when Query rules are disabled
  flushLargePartnerAccountsCache: function(accountRel) {
   var cacheName = "ACCOUNTS_FROM_ACCOUNT_REL";
   var key = "accounts_from_account_rel_" + accountRel.from_company;

   if (!new global.CSMQueryRulesUtil().useQueryRules()) {
       cacheName = "MY_ACCESSIBLE_ACCOUNTS";
       key = "my_accessible_accounts_" + accountRel.from_company;
   }

   var myAccessibleAccounts = GlideCacheManager.get(cacheName, key);
   if (!gs.nil(myAccessibleAccounts)) {
       gs.log("Flushing cache entry for account " + accountRel.from_company);
       GlideCacheManager.prefixFlush(cacheName, key);
       GlideCacheManager.flush('LARGE_PARTNER_ACCOUNTS');
   }
  },

  type: 'AccountsCacheUtil'
};

Sys ID

f99f76c653ae0110d6a0ddeeff7b1239

Offical Documentation

Official Docs: