diff --git a/src/org/openbravo/mobile/core/login/MobileCoreLoginUtilsServlet.java b/src/org/openbravo/mobile/core/login/MobileCoreLoginUtilsServlet.java
index 7829ea5..335fd83 100644
--- a/src/org/openbravo/mobile/core/login/MobileCoreLoginUtilsServlet.java
+++ b/src/org/openbravo/mobile/core/login/MobileCoreLoginUtilsServlet.java
@@ -106,6 +106,7 @@ public class MobileCoreLoginUtilsServlet extends WebServiceAbstractServlet {
           result.put("contextInfo", Context.getContextInfo().get(0));
         }
 
+        result.put("isTestEnvironment", isTestEnvironment());
         result.put("format", getFormat());
         // in case of invalid origin then only support this for prerender and report back to the
         // client
@@ -142,6 +143,13 @@ public class MobileCoreLoginUtilsServlet extends WebServiceAbstractServlet {
     }
   }
 
+  private boolean isTestEnvironment() {
+    final String testEnvironmentStr = OBPropertiesProvider.getInstance()
+        .getOpenbravoProperties()
+        .getProperty("test.environment");
+    return testEnvironmentStr != null && "true".equals(testEnvironmentStr);
+  }
+
   @Override
   public void doPost(HttpServletRequest request, HttpServletResponse response)
       throws IOException, ServletException {
diff --git a/web-test/model/application-state/State.test.js b/web-test/model/application-state/State.test.js
index 5006c3a..593b934 100644
--- a/web-test/model/application-state/State.test.js
+++ b/web-test/model/application-state/State.test.js
@@ -34,7 +34,8 @@ describe('Global State endpoint', () => {
     persistence = {
       initialize: jest.fn(),
       getState: jest.fn(),
-      dispatch: jest.fn()
+      dispatch: jest.fn(),
+      stateStorePersistor: { debouncedFlush: jest.fn() }
     };
 
     persistence.getState.mockReturnValue({
diff --git a/web/org.openbravo.mobile.core/app/model/application-state/State.js b/web/org.openbravo.mobile.core/app/model/application-state/State.js
index 1bb78ba..d69e8e5 100644
--- a/web/org.openbravo.mobile.core/app/model/application-state/State.js
+++ b/web/org.openbravo.mobile.core/app/model/application-state/State.js
@@ -77,9 +77,22 @@
     actionPayload
   ) => {
     try {
+      const previousBackendMsgIds = getBackendMessageIds(
+        persistence.getState()
+      );
       persistence.dispatch(model, action, actionPayload, {
         globalState: persistence.getState()
       });
+      if (
+        anyNewBackendMessage(
+          previousBackendMsgIds,
+          getBackendMessageIds(persistence.getState())
+        )
+      ) {
+        persistence.stateStorePersistor.flush();
+      } else if (shouldTriggerDebouncedPersistence(persistence, model)) {
+        persistence.stateStorePersistor.debouncedFlush();
+      }
     } catch (error) {
       await executeAllActionPreparationRollbacks(
         OB.App.StateAPI[model][action],
@@ -91,6 +104,27 @@
     }
   };
 
+  function getBackendMessageIds(state) {
+    if (!state || !state.Messages) {
+      return [];
+    }
+    return state.Messages.filter(msg => msg.type === 'backend')
+      .filter(msg => msg.modelName !== 'OBMOBC_TerminalLog')
+      .map(msg => msg.id);
+  }
+
+  function shouldTriggerDebouncedPersistence(persistence, modelName) {
+    const model = OB.App.StateAPI[modelName];
+
+    return (
+      modelName === 'Global' || (model.isPersisted && model.triggerPersistence)
+    );
+  }
+
+  function anyNewBackendMessage(previous = [], current = []) {
+    return current.some(msg => !previous.includes(msg));
+  }
+
   const getStatePortion = (state, model) => {
     if (model !== 'Global') {
       return state[model];
diff --git a/web/org.openbravo.mobile.core/app/model/application-state/StateAPI.js b/web/org.openbravo.mobile.core/app/model/application-state/StateAPI.js
index c28cca6..cdc61ce 100644
--- a/web/org.openbravo.mobile.core/app/model/application-state/StateAPI.js
+++ b/web/org.openbravo.mobile.core/app/model/application-state/StateAPI.js
@@ -40,7 +40,8 @@
     'options',
     'bbModel',
     'isUndoable',
-    'isPersisted'
+    'isPersisted',
+    'triggerPersistence'
   ];
 
   const modelRegistry = {
@@ -247,6 +248,8 @@
      * @param {object} options - An optional object with additional options, which may be:
      *                           * isUndoable (boolean): indicates whether the model supports undoing actions
      *                           * isPersisted (boolean): indicates whether the model is persisted in the local database or not
+     *                           * triggerPersistence (boolean): indicates whether a model update should trigger a debounced (200ms) state persistence.
+     *                                      If false, the change will be persisted when another model udpate triggers the persistence or when the default state throttling (60s) is triggered
      *
      * @throws {Error} - When the model already exists
      */
@@ -259,6 +262,7 @@
         initialState: lodash.cloneDeep(initialState),
         isUndoable: options.isUndoable || false,
         isPersisted: options.isPersisted !== false,
+        triggerPersistence: options.triggerPersistence !== false,
         ...modelRegistry,
         ...modelHookRegistry,
         ...utilitiesRegistry
diff --git a/web/org.openbravo.mobile.core/app/model/application-state/StatePersistence.js b/web/org.openbravo.mobile.core/app/model/application-state/StatePersistence.js
index 600c4e7..9408c85 100644
--- a/web/org.openbravo.mobile.core/app/model/application-state/StatePersistence.js
+++ b/web/org.openbravo.mobile.core/app/model/application-state/StatePersistence.js
@@ -135,7 +135,7 @@
         {
           key: 'root',
           storage: localforage,
-          throttle: 100,
+          throttle: 60000,
           blacklist: blackList
         },
         rootReducer
@@ -154,6 +154,22 @@
       // The stateStorePersistor provides operations over the state backup such as forcing flush, removing...
       this.stateStorePersistor = ReduxPersist.persistStore(this.stateStore);
 
+      const { flush } = this.stateStorePersistor;
+      // function that can be attached to a window unload event to force a state flush
+      this.stateStorePersistor.persistBeforeUnload = event => {
+        flush();
+        event.preventDefault();
+        // eslint-disable-next-line no-param-reassign
+        event.returnValue = '';
+      };
+      // to prevent persisting too often in disk (potentially creating a performance problem),
+      // a debounced version of the persistence flush is provided
+      const fallbackFunction = () => {};
+      this.stateStorePersistor.debouncedFlush = lodash.debounce(
+        this.stateStorePersistor.flush || fallbackFunction,
+        200
+      );
+
       // Ensures store persistence to be reset when localstorage has been cleared up
       if (!OB.UTIL.localStorage.getItem('stateIsConsistentWithLocalStorage')) {
         this.stateStorePersistor.purge();
diff --git a/web/org.openbravo.mobile.core/app/model/application-state/StatePersistence.js.orig b/web/org.openbravo.mobile.core/app/model/application-state/StatePersistence.js.orig
index 42dea94..600c4e7 100644
--- a/web/org.openbravo.mobile.core/app/model/application-state/StatePersistence.js.orig
+++ b/web/org.openbravo.mobile.core/app/model/application-state/StatePersistence.js.orig
@@ -122,7 +122,7 @@
       const rootReducer = this.createRootReducer(globalActionsReducer);
 
       localforage.config({
-        driver: localforage.INDEXEDDB,
+        driver: localforage.LOCALSTORAGE,
         name: `${OB.App.TerminalProperty.get('localDB').name}_state`,
         storeName: 'State'
       });
@@ -135,7 +135,7 @@
         {
           key: 'root',
           storage: localforage,
-          throttle: 10,
+          throttle: 100,
           blacklist: blackList
         },
         rootReducer
diff --git a/web/org.openbravo.mobile.core/app/model/business-object/remote-server/RemoteServer.js b/web/org.openbravo.mobile.core/app/model/business-object/remote-server/RemoteServer.js
index 5721424..e8347d3 100644
--- a/web/org.openbravo.mobile.core/app/model/business-object/remote-server/RemoteServer.js
+++ b/web/org.openbravo.mobile.core/app/model/business-object/remote-server/RemoteServer.js
@@ -1,10 +1,15 @@
 /*
  ************************************************************************************
- * Copyright (C) 2021 Openbravo S.L.U.
+ * Copyright (C) 2021-2023 Openbravo S.L.U.
  * Licensed under the Openbravo Commercial License version 1.0
  * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html
  * or in the legal folder of this module distribution.
  ************************************************************************************
  */
 
-OB.App.StateAPI.registerModel('RemoteServer', {});
+OB.App.StateAPI.registerModel(
+  'RemoteServer',
+  {},
+  // no need to persist changes on this models immediately, it can wait until default persistence throttling (60s) takes place
+  { triggerPersistence: false }
+);
diff --git a/web/org.openbravo.mobile.core/app/model/business-object/terminal-log/TerminalLog.js b/web/org.openbravo.mobile.core/app/model/business-object/terminal-log/TerminalLog.js
index 1343c61..c1af910 100644
--- a/web/org.openbravo.mobile.core/app/model/business-object/terminal-log/TerminalLog.js
+++ b/web/org.openbravo.mobile.core/app/model/business-object/terminal-log/TerminalLog.js
@@ -1,6 +1,6 @@
 /*
  ************************************************************************************
- * Copyright (C) 2019-2020 Openbravo S.L.U.
+ * Copyright (C) 2019-2023 Openbravo S.L.U.
  * Licensed under the Openbravo Commercial License version 1.0
  * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html
  * or in the legal folder of this module distribution.
@@ -18,10 +18,15 @@
    * events: array containing one item per log line
    * eventsMaximumNumber: maximun number of log lines per message, rest of log lines are ignored.
    */
-  OB.App.StateAPI.registerModel('TerminalLog', {
-    context: 'refresh(F5)',
-    contextPopup: '',
-    events: [],
-    eventsMaximumNumber: 10000
-  });
+  OB.App.StateAPI.registerModel(
+    'TerminalLog',
+    {
+      context: 'refresh(F5)',
+      contextPopup: '',
+      events: [],
+      eventsMaximumNumber: 10000
+    },
+    // no need to persist changes on this models immediately, it can wait until default persistence throttling (60s) takes place
+    { triggerPersistence: false }
+  );
 })();
diff --git a/web/org.openbravo.mobile.core/source/model/ob-terminal-model.js b/web/org.openbravo.mobile.core/source/model/ob-terminal-model.js
index e3497a1..0c1466d 100644
--- a/web/org.openbravo.mobile.core/source/model/ob-terminal-model.js
+++ b/web/org.openbravo.mobile.core/source/model/ob-terminal-model.js
@@ -2028,6 +2028,7 @@ OB.Model.Terminal = Backbone.Model.extend({
             return;
           }
           me.trigger('initializedCommonComponents');
+
           me.preLoadContext(function() {
             if (
               !inResponse.contextInfo ||
@@ -2037,6 +2038,13 @@ OB.Model.Terminal = Backbone.Model.extend({
               OB.MobileApp.model.navigate('login');
               return;
             }
+
+            window.OB.UTIL.localStorage.setItem(
+              'isTestEnvironment',
+              inResponse.isTestEnvironment
+            );
+            // when logging in or after refreshing the tab, force a state persistence before closing/refreshing the browser
+            me.addPersistOnRefreshListener();
             OB.MobileApp.model.triggerOnLine();
             OB.info('Set isLoggingIn true');
             OB.MobileApp.model.set('isLoggingIn', true);
@@ -3002,6 +3010,8 @@ OB.Model.Terminal = Backbone.Model.extend({
       return;
     }
 
+    // when logging in or after refreshing the tab, force a state persistence before closing/refreshing the browser
+    this.addPersistOnRefreshListener();
     OB.MobileApp.model.set('windowRegistered', undefined);
     OB.MobileApp.model.set('loggedOffline', true);
     OB.MobileApp.model.set('datasourceLoadFailed', false);
@@ -3046,6 +3056,28 @@ OB.Model.Terminal = Backbone.Model.extend({
     OB.debug('next process: none. set your application start point here');
   },
 
+  addPersistOnRefreshListener: function() {
+    // do not do it in test environments as Selenium is not compatible with this feature
+    if (window.OB.UTIL.localStorage.getItem('isTestEnvironment') === 'true') {
+      return;
+    }
+    window.addEventListener(
+      'beforeunload',
+      OB.App.State.persistence.stateStorePersistor.persistBeforeUnload
+    );
+  },
+
+  removePersistOnRefreshListener: function() {
+    // do not do it in test environments as Selenium is not compatible with this feature
+    if (window.OB.UTIL.localStorage.getItem('isTestEnvironment') === 'true') {
+      return;
+    }
+    window.removeEventListener(
+      'beforeunload',
+      OB.App.State.persistence.stateStorePersistor.persistBeforeUnload
+    );
+  },
+
   login: function(user, password, mode, command) {
     OB.info('isLoggingIn ' + this.get('isLoggingIn'));
     if (this.get('isLoggingIn') === true) {
@@ -3320,6 +3352,8 @@ OB.Model.Terminal = Backbone.Model.extend({
     }
 
     this.preLogoutActions(function() {
+      // when logged out, no need to force a state persistence before closing/refreshing the browser
+      me.removePersistOnRefreshListener();
       OB.App.SynchronizationBuffer.internalFlush()
         .then(() => {
           return OB.App.State.persistence.stateStorePersistor.flush();
diff --git a/web/org.openbravo.mobile.core/source/model/ob-terminal-model.js.orig b/web/org.openbravo.mobile.core/source/model/ob-terminal-model.js.orig
deleted file mode 100644
index 8471710..0000000
--- a/web/org.openbravo.mobile.core/source/model/ob-terminal-model.js.orig
+++ /dev/null
@@ -1,3473 +0,0 @@
-/*
- ************************************************************************************
- * Copyright (C) 2012-2021 Openbravo S.L.U.
- * Licensed under the Openbravo Commercial License version 1.0
- * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html
- * or in the legal folder of this module distribution.
- ************************************************************************************
- */
-
-/* global enyo, ServiceWorkerUtil, CryptoJS */
-
-OB.Model = window.OB.Model || {};
-OB.MobileApp = OB.MobileApp || {};
-OB.Data = OB.Data || {};
-
-// used for test purposes to keep track that sync dialog was shown
-OB.Data.showSynchronizedDialogChangeTime = 0;
-
-OB.MobileApp.windowRegistry = new (Backbone.Model.extend({
-  registeredWindows: [],
-
-  registerWindow: function(window) {
-    if (
-      OB &&
-      OB.MobileApp &&
-      OB.MobileApp.model &&
-      OB.UTIL.isNullOrUndefined(OB.MobileApp.model.get('defaultWindow')) &&
-      window.defaultWindow
-    ) {
-      OB.MobileApp.model.set('defaultWindow', window.route);
-    } else if (window.defaultWindow) {
-      if (OB && OB.error) {
-        OB.warn('Default window ignored. ' + window.windowClass);
-      } else {
-        OB.warn('Default window ignored. ' + window.windowClass);
-      }
-    }
-    this.registeredWindows.push(window);
-  }
-}))();
-
-OB.MobileApp.actionsRegistry = new OB.Actions.Registry();
-OB.MobileApp.statesRegistry = new OB.State.Registry();
-
-OB.Model.Collection = Backbone.Collection.extend({
-  constructor: function(data) {
-    this.ds = data.ds;
-    Backbone.Collection.prototype.constructor.call(this);
-  },
-  inithandler: function(init) {
-    if (init) {
-      init.call(this);
-    }
-  },
-  exec: function(filter) {
-    var me = this;
-    if (this.ds) {
-      this.ds.exec(filter, function(data, info) {
-        var i;
-        me.reset();
-        me.trigger('info', info);
-        if (data.exception) {
-          OB.UTIL.showError(data.exception.message);
-        } else {
-          for (i in data) {
-            if (Object.prototype.hasOwnProperty.call(data, i)) {
-              me.add(data[i]);
-            }
-          }
-        }
-      });
-    }
-  }
-});
-
-// Terminal model.
-OB.Model.Terminal = Backbone.Model.extend({
-  defaults: {
-    terminal: null,
-    context: null,
-    permissions: null,
-    businesspartner: null,
-    location: null,
-    pricelist: null,
-    pricelistversion: null,
-    currency: null,
-    connectedToERP: null,
-    terminalLogContextPopUp: [],
-    loginUtilsUrl: '../../org.openbravo.mobile.core.loginutils',
-    loginUtilsParams: {},
-    supportsOffline: false,
-    loginHandlerUrl: '../../org.openbravo.mobile.core/LoginHandler',
-    applicationFormatUrl:
-      '../../org.openbravo.mobile.core/OBCLKER_Kernel/Application',
-    logConfiguration: {
-      deviceIdentifier: '',
-      logPropertiesExtension: []
-    },
-    windows: null,
-    appName: 'OBMOBC',
-    useBarcode: false,
-    useBarcodeLayout: null,
-    useEmbededBarcode: true,
-    profileOptions: {
-      showOrganization: true,
-      showWarehouse: true,
-      defaultProperties: {
-        role: null,
-        organization: null,
-        warehouse: null,
-        languagage: null
-      }
-    },
-    localDB: {
-      size: OB.UTIL.VersionManagement.current.mobileCore.WebSQLDatabase.size,
-      name: OB.UTIL.VersionManagement.current.mobileCore.WebSQLDatabase.name,
-      displayName:
-        OB.UTIL.VersionManagement.current.mobileCore.WebSQLDatabase.displayName
-    },
-    shouldExecuteBenchmark: false,
-    propertiesLoaders: [],
-    dataSyncModels: []
-  },
-
-  initialize: function() {
-    var me = this;
-
-    // expose terminal globally
-    window.OB.MobileApp = OB.MobileApp || {};
-    window.OB.MobileApp.model = this;
-
-    OB.UTIL.HookManager.executeHooks('OBMOBC_InitActions', {}, function(args) {
-      if (args && args.cancelOperation && args.cancelOperation === true) {
-        return;
-      } else {
-        me.initActions(function() {});
-      }
-    });
-
-    // attach objects to model
-    this.router = new OB.Model.RouterHelper(this);
-    this.windowRegistry = OB.MobileApp.windowRegistry;
-    OB.UTIL.VersionManagement.deprecated(
-      27349,
-      function() {
-        this.hookManager = OB.UTIL.HookManager;
-      },
-      function(deprecationMessage) {
-        this.hookManager = {
-          registerHook: function(qualifier, func) {
-            OB.warn(deprecationMessage + ". Hook: '" + qualifier + "'");
-            OB.UTIL.HookManager.registerHook(qualifier, func);
-          },
-          executeHooks: function(qualifier, args, callback) {
-            OB.warn(deprecationMessage + ". Hook: '" + qualifier + "'");
-            OB.UTIL.HookManager.executeHooks(qualifier, args, callback);
-          },
-          callbackExecutor: function(args, callback) {
-            OB.warn(deprecationMessage);
-            OB.UTIL.HookManager.callbackExecutor(args, callback);
-          }
-        };
-      },
-      this
-    );
-
-    // DEVELOPER: activate this to see all the events that are being fired by the backbone components of the terminal
-    // this.on('all', function(eventName, object, third) {
-    //   if (eventName.indexOf('change') >= 0) {
-    //     return;
-    //   }
-    //   var enyoName = object ? object.name : '';
-    //   OB.info('event fired: ' + eventName + ', ' + enyoName + ', ' + third);
-    // });
-    // model events
-    this.on('window:ready', this.renderContainerWindow); // When the active window is loaded, the window is rendered with the renderContainerWindow function
-    this.on('terminalInfoLoaded', function() {
-      OB.debug('next process: processPropertyLoaders');
-      OB.UTIL.localStorage.setItem(
-        'cacheAvailableForUser:' + OB.MobileApp.model.get('orgUserId'),
-        true
-      );
-      this.processPropertyLoaders();
-    });
-    this.on(
-      'propertiesLoadersReady',
-      function() {
-        OB.debug(
-          'next process: loadRegisteredWindows, renderMain, postLoginActions'
-        );
-
-        OB.UTIL.completeLoadingStep();
-        me.saveBrowserTabId();
-        // Now we can start synchronizing pending messages with the backend server
-        OB.App.RemoteServerController.getRemoteServer(
-          'BackendServer'
-        ).connectSynchronizationEndpoints();
-        var callbackAlreadyExecuted = false;
-
-        this.loadRegisteredWindows(function() {
-          if (!callbackAlreadyExecuted) {
-            callbackAlreadyExecuted = true;
-            me.renderMain();
-            me.postLoginActions();
-          }
-        });
-      },
-      this
-    );
-
-    // when the page has finished loading the components, load the root webpage
-    window.addEventListener(
-      'load',
-      function(e) {
-        OB.MobileApp.model.initializeGlobalState();
-        // verifying that all dataSyncModels have modelFunc defined
-        _.each(
-          OB.MobileApp.model.get('dataSyncModels'),
-          function(syncModel) {
-            if (syncModel && OB.UTIL.isNullOrUndefined(syncModel.modelFunc)) {
-              if (
-                syncModel.model &&
-                syncModel.model.prototype &&
-                syncModel.model.prototype.modelName
-              ) {
-                syncModel.modelFunc =
-                  'OB.Model.' + syncModel.model.prototype.modelName;
-              }
-            }
-          },
-          this
-        );
-        // explicitly setting pushState to false tries to ensure...
-        // that future default modes will not activate the pushState...
-        // breaking the POS navigation
-        // setTimeout to move the execution until all 'load' listeners have finished
-        setTimeout(function() {
-          Backbone.history.start({
-            root: '',
-            pushState: false
-          });
-        }, 0);
-      },
-      false
-    );
-
-    window.addEventListener('beforeunload', function(e) {
-      OB.MobileApp.model.reloadingApplication = true;
-    });
-  },
-
-  initializeGlobalState: function() {
-    const persistence = new OB.App.Class.StatePersistence();
-    window.OB.App.State = new OB.App.Class.State(persistence);
-
-    window.OB.App.PersistenceChangeListenerManager = new OB.App.Class.PersistenceChangeListenerManager(
-      persistence
-    );
-
-    OB.App.State.TerminalLog.setContext({ context: 'refresh(F5)' });
-
-    window.addEventListener('beforeunload', function(e) {
-      // Try to save the database before unload.
-      // It is missing the await, but in the 'beforeunload' it doesn't wait for any async code so is no diference to put it.
-      // Since doesn't wait, it doesn't waranty that will work in 100% of cases, but in many cases will have time to persist into disk
-      // Note that this code is an extra security mechanism appart of the continous persistence controled by a throttle
-      OB.App.State.persistence.stateStorePersistor.flush();
-    });
-
-    window.addEventListener(
-      'storage',
-      function(e) {
-        // Prevent state persistance when application is opened in another tab
-        // Event will be triggered only when localStorage values are changed in another tab
-        if (
-          e.key === OB.UTIL.localStorage.getAppName() + '.browserTabId' &&
-          e.oldValue !== e.newValue
-        ) {
-          OB.App.State.persistence.stateStorePersistor.pause();
-        }
-      },
-      false
-    );
-  },
-  /**
-   * Method to be called when there is an error while loading the application
-   * @param  {String}  caller   a string that identifies the process that failed
-   */
-  loadingErrorsActions: function(caller) {
-    // arguments check
-    OB.UTIL.Debug.execute(function() {
-      if (!caller) {
-        throw 'missing parameter: caller';
-      }
-    });
-
-    // remember that the loading has failed. used by the LogClient
-    OB.MobileApp.model.loadingErrorsActions.executed = true;
-
-    var link = 'NA';
-    try {
-      link = OB.UTIL.getStackLink(3);
-    } catch (ex) {
-      OB.error('executeSqlErrorHandler.getStackLink: ' + ex);
-    }
-    OB.error(
-      "loadingErrorsActions: '" +
-        caller +
-        "' failed while loading the application. line: " +
-        link
-    );
-  },
-
-  cleanTerminalData: function() {
-    _.each(
-      this.get('propertiesLoaders'),
-      function(curPropertiesToLoadProcess) {
-        _.each(
-          curPropertiesToLoadProcess.properties,
-          function(curProperty) {
-            this.set(curProperty, null);
-          },
-          this
-        );
-      },
-      this
-    );
-  },
-
-  returnToOnline: function() {
-    //DEVELOPERS: overwrite this function to perform actions when it happens
-    OB.info('The system has come back to online');
-  },
-
-  //DEVELOPER: This function allow us to execute some code to add properties to to terminal model. Each position of the array
-  // must identify the properties which are set and needs to define a loadFunction which will be executed to get the data.
-  // when the data is ready terminalModel.propertiesReady(properties) should be executed.
-  addPropertiesLoader: function(obj) {
-    this.get('propertiesLoaders').push(obj);
-    this.syncAllPropertiesLoaded = _.after(
-      this.get('propertiesLoaders').length,
-      this.allPropertiesLoaded
-    );
-  },
-
-  handlePropertiesLoader: function(
-    properties,
-    source,
-    params,
-    successCallback
-  ) {
-    function handleError() {
-      var msg =
-          OB.I18N.getLabel('OBMOBC_TerminalPropertiesErrorBody', [
-            properties.join(', ')
-          ]) + OB.I18N.getLabel('OBMOBC_LoadingErrorBody'),
-        isErrorPopupShown =
-          OB.MobileApp.view.$.confirmationContainer.getCurrentPopup() &&
-          OB.MobileApp.view.$.confirmationContainer
-            .getCurrentPopup()
-            .getShowing();
-      if (
-        OB.MobileApp.model.get('isLoggingIn') === true &&
-        !isErrorPopupShown
-      ) {
-        OB.UTIL.showConfirmation.display(
-          OB.I18N.getLabel('OBMOBC_TerminalPropertiesErrorHeader'),
-          msg,
-          [
-            {
-              label: OB.I18N.getLabel('OBMOBC_Reload'),
-              action: function() {
-                window.location.reload();
-              }
-            }
-          ],
-          {
-            onShowFunction: function(popup) {
-              OB.UTIL.localStorage.removeItem(
-                'cacheAvailableForUser:' + OB.MobileApp.model.get('orgUserId')
-              );
-              popup.$.headerCloseButton.hide();
-              OB.MobileApp.view.$.containerWindow.destroyComponents();
-            },
-            autoDismiss: false,
-            showLoading: true
-          }
-        );
-      }
-    }
-
-    new OB.DS.Request(source).exec(
-      params,
-      function(data) {
-        if (data.exception) {
-          handleError();
-        } else {
-          if (typeof successCallback === 'function') {
-            successCallback(data);
-          }
-        }
-      },
-      function(data) {
-        handleError();
-      }
-    );
-  },
-
-  propertiesReady: function(properties) {
-    OB.info("[sdrefresh] '" + properties + "' property loaded");
-    this.syncAllPropertiesLoaded();
-  },
-
-  processPropertyLoaders: function() {
-    OB.debug('next process: allPropertiesLoaded');
-    var termInfo,
-      msg,
-      key,
-      keysToSkip = ['dataSyncModels', 'connectedToERP'];
-    if (this.get('loggedOffline')) {
-      //Load from termInfo
-      if (this.usermodel.get('terminalinfo')) {
-        termInfo = JSON.parse(this.usermodel.get('terminalinfo'));
-        for (key in termInfo) {
-          if (
-            Object.prototype.hasOwnProperty.call(termInfo, key) &&
-            keysToSkip.indexOf(key) === -1
-          ) {
-            //If it is not in the keys to skip
-            this.set(key, termInfo[key]);
-          }
-        }
-        //overwrite loaded values which was stored into DB when system was online
-        this.set('loggedOffline', true);
-        this.set('connectedToERP', false);
-        //Funtions are not recoverd when obj is loaded from DB. Recover Them
-        this.set('logConfiguration', {
-          deviceIdentifier:
-            OB.UTIL.localStorage.getItem('terminalAuthentication') === 'Y'
-              ? OB.UTIL.localStorage.getItem('terminalName')
-              : OB.UTIL.getParameterByName('terminal'),
-          logPropertiesExtension: [
-            function() {
-              return {
-                isOnline: OB.MobileApp.model.get('connectedToERP')
-              };
-            }
-          ]
-        });
-
-        _.each(this.get('dataSyncModels'), function(item) {
-          item.model = eval(item.modelFunc);
-        });
-        //Overwrite offline values
-        this.set('connectedToERP', false);
-        this.set('loggedOffline', true);
-
-        this.allPropertiesLoaded();
-      } else {
-        // not enough data in cache
-        OB.MobileApp.model.loadingErrorsActions(
-          'processPropertyLoaders: not enough data in cache'
-        );
-
-        msg =
-          OB.I18N.getLabel('OBMOBC_NotEnoughDataInCache') +
-          OB.I18N.getLabel('OBMOBC_LoadingErrorBody');
-        OB.UTIL.showConfirmation.display(
-          OB.I18N.getLabel('OBMOBC_TerminalPropertiesErrorHeader'),
-          msg,
-          [
-            {
-              label: OB.I18N.getLabel('OBMOBC_Reload'),
-              action: function() {
-                window.location.reload();
-              }
-            }
-          ],
-          {
-            onShowFunction: function(popup) {
-              OB.UTIL.localStorage.removeItem(
-                'cacheAvailableForUser:' + OB.MobileApp.model.get('orgUserId')
-              );
-              popup.$.headerCloseButton.hide();
-            },
-            autoDismiss: false,
-            showLoading: true
-          }
-        );
-      }
-      return;
-    }
-    this.set('loggedOffline', false);
-    //Loading the properties of the array
-    OB.info(
-      '[terminal] Starting to load properties based on properties loaders, count: ' +
-        this.get('propertiesLoaders').length
-    );
-    OB.UTIL.completeLoadingStep();
-    OB.UTIL.showLoadingMessage(OB.I18N.getLabel('OBMOBC_LoadingTerminalProps'));
-
-    if (
-      this.get('propertiesLoaders') &&
-      this.get('propertiesLoaders').length > 0
-    ) {
-      _.each(
-        this.get('propertiesLoaders'),
-        function(curProperty) {
-          //each loadFunction will call to propertiesReady function. This function will trigger
-          //allPropertiesLoaded when all of the loadFunctions are done.
-          curProperty.loadFunction(this);
-        },
-        this
-      );
-    } else {
-      this.allPropertiesLoaded();
-    }
-  },
-
-  //DEVELOPER: this function will be automatically called when all the properties defined in
-  //this.get('propertiesLoaders') are loaded. To indicate that a property is loaded
-  //me.propertiesReady(properties) should be executed by loadFunction of each property
-  allPropertiesLoaded: function() {
-    var me = this;
-    OB.debug('next process: propertiesLoadersReady');
-    if (!OB.MobileApp.model.get('datasourceLoadFailed')) {
-      OB.UTIL.HookManager.executeHooks(
-        'OBMOBC_TerminalLoaded',
-        {
-          terminalInfo: me
-        },
-        function(args) {
-          OB.info('[terminal] Properties have been successfully loaded');
-          // activate this line to see all the attributes (all the key data from the server)
-          // OB.debug('[terminal] Properties have been successfully loaded', this.attributes);
-          if (!me.get('loggedOffline')) {
-            //In online mode, we save the terminal information in the local db
-            const terminalInfo = JSON.stringify(me);
-            me.usermodel.set('terminalinfo', terminalInfo);
-            OB.App.OfflineSession.updateTerminalInfo(
-              me.usermodel.get('id'),
-              terminalInfo
-            ).then(
-              () => {},
-              error => OB.error('allPropertiesLoaded', error, arguments)
-            );
-          }
-          //renderMain
-          me.trigger('propertiesLoadersReady');
-        }
-      );
-    }
-  },
-
-  /**
-   * This function calls to route function of backbone.
-   * Replace parameter by default is true (if not passed), it means that the current history point will be replaced with the new one without create a new point.
-   * If you want to create a new point in the history then pReplace should be passed as false
-   * http://backbonejs.org/#Router-navigate
-   */
-  navigate: function(route, pReplace, parameters) {
-    if (OB.MobileApp.model.reloadingApplication) {
-      OB.info('Navigation cancelled since application is reloading');
-      return false;
-    }
-    if (route === Backbone.history.getFragment()) {
-      OB.info(
-        'Navigating to same window: ' + route + '. Navigation cancelled.'
-      );
-      return false;
-    }
-    if (pReplace !== false) {
-      pReplace = true;
-    }
-    OB.debug("Navigating to '" + route + "' Replace: " + pReplace);
-    if (route) {
-      OB.App.State.TerminalLog.setContext({ context: route });
-    }
-    OB.MobileApp.view.keyReceivers.splice(
-      0,
-      OB.MobileApp.view.keyReceivers.length
-    );
-    OB.MobileApp.view.currentWindowParameters = parameters;
-    this.router.navigate(route, {
-      trigger: true,
-      replace: pReplace
-    });
-    return true;
-  },
-
-  /**
-   * Loads registered windows and calls renderMain method implemented by each app
-   */
-  renderTerminalMain: function() {
-    OB.info('next process: databaseInitialization');
-    OB.UTIL.Debug.execute(function() {
-      if (!this.renderMain) {
-        throw 'There is no renderMain method in Terminal Model';
-      }
-    }, this);
-    OB.UTIL.localStorage.setItem('POSSessionActive', true);
-    this.databaseInitialization();
-  },
-
-  checkAllPermissions: function(permissions) {
-    // Verify all permissions
-    var i;
-    for (i in permissions) {
-      if (Object.prototype.hasOwnProperty.call(permissions, i)) {
-        if (this.get('permissions')) {
-          if (permissions[i] !== this.get('permissions')[i]) {
-            return true;
-          }
-        }
-      }
-    }
-
-    return false;
-  },
-
-  /**
-   * Database initialization
-   */
-  databaseInitialization: function() {
-    OB.info('next process: loadTerminalInfo');
-    if (window.openDatabase) {
-      this.initLocalDB();
-    } else {
-      this.loadTerminalInfo();
-    }
-  },
-
-  /**
-   * Loads all needed stuff for the terminal such as permissions, Application...
-   */
-  loadTerminalInfo: function() {
-    OB.info('next process: terminalInfoLoaded');
-    OB.UTIL.completeLoadingStep();
-    OB.UTIL.showLoadingMessage(OB.I18N.getLabel('OBMOBC_LoadingTerminalInfo'));
-    var me = this;
-
-    if (OB.MobileApp.model.get('loggedOffline')) {
-      OB.Format = JSON.parse(OB.UTIL.localStorage.getItem('AppFormat'));
-      OB.I18N.labels = JSON.parse(
-        OB.UTIL.localStorage.getItem(
-          'I18NLabels_' +
-            OB.UTIL.localStorage.getItem(
-              'languageForUser_' + me.usermodel.get('id')
-            )
-        )
-      );
-    }
-    this.setUserModelOnline(function() {
-      me.trigger('terminalInfoLoaded');
-    });
-  },
-
-  isSafeToResetDatabase: function(callbackIsSafe, callbackIsNotSafe) {
-    callbackIsSafe();
-  },
-
-  databaseCannotBeResetAction: function() {
-    //Will never happen in standard mobile core. Should be overwritten in applications if isSafeToResetDatabase is implemented
-  },
-
-  openLocalDB: async function() {
-    if (OB.Data.localDB) {
-      OB.Data.localDB.transaction(
-        function() {},
-        function() {
-          OB.Dal.openWebSQL();
-        },
-        null
-      );
-    } else {
-      OB.Dal.openWebSQL();
-    }
-
-    await OB.App.MasterdataController.openDatabase();
-    await OB.App.MessageModelController.openDatabase();
-    await OB.App.OfflineSessionController.openDatabase();
-  },
-
-  initLocalDB: function() {
-    function dropTable(modelObj) {
-      return new Promise(function(resolve, reject) {
-        function dropTableFunction(modelObj) {
-          OB.Dal.dropTable(
-            modelObj,
-            function() {
-              var modelName = modelObj.prototype.modelName;
-              var modelChecksum = OB.Data.getModelStructureChecksum(modelObj);
-              //If this table belongs to a masterdata model, the masterdata needs to be fully loaded
-              if (
-                OB.UTIL.localStorage.getItem('lastUpdatedTimestamp' + modelName)
-              ) {
-                OB.UTIL.localStorage.removeItem(
-                  'lastUpdatedTimestamp' + modelName
-                );
-                OB.UTIL.localStorage.removeItem('POSLastTotalRefresh');
-                OB.UTIL.localStorage.removeItem('POSLastIncRefresh');
-              }
-              OB.Dal.initCache(
-                modelObj,
-                [],
-                function() {
-                  //Set checksum after the model has been created to prevent inconsistent states (e.g. checksum set but missing model)
-                  OB.debug(
-                    'Set model ' + modelName + ' checksum to ' + modelChecksum
-                  );
-                  OB.UTIL.localStorage.setItem(
-                    'structureChecksum-' + modelName,
-                    modelChecksum
-                  );
-                  resolve();
-                },
-                function() {
-                  OB.error("Couldn't initialize table for model: " + modelName);
-                  resolve();
-                }
-              );
-            },
-            function() {
-              OB.error(OB.UTIL.argumentsToStringifyed('dropTable', arguments));
-              reject();
-            }
-          );
-        }
-
-        var syncModel = OB.MobileApp.model.getSyncModel(modelObj);
-        if (syncModel) {
-          OB.MobileApp.model.syncModelHasData(
-            syncModel,
-            function() {
-              //Sync model has data. We will try to synchronize, and if we fail then the databaseCannotBeReset action will be executed
-              OB.MobileApp.model.syncAllModels(function() {
-                dropTableFunction(modelObj);
-              }, OB.MobileApp.model.databaseCannotBeResetAction);
-            },
-            function() {
-              dropTableFunction(modelObj);
-            }
-          );
-        } else {
-          dropTableFunction(modelObj);
-        }
-      });
-    }
-
-    function checkChangedInModels() {
-      var tablesToDrop = [];
-      _.each(OB.Model, function(model) {
-        if (
-          !model.prototype ||
-          !model.prototype.modelName ||
-          model.prototype.legacyModel
-        ) {
-          return;
-        }
-        var modelName = model.prototype.modelName;
-        var modelChecksum = OB.Data.getModelStructureChecksum(model);
-        if (modelChecksum === '') {
-          return;
-        }
-        if (
-          OB.UTIL.localStorage.getItem('structureChecksum-' + modelName) !==
-          modelChecksum
-        ) {
-          if (!OB.UTIL.localStorage.getItem('structureChecksum-' + modelName)) {
-            OB.debug(
-              "Model '" +
-                modelName +
-                "' should not exists because there isn't a paired entry in the localStorage. Performning preemptive table dropping..."
-            );
-          } else {
-            OB.info("Model '" + modelName + "' changed. Rebuilding...");
-          }
-
-          tablesToDrop.push(dropTable(model));
-          OB.MobileApp.model.get('modelsRebuilded').push(model);
-        }
-      });
-
-      OB.info('Checking database models...');
-
-      if (tablesToDrop.length === 0) {
-        OB.info('No models changed.');
-        OB.MobileApp.model.loadTerminalInfo();
-        return;
-      }
-
-      Promise.all(tablesToDrop).then(
-        function() {
-          OB.MobileApp.model.loadTerminalInfo();
-        },
-        function() {
-          OB.MobileApp.model.loadingErrorsActions('initLocalDB.dropTalbles');
-        }
-      );
-    }
-    // check if terminal id has changed
-    if (
-      OB.UTIL.localStorage.getItem('loggedTerminalName') &&
-      OB.UTIL.localStorage.getItem('loggedTerminalName') !==
-        OB.MobileApp.model.get('terminalName')
-    ) {
-      OB.warn(
-        OB.UTIL.argumentsToStringifyed(
-          'terminal changed (' +
-            OB.UTIL.localStorage.getItem('loggedTerminalName') +
-            ' -> ' +
-            OB.MobileApp.model.get('terminalName') +
-            ')'
-        )
-      );
-      OB.info(
-        'Terminal has been changed. Resetting database and local storage information.'
-      );
-      OB.UTIL.localStorage.clear(function() {
-        OB.UTIL.localStorage.setItem(
-          'terminalName',
-          OB.MobileApp.model.get('terminalName')
-        );
-        OB.MobileApp.model.logout();
-        return;
-      });
-    } else {
-      OB.MobileApp.model.set('modelsRebuilded', []);
-      checkChangedInModels();
-    }
-  },
-
-  /**
-   * initActions actions is executed before initializeCommonComponents.
-   *
-   * Override this in case you app needs to do something special
-   * Do not forget to execute callback when overriding the method
-   */
-  initActions: function(callback) {
-    var params = {};
-    var cacheSessionId = null;
-    if (
-      OB.UTIL.localStorage.getItem('cacheSessionId') &&
-      OB.UTIL.localStorage.getItem('cacheSessionId').length === 32
-    ) {
-      cacheSessionId = OB.UTIL.localStorage.getItem('cacheSessionId');
-    }
-
-    params.cacheSessionId = cacheSessionId;
-    params.command = 'initActions';
-    new OB.OBPOSLogin.UI.LoginRequest({
-      url: this.get('loginUtilsUrl')
-        ? this.get('loginUtilsUrl')
-        : '../../org.openbravo.mobile.core.loginutils',
-      data: params
-    })
-      .response(this, function(inSender, inResponse) {
-        if (
-          !(
-            OB.UTIL.localStorage.getItem('cacheSessionId') &&
-            OB.UTIL.localStorage.getItem('cacheSessionId').length === 32
-          )
-        ) {
-          OB.info(
-            'cacheSessionId is not defined and we will set the id generated in the backend: ' +
-              inResponse.cacheSessionId
-          );
-          OB.UTIL.localStorage.setItem(
-            'cacheSessionId',
-            inResponse.cacheSessionId
-          );
-          OB.UTIL.localStorage.setItem(
-            'LastCacheGeneration',
-            new Date().getTime()
-          );
-        }
-        //      Save available servers and services and initialize Request Router layer and Proccess Controller
-        _.each(_.keys(inResponse.properties), function(key) {
-          if (inResponse.properties[key]) {
-            OB.UTIL.localStorage.setItem(
-              key,
-              typeof inResponse.properties[key] === 'string'
-                ? inResponse.properties[key]
-                : JSON.stringify(inResponse.properties[key])
-            );
-          }
-        });
-        OB.RR.RequestRouter.initialize();
-        OB.UTIL.ProcessController.initialize();
-
-        if (callback) {
-          callback();
-        }
-      })
-      .error(function() {
-        if (callback) {
-          callback();
-        }
-      })
-      .go(params);
-  },
-
-  /**
-   * PreLoadContext actions is executed before loading the context.
-   *
-   * Override this in case you app needs to do something special
-   * Do not forget to execute callback when overriding the method
-   */
-  preLoadContext: function(callback) {
-    callback();
-  },
-
-  /**
-   * Returns the corresponding sync model for a data model. Returns null if it's not a sync model
-   */
-  getSyncModel: function(dataModel) {
-    var theSyncModel = null;
-    _.each(this.get('dataSyncModels'), function(syncModel) {
-      if (syncModel.model === dataModel) {
-        theSyncModel = syncModel;
-      }
-    });
-    return theSyncModel;
-  },
-  /**
-   * Returns the corresponding sync model for a data model. Returns null if it's not a sync model
-   */
-  getSyncModelByModelName: function(modelName) {
-    //iterate models
-    var modelFound = _.find(this.get('dataSyncModels'), function(curModel) {
-      return curModel.name === modelName ? curModel : null;
-    });
-    if (modelFound) {
-      return modelFound;
-    }
-    return null;
-  },
-
-  /**
-   * Checks if the corresponding synchronization model has data pending to be synchronized.
-   * - If data is still present, hasDataCallback will be executed, and the data will be sent
-   *   as a parameter in the callback
-   * - If there is no data, doesntHaveDataCallback will be executed
-   */
-  syncModelHasData: function(
-    modelObj,
-    hasDataCallback,
-    doesntHaveDataCallback
-  ) {
-    var criteria = modelObj.changesPendingCriteria
-      ? modelObj.changesPendingCriteria
-      : modelObj.getCriteria
-      ? modelObj.getCriteria()
-      : modelObj.criteria
-      ? modelObj.criteria
-      : null;
-    var modelObject = modelObj;
-    if (modelObj.model) {
-      modelObject = modelObj.model;
-    }
-    if (criteria) {
-      criteria._limit = -1;
-    }
-
-    OB.Dal.find(
-      modelObject,
-      criteria,
-      function(dataToSync) {
-        if (dataToSync.length === 0) {
-          if (doesntHaveDataCallback) {
-            doesntHaveDataCallback(modelObject);
-          }
-        } else {
-          if (hasDataCallback) {
-            hasDataCallback(modelObject, dataToSync);
-          }
-        }
-      },
-      function() {
-        if (doesntHaveDataCallback) {
-          doesntHaveDataCallback(modelObject);
-        }
-      },
-      {
-        doNotShowErrors: true
-      }
-    );
-  },
-
-  /**
-   * @return {Array}  The list of the Sync Models (models which data is sent to the server) with a flag indicating if they have data pending to be sent to the server
-   *
-   * Howto use it:
-   *
-   *    OB.MobileApp.model.getSyncModelsWithHasData().then(function(syncModelsWithHasData) {
-   *      OB.info(syncModelsWithHasData);
-   *    })
-   *
-   * Please note that this function is experimental and that can be changed or removed at any time without notice
-   */
-  getSyncModelsWithHasData: function() {
-    return new Promise(function(resolve, reject) {
-      var syncModelsWithHasData = []; // list of models that requires synchronization and their data status
-      var promisesOfModelsToVerify = [];
-      _.each(OB.Model, function(model) {
-        if (!model.prototype || !model.prototype.modelName) {
-          return;
-        }
-        var modelName = model.prototype.modelName;
-        var modelChecksum = OB.Data.getModelStructureChecksum(model);
-        if (modelChecksum === '') {
-          return;
-        }
-        //TerminalLog synchronization shouldn't be mandatory for tests
-        if (modelName === 'TerminalLog') {
-          return;
-        }
-        var promiseOfModelToVerify = new Promise(function(resolve, reject) {
-          var syncModel = OB.MobileApp.model.getSyncModel(model);
-          if (syncModel) {
-            // add the Sync Model to the array with a hasData flag
-            var callbackHasData = function() {
-              syncModelsWithHasData.push({
-                model: model,
-                hasData: true
-              });
-              resolve();
-            };
-            var callbackNoData = function() {
-              syncModelsWithHasData.push({
-                model: model,
-                hasData: false
-              });
-              resolve();
-            };
-            OB.MobileApp.model.syncModelHasData(
-              syncModel,
-              callbackHasData,
-              callbackNoData
-            );
-          } else {
-            resolve();
-          }
-        });
-        promisesOfModelsToVerify.push(promiseOfModelToVerify);
-      });
-      Promise.all(promisesOfModelsToVerify).then(
-        function() {
-          resolve(syncModelsWithHasData);
-        },
-        function() {
-          OB.error('Could not gather information about the models');
-          reject();
-        }
-      );
-    });
-  },
-
-  /**
-   * Is used by the synchronized mode logic to reset tables to their previous state
-   * before making the synchronized call to the server. So if the user then
-   * refreshes the browser during the call at least the tables are in their previous
-   * versions. This is mainly relevant for cashup information which gets updated
-   * along the way and needs to be reversed if needed.
-   *
-   * If the synchronized call fails then the old cashup information still applies.
-   *
-   * The flow is as follows:
-   * # application code calls saveBackupBeforeChange function, it stores all the relevant tables
-   * for that action
-   * # application then changes what it wants
-   * # then calls runsync process
-   * # runsyncprocess will just before calling the server backup the new version of the
-   *  tables (saveBackupBeforeSyncRestorePreChangeBackup function) and restore the
-   *  before change version
-   * # when the server encounters an error or something else then nothing is changed as
-   * all the data is already in the previous version
-   * # when the server returns correctly the backup tables are restored to their state just
-   * before the send to the server
-   *
-   */
-  _synchronizedCheckpointModels: [],
-  addSyncCheckpointModel: function(model) {
-    this._synchronizedCheckpointModels.push(model);
-  },
-  _prechangeCheckpoint: null,
-  _presyncCheckpoint: null,
-  synchProcessingTransaction: null,
-  setSynchronizedCheckpoint: function(callback) {
-    var me = OB.MobileApp.model;
-
-    if (!OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) {
-      return;
-    }
-
-    // already show the dialog now
-    if (!me.showSynchronizedDialog) {
-      me.showSynchronizingDialog();
-    }
-    OB.Dal.createDataDump(me._synchronizedCheckpointModels, function(
-      checkPoint
-    ) {
-      me._prechangeCheckpoint = checkPoint;
-      if (callback) {
-        callback();
-      }
-    });
-  },
-  synchronizingDialogConditions: new Backbone.Collection(),
-  showSynchronizingDialog: function(condition) {
-    var me = OB.MobileApp.model;
-    if (condition) {
-      this.synchronizingDialogConditions.push(condition);
-    }
-    if (!OB.MobileApp.model.get('avoidSyncronizeModePopup')) {
-      me.showSynchronizedDialog = OB.UTIL.showConfirmation.display(
-        OB.I18N.getLabel('OBMOBC_ProcessingTransactionTitle'),
-        OB.I18N.getLabel('OBMOBC_ProcessingTransaction'),
-        [],
-        {
-          hideCloseButton: true,
-          autoDismiss: false,
-          closeOnEscKey: false
-        }
-      );
-    }
-    OB.Data.showSynchronizedDialogChangeTime = new Date().getTime();
-    OB.UTIL.preventRefreshByUser();
-  },
-
-  hideSynchronizingDialog: function(condition) {
-    var me = OB.MobileApp.model;
-    if (condition) {
-      this.synchronizingDialogConditions.pop(condition);
-    }
-    if (
-      me.showSynchronizedDialog &&
-      this.synchronizingDialogConditions.length === 0
-    ) {
-      me.showSynchronizedDialog.hide();
-      me.showSynchronizedDialog = null;
-      OB.UTIL.resetPreventRefreshByUser();
-    }
-  },
-
-  createPresyncCheckpoint: function(callback) {
-    var me = OB.MobileApp.model;
-
-    OB.Dal.createDataDump(me._synchronizedCheckpointModels, function(
-      checkPoint
-    ) {
-      me._presyncCheckpoint = checkPoint;
-      if (callback) {
-        callback();
-      }
-    });
-  },
-  moveToPrechangeCheckpoint: function(callback) {
-    var me = OB.MobileApp.model,
-      dataDump = me._prechangeCheckpoint;
-    if (!dataDump) {
-      if (callback) {
-        callback();
-      }
-      return;
-    }
-    // be on the save side, set it to null if it fails we won't get it
-    // back anyway
-    me._prechangeCheckpoint = null;
-    OB.Dal.restoreDataDump(dataDump, function() {
-      me._prechangeCheckpoint = null;
-      if (callback) {
-        callback();
-      }
-    });
-  },
-  resetCheckpointData: function() {
-    var me = OB.MobileApp.model;
-
-    me._presyncCheckpoint = null;
-    me._prechangeCheckpoint = null;
-  },
-  moveToPresyncCheckpoint: function(callback) {
-    var me = OB.MobileApp.model;
-    // reset this one also
-    me._prechangeCheckpoint = null;
-
-    if (!me._presyncCheckpoint) {
-      if (callback) {
-        callback();
-      }
-      return;
-    }
-    OB.Dal.restoreDataDump(me._presyncCheckpoint, function() {
-      me._presyncCheckpoint = null;
-      if (callback) {
-        callback();
-      }
-    });
-  },
-
-  preSyncPromises: [],
-  doPreSynchronizedCallActions: function(callback, syncData) {
-    var me = OB.MobileApp.model;
-    OB.UTIL.localStorage.setItem('synchronizedMessageId', syncData.messageId);
-    new Promise(function(resolve, reject) {
-      me.createPresyncCheckpoint(function() {
-        resolve();
-      });
-    })
-      .then(function() {
-        return new Promise(function(resolve, reject) {
-          me.moveToPrechangeCheckpoint(function() {
-            resolve();
-          });
-        });
-      })
-      .then(function() {
-        return Promise.all(me.preSyncPromises);
-      })
-      .then(
-        function() {
-          me.preSyncPromises = [];
-          if (callback) {
-            callback();
-          }
-        },
-        function(reason) {
-          OB.error('Error while processing promise ' + reason);
-        }
-      );
-  },
-  doPostSynchronizedCallActions: function(callback, syncData) {
-    if (
-      OB.UTIL.isNullOrUndefined(
-        OB.UTIL.localStorage.getItem('synchronizedMessageId')
-      ) ||
-      OB.UTIL.localStorage.getItem('synchronizedMessageId') ===
-        syncData.messageId
-    ) {
-      OB.UTIL.localStorage.removeItem('synchronizedMessageId');
-    } else {
-      OB.error(
-        "Message id of the last request doesn't much with the current messageId"
-      );
-    }
-    if (callback) {
-      callback();
-    }
-  },
-  /**
-   * Sets the OBMOBC_SynchronizedMode permission and returns the previous value.
-   * Can be used to temporarily disable synchronized mode.
-   */
-  setSynchronizedPreference: function(newValue) {
-    var currentValue = OB.MobileApp.model.hasPermission(
-      'OBMOBC_SynchronizedMode',
-      true
-    );
-    OB.MobileApp.model.get('permissions').OBMOBC_SynchronizedMode = newValue;
-    return currentValue;
-  },
-
-  /**
-   * Should not be called directly. syncAllModels should be used instead
-   *
-   * Recursively syncs models. The recursion will end if:
-   *   - all models have successfully synchronized
-   *  or if
-   *   - an exception is raised
-   *
-   */
-  syncModelQueue: null,
-  syncModel: function() {
-    var me = this;
-
-    // stop the recursion when the queue of syncModels is empty
-    // the rest of the actions are in the removeSyncedElemsCallback
-    if (me.syncModelQueue.length === 0) {
-      //There aren't anymore elements to synchronize
-      if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) {
-        // clean up in any case after success or error
-        // note: moveToPresyncCheckpoint must be called before the reset
-        me.syncModelSuccessCallbacks.unshift(function() {
-          me.resetCheckpointData();
-        });
-        me.syncModelErrorCallbacks.push(function() {
-          me.resetCheckpointData();
-        });
-
-        // nothing to do go away
-        if (me.synchronizedData.length === 0) {
-          me.syncModelExecuteSuccessCallbacks();
-          return;
-        }
-
-        // already show the dialog now
-        if (
-          !me.showSynchronizedDialog &&
-          !OB.MobileApp.view.$.containerLoading.showing
-        ) {
-          me.showSynchronizingDialog();
-        }
-        //now send all the collected json as one request
-        var syncProc = new OB.DS.Process(
-          'org.openbravo.mobile.core.servercontroller.SynchronizedServerProcessCaller'
-        );
-        var syncData = {
-          messageId: OB.UTIL.get_UUID(),
-          _source: 'WEBPOS',
-          _executeInOneServer: true,
-          _tryCentralFromStore: true,
-          posTerminal: OB.MobileApp.model.get('terminal')
-            ? OB.MobileApp.model.get('terminal').id
-            : null,
-          data: me.synchronizedData,
-          extraParams: {
-            isSynchronizeModeTransaction: true
-          }
-        };
-
-        // clear some memory
-        me.synchronizedData = [];
-
-        // and execute the complete request, first do the presync actions
-        me.doPreSynchronizedCallActions(function() {
-          syncProc.exec(
-            syncData,
-            function() {
-              var args = arguments;
-              me.doPostSynchronizedCallActions(function() {
-                var params;
-                if (args.length > 0) {
-                  params = args[0];
-                  if (args[0].result && args[0].result.length > 0) {
-                    params = args[0].result[0];
-                  }
-                }
-                me.syncModelExecuteSuccessCallbacks(params);
-              }, syncData);
-            },
-            function() {
-              var args = arguments;
-              me.syncModelExecuteErrorCallbacks(args);
-            },
-            null,
-            me.synchronizedTimeOut
-          );
-        }, syncData);
-      } else {
-        me.syncModelExecuteSuccessCallbacks();
-      }
-      return;
-    }
-
-    var modelObj = me.syncModelQueue.shift();
-    var model = modelObj.model;
-    var criteria;
-    if (modelObj.getCriteria) {
-      criteria = modelObj.getCriteria();
-    } else if (modelObj.criteria) {
-      criteria = modelObj.criteria;
-    } else {
-      criteria = {
-        hasBeenProcessed: 'Y'
-      };
-    }
-    criteria._limit = -1;
-    OB.Dal.find(
-      model,
-      criteria,
-      function(dataToSync) {
-        me.skipSyncModel = dataToSync.length === 0;
-
-        if (modelObj.preSendModel) {
-          // preSendModel is like a hook which can be used by custom code
-          // to influence the logic, for example setting me.skipSyncModel
-          modelObj.preSendModel(me, dataToSync);
-        }
-
-        if (me.skipSyncModel) {
-          me.skipSyncModel = false;
-          me.syncModel();
-          return;
-        }
-
-        var className = modelObj.className;
-
-        if (model === OB.Model.Order && OB.UTIL.processOrderClass) {
-          className = OB.UTIL.processOrderClass;
-        }
-
-        var mdl,
-          modelIndex = 0,
-          modelNotFullySynced = false,
-          dataCorruption = false,
-          newDataToSync = new Backbone.Collection();
-        while (modelIndex < dataToSync.length) {
-          mdl = dataToSync.at(modelIndex);
-          if (
-            !_.isUndefined(mdl.get('json')) &&
-            (_.isEmpty(mdl.get('json')) || _.isNull(mdl.get('json')))
-          ) {
-            OB.error(
-              '[syncModel] Wrong model to Synchronize in backend: ' +
-                mdl.modelName +
-                ' because json column is undefined.'
-            );
-            dataCorruption = true;
-          } else {
-            newDataToSync.add(dataToSync.at(modelIndex));
-          }
-
-          modelIndex++;
-          // partition the data in chunks
-          if (modelIndex >= 100 && modelIndex < dataToSync.length) {
-            modelNotFullySynced = true;
-            // add the model again to the beginning of the queue
-            me.syncModelQueue.unshift(modelObj);
-            break;
-          }
-        }
-        if (dataCorruption) {
-          var criteria = {
-            whereClause: ' WHERE json is null OR json= "" '
-          };
-          OB.Dal.removeAll(model, criteria);
-        }
-
-        var dataToSend = [];
-        newDataToSync.each(function(record) {
-          if (record.get('json')) {
-            dataToSend.push(JSON.parse(record.get('json')));
-          } else if (!_.isUndefined(record.get('objToSend'))) {
-            if (!_.isNull(record.get('objToSend'))) {
-              dataToSend.push(JSON.parse(record.get('objToSend')));
-            }
-          } else {
-            dataToSend.push(record);
-          }
-        });
-
-        var timeout = modelObj.timeout || 20000;
-        var timePerRecord = modelObj.timePerRecord || 1000;
-        var data = {
-          messageId: OB.UTIL.get_UUID(),
-          modelName: modelObj.name,
-          data: dataToSend,
-          isSyncModel: true
-        };
-
-        // add an additional pre-sync action, remove any non-persistent data
-        // before really going to the server
-        if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) {
-          newDataToSync.each(function(record) {
-            me.preSyncPromises.push(
-              new Promise(function(resolve, reject) {
-                if (!modelObj.isPersistent) {
-                  OB.Dal.remove(
-                    record,
-                    function() {
-                      resolve();
-                    },
-                    function(tx, err) {
-                      OB.UTIL.showError(err);
-                      reject();
-                    }
-                  );
-                } else {
-                  resolve();
-                }
-              })
-            );
-          });
-        }
-
-        var procErrorCallBack = function() {
-          // proc.exec  mcallbackerror
-          OB.warn(
-            "Error while synchronizing model '" +
-              OB.Dal.getTableName(model) +
-              "'"
-          );
-
-          me.syncModelExecuteErrorCallbacks();
-        };
-
-        var procSuccessCallBack = function(
-          data,
-          message,
-          lastUpdated,
-          endRow,
-          tx,
-          requestCallback
-        ) {
-          // error
-          if (data && data.exception) {
-            OB.warn(
-              "The model '" +
-                OB.Dal.getTableName(model) +
-                "'' has not been synchronized with the server"
-            );
-            if (
-              data.exception.invalidPermission &&
-              !me.get('displayedInvalidPermission')
-            ) {
-              // invalid permission message only will be displayed once time
-              me.set('displayedInvalidPermission', true);
-              OB.UTIL.showConfirmation.display(
-                'Info',
-                OB.I18N.getLabel('OBMOBC_NoPermissionToSyncModel', [
-                  OB.Dal.getTableName(model),
-                  OB.Dal.getTableName(model)
-                ]),
-                [
-                  {
-                    label: OB.I18N.getLabel('OBMOBC_LblOk'),
-                    isConfirmButton: true,
-                    action: function() {}
-                  }
-                ]
-              );
-            }
-            me.syncModelExecuteErrorCallbacks();
-            return;
-          }
-          // success. Elements can be now deleted from the database
-          var removeSyncedElemsCallback = function(tx) {
-            OB.info("Purging the '" + OB.Dal.getTableName(model) + "' table");
-
-            var promises = [];
-
-            if (modelObj.successSendModel) {
-              promises.push(
-                new Promise(function(resolve, reject) {
-                  modelObj.successSendModel();
-                  resolve();
-                })
-              );
-            }
-
-            newDataToSync.each(function(record) {
-              promises.push(
-                new Promise(function(resolve, reject) {
-                  if (modelObj.isPersistent) {
-                    // Persistent model. Do not delete, just mark it as processed.
-                    OB.Dal.updateRecordColumn(
-                      record,
-                      'isbeingprocessed',
-                      'Y',
-                      function() {
-                        if (requestCallback) {
-                          requestCallback();
-                        }
-                        resolve();
-                      },
-                      function(tx, err) {
-                        reject();
-                      },
-                      tx
-                    );
-                  } else {
-                    // no persistent model (Default).
-                    OB.Dal.removeInTransaction(
-                      tx,
-                      record,
-                      function() {
-                        if (requestCallback) {
-                          requestCallback();
-                        }
-                        resolve();
-                      },
-                      function(tx, err) {
-                        OB.UTIL.showError(err);
-                        reject();
-                      }
-                    );
-                  }
-                })
-              );
-            });
-
-            Promise.all(promises).then(
-              function() {
-                // if the model has been partitioned
-                if (modelNotFullySynced) {
-                  OB.info(
-                    newDataToSync.length +
-                      " records of the table '" +
-                      OB.Dal.getTableName(model) +
-                      "' have been successfully synchronized with the server. " +
-                      (dataToSync.length - newDataToSync.length) +
-                      ' records remaining to be synchronized.'
-                  );
-                  me.syncModel();
-                  return;
-                }
-
-                OB.info(
-                  "The table '" +
-                    OB.Dal.getTableName(model) +
-                    "' has been fully synchronized with the server"
-                );
-              },
-              function(err) {
-                OB.error(
-                  "Could not purge the '" +
-                    OB.Dal.getTableName(model) +
-                    "' table. Error message: " +
-                    err
-                );
-              }
-            );
-            // not synchronized mode do the next in the success callback
-            // with synchronized mode the recall syncmodel is below in the code
-            if (
-              !OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)
-            ) {
-              me.syncModel();
-            }
-          };
-          if (modelObj.removeSyncedElemsCallback) {
-            modelObj.removeSyncedElemsCallback(
-              newDataToSync,
-              tx,
-              requestCallback
-            );
-          } else {
-            removeSyncedElemsCallback(tx);
-          }
-          if (modelObj.postProcessingFunction) {
-            modelObj.postProcessingFunction(
-              newDataToSync,
-              removeSyncedElemsCallback
-            );
-          }
-        };
-
-        if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) {
-          me.collectSyncData(
-            className,
-            data,
-            timeout + timePerRecord * newDataToSync.length
-          );
-          me.syncModelSuccessCallbacks.push(procSuccessCallBack);
-          me.syncModel();
-        } else {
-          var proc = new OB.DS.Process(className);
-          //if the model of the message requires polling, add it to the list
-          var tmpMsg = OB.PollingUtils.createMessage(data, proc.source);
-          data.messageId = tmpMsg.id;
-          if (OB.PollingUtils.getPollingUrl(tmpMsg)) {
-            OB.Polling.PollingRequestHandler.planedToSendPollingRequest.add(
-              new OB.Model.PollingRequest({
-                message: tmpMsg
-              })
-            );
-          }
-          proc.exec(
-            data,
-            procSuccessCallBack,
-            procErrorCallBack,
-            null,
-            timeout + timePerRecord * newDataToSync.length
-          );
-        }
-      },
-
-      function() {
-        // there is no model in the local database. this is ok. move to the next model
-        me.syncModel();
-      },
-      {
-        // do not show an error when the table is not present in the local database because it could happen when the cache is still clean
-        doNotShowErrors: true
-      }
-    );
-  },
-  syncModelSuccessCallbacks: [],
-  syncModelErrorCallbacks: [],
-  syncModelExecuteSuccessCallbacks: function(result) {
-    result = result || {};
-    OB.UTIL.Debug.execute(function() {
-      if (
-        OB.MobileApp.model.syncModelQueue &&
-        OB.MobileApp.model.syncModelQueue.length > 0
-      ) {
-        throw "The 'syncModelQueue' should be empty at this point";
-      }
-    });
-
-    // exception occurred but was returned in the json as a valid response
-    if (result && result.exception) {
-      OB.MobileApp.model.syncModelExecuteErrorCallbacks(arguments);
-      return;
-    }
-    if (OB.MobileApp.model.showSynchronizedDialog) {
-      OB.MobileApp.model.hideSynchronizingDialog();
-    }
-
-    OB.MobileApp.model.syncModelQueue = [];
-    OB.MobileApp.model.syncModelErrorCallbacks = [];
-
-    function execCallbacks() {
-      new Promise(function(resolve, reject) {
-        // is only doing anything in case of synchronized mode
-        OB.MobileApp.model.moveToPresyncCheckpoint(function() {
-          resolve();
-        });
-      }).then(function() {
-        OB.UTIL.executeCallbackQueue(
-          OB.MobileApp.model.syncModelSuccessCallbacks,
-          result
-        );
-      });
-    }
-
-    //Get messages from local database only when polling models exists
-    if (OB.Polling.PollingRequestHandler.getPollingSyncModels().length > 0) {
-      //set in result messages pending to synchronize
-      OB.RR.ServTypeTransaction.getMessages(
-        function(messages) {
-          var promises = [];
-          _.each(messages.models, function(msg) {
-            //if the model of the message requires polling, add it to the list
-            if (OB.PollingUtils.getPollingUrl(msg)) {
-              promises.push(
-                new Promise(function(resolve, reject) {
-                  OB.Polling.PollingRequestHandler.planedToSendPollingRequest.add(
-                    new OB.Model.PollingRequest({
-                      message: msg
-                    })
-                  );
-                  resolve();
-                })
-              );
-            }
-          });
-          Promise.all(promises).then(function() {
-            result.messages =
-              OB.Polling.PollingRequestHandler.planedToSendPollingRequest;
-            execCallbacks();
-          });
-        },
-        function() {
-          execCallbacks();
-        }
-      );
-    } else {
-      execCallbacks();
-    }
-  },
-  syncModelExecuteErrorCallbacks: function() {
-    OB.MobileApp.model.syncModelQueue = [];
-    OB.MobileApp.model.syncModelSuccessCallbacks = [];
-
-    if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) {
-      var msg =
-        arguments[0][0] && arguments[0][0].exception
-          ? arguments[0][0].exception.message
-          : 'No Details';
-
-      if (OB.MobileApp.model.showSynchronizedDialog) {
-        OB.MobileApp.model.hideSynchronizingDialog();
-      }
-
-      OB.UTIL.showConfirmation.display(
-        OB.I18N.getLabel('OBMOBC_TransactionFailedTitle'),
-        OB.I18N.getLabel('OBMOBC_TransactionFailed', [msg]),
-        [
-          {
-            isConfirmButton: true,
-            label: OB.I18N.getLabel('OBMOBC_LblOk'),
-            action: function() {
-              if (OB.MobileApp.view.currentWindow !== 'retail.pointofsale') {
-                OB.POS.navigate('retail.pointofsale');
-                return true;
-              }
-            }
-          }
-        ]
-      );
-    }
-
-    OB.UTIL.executeCallbackQueue(OB.MobileApp.model.syncModelErrorCallbacks);
-  },
-
-  // collect the data to sync
-  collectSyncData: function(source, params, timeout) {
-    var data = OB.DS.Process.prepareData(params);
-
-    data._serviceName = source;
-
-    this.synchronizedTimeOut = this.synchronizedTimeOut + timeout;
-
-    this.synchronizedData.push(data);
-  },
-
-  /**
-   * Synchronizes all dataSyncModels (models which data is kept localy until flushed to the server)
-   *
-   * If this method is called while a previous data synchronization is in place:
-   * - the data synchronization of the model being synchronized at the time this method is called, will be finished
-   * - the remaining models will not be synchronized
-   * - the synchronization will start over with the first model
-   * - all the callbacks (success or error) are gathered in a queue, all of them will be executed when the synchronization ends
-   */
-  syncAllModels: function(successCallback, errorCallback) {
-    this.syncAllModelsImpl(successCallback, errorCallback);
-  },
-
-  syncAllModelsImpl: function(successCallback, errorCallback) {
-    var me = this;
-
-    // if the user is not authenticated, the server will reject all the connections
-    if (!OB.MobileApp.model.isUserAuthenticated()) {
-      OB.UTIL.Debug.execute(function() {
-        OB.warn(
-          "'OB.MobileApp.model.syncAllModels' cannot be executed because it requires an autheticated user"
-        );
-      });
-      if (errorCallback) {
-        errorCallback();
-      }
-      return;
-    }
-    // if there is no model to be synchronized
-    if (!me.get('dataSyncModels') || me.get('dataSyncModels').length === 0) {
-      if (successCallback) {
-        successCallback();
-      }
-      return;
-    }
-    // flow note: this line must be located before the queues are reset. Check models queue and callbacks queues, the process finishes when the callback are called
-    var isCurrentlySynchronizing =
-      (me.syncModelQueue && me.syncModelQueue.length > 0) ||
-      (me.syncModelSuccessCallbacks &&
-        me.syncModelSuccessCallbacks.length > 0) ||
-      (me.syncModelErrorCallbacks && me.syncModelErrorCallbacks.length > 0);
-    // start the synchronization if it was not already in progress
-    if (!isCurrentlySynchronizing) {
-      me.syncModelSuccessCallbacks = [];
-      me.syncModelErrorCallbacks = [];
-
-      // remember the callbacks in the callbacks queue
-      me.syncModelSuccessCallbacks.push(successCallback);
-      me.syncModelErrorCallbacks.push(errorCallback);
-
-      // all models must restart the synchronization when syncAllModels is called. this is attained reseting the queue
-      me.syncModelQueue = [];
-      // add all the models to the queue
-      var i;
-      for (i = 0; i < this.get('dataSyncModels').length; i++) {
-        var modelObj = this.get('dataSyncModels')[i];
-        me.syncModelQueue.push(modelObj);
-      }
-
-      // reset some members used in synchronized comms
-      me.synchronizedData = [];
-      me.synchronizedTimeOut = 0;
-
-      me.syncModel(
-        this.syncModelExecuteSuccessCallbacks,
-        this.syncModelExecuteErrorCallbacks
-      );
-    }
-  },
-
-  /**
-   * Returns true if a user is authenticated
-   */
-  isUserAuthenticated: function() {
-    return !!OB.MobileApp.model.get('context');
-  },
-
-  /**
-   * If any module needs to perform operations with properties coming from the server
-   * this function must be overwritten
-   */
-  isUserCacheAvailable: function() {
-    return false;
-  },
-
-  /**
-   * Invoked from initComponents in terminal view
-   */
-  initializeCommonComponents: function() {
-    this.openLocalDB().finally(() => {
-      this.initializeCommonComponentsImp();
-    });
-  },
-
-  initializeCommonComponentsImp: function() {
-    OB.info(
-      "next process: navigate 'login' or renderTerminalMain or loginUsingCache"
-    );
-
-    var me = this,
-      params = {};
-    OB.UTIL.localStorage.setItem('LOGINTIMER', new Date().getTime());
-
-    params = this.get('loginUtilsParams') || {};
-    params.command = 'preRenderActions';
-    params.appModuleId = this.get('appModuleId');
-    params.supportsExternalBusinessPartnerIntegration = this.get(
-      'supportsExternalBusinessPartnerIntegration'
-    );
-    // initialize labels and other common stuff
-    var rr,
-      ajaxRequest = new enyo.Ajax({
-        url: this.get('loginUtilsUrl'),
-        cacheBust: false,
-        timeout: 5000,
-        // don't do retries as this gives side effects as re-showing login page
-        maxNumOfRequestRetries: 0,
-        method: 'GET',
-        handleAs: 'json',
-        contentType: 'application/json;charset=utf-8',
-        data: params,
-        success: function(inSender, inResponse) {
-          OB.info('loginUtilsUrl success');
-          if (inResponse.csrfToken) {
-            OB.MobileApp.model.set('csrfToken', inResponse.csrfToken);
-          }
-          if (inResponse.externalBpIntegration) {
-            OB.MobileApp.model.set(
-              'externalBpIntegration',
-              inResponse.externalBpIntegration
-            );
-          }
-
-          if (
-            _.isEmpty(inResponse.labels) ||
-            _.isNull(inResponse.labels) ||
-            _.isUndefined(inResponse.labels)
-          ) {
-            OB.I18N.labels = JSON.parse(
-              OB.UTIL.localStorage.getItem('I18NLabels')
-            );
-          } else {
-            OB.appCaption = inResponse.appCaption;
-            OB.UTIL.localStorage.setItem(
-              'POSlanguageId',
-              inResponse.labels.languageId
-            );
-            OB.UTIL.localStorage.setItem(
-              'POSlanguageSK',
-              inResponse.labels.languageSk
-            );
-            OB.I18N.labels = inResponse.labels;
-            if (inResponse.activeSession) {
-              // The labels will only be saved in the localStorage if they come from an active session
-              // We do this to prevent the labels loaded in the login page from being stored here and overwritting
-              // the labels in the correct language (see issue 23613)
-              OB.UTIL.localStorage.setItem(
-                'languageForUser_' + OB.MobileApp.model.get('orgUserId'),
-                inResponse.labels.languageId
-              );
-              OB.UTIL.localStorage.setItem(
-                'I18NLabels',
-                JSON.stringify(OB.I18N.labels)
-              );
-              OB.UTIL.localStorage.setItem(
-                'I18NLabels_' + inResponse.labels.languageId,
-                JSON.stringify(OB.I18N.labels)
-              );
-            }
-          }
-          if (
-            _.isEmpty(inResponse.lists) ||
-            _.isNull(inResponse.lists) ||
-            _.isUndefined(inResponse.lists)
-          ) {
-            OB.I18N.lists = JSON.parse(
-              OB.UTIL.localStorage.getItem('I18NLists')
-            );
-          } else {
-            OB.I18N.lists = inResponse.lists;
-            if (inResponse.activeSession) {
-              // The reference list will only be saved in the localStorage if they come from an active session
-              // We do this to prevent the reference list loaded in the login page from being stored here and overwritting
-              // the reference list in the correct language
-              OB.UTIL.localStorage.setItem(
-                'I18NLists',
-                JSON.stringify(OB.I18N.lists)
-              );
-              OB.UTIL.localStorage.setItem(
-                'I18NLists_' + inResponse.lists.languageId,
-                JSON.stringify(OB.I18N.lists)
-              );
-            }
-          }
-          if (
-            _.isEmpty(inResponse.dateFormats) ||
-            _.isNull(inResponse.dateFormats) ||
-            _.isUndefined(inResponse.dateFormats)
-          ) {
-            OB.Format = JSON.parse(OB.UTIL.localStorage.getItem('AppFormat'));
-          } else {
-            OB.Format = inResponse.dateFormats;
-          }
-
-          var permissions = {},
-            i,
-            separator;
-          if (inResponse.permissions) {
-            for (i = 0; i < inResponse.permissions.length; i++) {
-              permissions[inResponse.permissions[i].key] =
-                inResponse.permissions[i].value; // Add the permission value.
-              separator = inResponse.permissions[i].key.indexOf('_');
-              if (separator >= 0) {
-                permissions[
-                  inResponse.permissions[i].key.substring(separator + 1)
-                ] = inResponse.permissions[i].value; // if key has a DB prefix, add also the permission value without this prefix
-              }
-            }
-          } else {
-            permissions = null;
-          }
-
-          me.set('permissions', permissions);
-
-          if ('invalidRequestOrigin' === inResponse.exception) {
-            OB.UTIL.showConfirmation.display(
-              OB.I18N.getLabel('OBMOBC_InvalidOriginTitle'),
-              OB.I18N.getLabel('OBMOBC_InvalidOriginMsg')
-            );
-            return;
-          }
-          me.trigger('initializedCommonComponents');
-          me.preLoadContext(function() {
-            if (
-              !inResponse.contextInfo ||
-              OB.UTIL.localStorage.getItem('POSSessionActive') === 'false'
-            ) {
-              //Not authenticated, need to navigate to login page
-              OB.MobileApp.model.navigate('login');
-              return;
-            }
-            OB.MobileApp.model.triggerOnLine();
-            OB.info('Set isLoggingIn true');
-            OB.MobileApp.model.set('isLoggingIn', true);
-            OB.MobileApp.model.set('orgUserId', inResponse.contextInfo.user.id);
-            me.set('context', inResponse.contextInfo); // fires the 'change:context' event
-            window.OB.Format = inResponse.format;
-            window.OB.UTIL.localStorage.setItem(
-              'AppFormat',
-              JSON.stringify(OB.Format)
-            );
-            OB.UTIL.startLoadingSteps();
-            me.renderTerminalMain();
-            return;
-          });
-        },
-        fail: function(inSender, inResponse) {
-          OB.info('loginUtilsUrl fail');
-          if (this.alreadyProcessed) {
-            return;
-          }
-          this.alreadyProcessed = true;
-          // we are likely offline. Attempt to navigate to the login page
-          OB.I18N.labels = JSON.parse(
-            OB.UTIL.localStorage.getItem('I18NLabels')
-          );
-          OB.Format = JSON.parse(OB.UTIL.localStorage.getItem('AppFormat'));
-          me.trigger('initializedCommonComponents');
-          if (!OB.I18N.labels || !OB.Format) {
-            // These 2 objects are needed for the application to show i18n messages and date and number formats
-            OB.UTIL.showLoading(false);
-            var errorMsg =
-              'The server is not available and the cache has not enough data. Connect to the server and try again.';
-            OB.error('initializeCommonComponents', errorMsg);
-            OB.UTIL.showConfirmation.display(
-              'Error',
-              errorMsg,
-              [
-                {
-                  label: 'Retry',
-                  isConfirmButton: true,
-                  action: function() {
-                    // Retry. If the server is not available, the message will open again
-                    me.initializeCommonComponents();
-                  }
-                }
-              ],
-              {
-                onHideFunction: function() {
-                  // Retry. If the server is not available, the message will open again
-                  me.initializeCommonComponents();
-                }
-              }
-            );
-            return;
-          }
-          me.attemptToLoginOffline();
-        }
-      });
-
-    rr = new OB.RR.Request({
-      ajaxRequest: ajaxRequest
-    });
-    OB.info('loginUtilsUrl request');
-    rr.exec(ajaxRequest.url);
-  },
-
-  renderLogin: function() {
-    if (!OB.MobileApp.view) {
-      // the terminal view has yet to be created
-      OB.UTIL.Debug.execute(function() {
-        throw 'OB.MobileApp.view must be defined';
-      });
-      OB.MobileApp.model.navigate('');
-      return;
-    }
-    if (!OB.MobileApp.view.$.containerWindow) {
-      // this can happen if the webpage is reloaded
-      // OB.UTIL.Debug.execute(function () {
-      //   OB.error("OB.MobileApp.view.$.containerWindow must be defined");
-      // });
-      OB.MobileApp.model.navigate('');
-      return;
-    }
-
-    this.initApplicationTasks(function() {
-      OB.MobileApp.view.$.containerWindow.destroyComponents();
-      OB.MobileApp.view.$.containerWindow
-        .createComponent({
-          kind: OB.OBPOSLogin.UI.Login,
-          classes: 'obUiTerminal-containerWindow-obObposLoginUiLogin'
-        })
-        .render();
-      OB.UTIL.showLoading(false);
-    });
-  },
-
-  initApplicationTasks: async function(callback) {
-    const me = this;
-    // ensure exists message table, to check if there are messages pending to sync,
-    // thats needs to be synchonized before update the sources
-    const stateMessages = OB.App.State.getState().Messages;
-    const syncBufferMessages = await OB.App.SynchronizationBuffer.getPendingMessages();
-    const hasNotSyncedMessages =
-      stateMessages.length > 0 || syncBufferMessages.length > 0;
-
-    if (hasNotSyncedMessages) {
-      // do not update sources
-      me.checkBenchMark(callback);
-      OB.warn(
-        'On preparing login page, but cannot check for new sources becasue there are messages to be sync. Needed to be logged in to sync them'
-      );
-    } else {
-      // update sources
-      this.loadApplicationSources(callback);
-    }
-  },
-
-  checkBenchMark: function(finalCallback) {
-    const browserInfo = OB.UTIL.getSupportedBrowserInfo();
-    OB.MobileApp.model.set('ApplicationSourcesLoaded', true);
-    if (browserInfo.isSupported) {
-      if (
-        !OB.UTIL.Debug.getDebugCauses() ||
-        (!OB.UTIL.Debug.getDebugCauses().isInDevelopment &&
-          !OB.UTIL.Debug.getDebugCauses().isTestEnvironment)
-      ) {
-        if (
-          OB.MobileApp.model.get('shouldExecuteBenchmark') &&
-          OB.UTIL.localStorage.getItem('doNotExecuteBenchmark') === null &&
-          OB.UTIL.localStorage.getItem('executePerformanceTest') !== 'N'
-        ) {
-          this.dialog = OB.MobileApp.view.$.confirmationContainer.createComponent(
-            {
-              kind: 'OB.UI.ModalBenchmark',
-              name: 'modalBenchmark',
-              classes: 'obUiTerminal-confirmationContainer-modalBenchmark',
-              context: this
-            }
-          );
-          OB.UTIL.showLoading(false);
-          this.dialog.show({
-            callback: finalCallback
-          });
-          return;
-        }
-      }
-    }
-    finalCallback();
-  },
-
-  loadApplicationSources: function(callback) {
-    var finalCallback, permissionSW;
-    const me = this;
-    finalCallback = function() {
-      if (callback instanceof Function) {
-        callback();
-      }
-    };
-
-    if (typeof ServiceWorkerUtil !== 'undefined') {
-      permissionSW = ServiceWorkerUtil.useServiceWorkers;
-    } else {
-      permissionSW = false;
-    }
-    if (permissionSW === true) {
-      OB.UTIL.fetchApplicationSources(
-        function() {
-          me.checkBenchMark(finalCallback);
-        },
-        function() {
-          OB.error('Error in fetching the application sources.');
-          OB.MobileApp.model.set('loadManifeststatus', {
-            type: 'error',
-            reason: 'fail'
-          });
-          finalCallback();
-        }
-      );
-    } else {
-      //If preference is not set, we will use AppCache
-      me.checkBenchMark(finalCallback);
-    }
-  },
-
-  loadModels: function(windows, incremental, parentCallback, background) {
-    var i,
-      j,
-      windowName,
-      windowClass,
-      windowDatasources,
-      datasources = [],
-      w,
-      c,
-      path;
-
-    const initLogParamsForBackgroundProcesses = function() {
-      OB.UTIL.localStorage.setItem('totalRecordsBackgroundRequest', 0);
-      OB.UTIL.localStorage.setItem('totalTimeBackgroundRequest', 0);
-      OB.UTIL.localStorage.setItem('totalRecordsBackgroundSave', 0);
-      OB.UTIL.localStorage.setItem('totalTimeBackgroundSave', 0);
-    };
-
-    const showLogsForBackgroundProcesses = function() {
-      let processDetails = incremental ? 'inc' : 'full';
-      let totalRecordsBackgroundRequest = OB.UTIL.localStorage.getItem(
-        'totalRecordsBackgroundRequest'
-      );
-      let totalTimeBackgroundRequest = OB.UTIL.localStorage.getItem(
-        'totalTimeBackgroundRequest'
-      );
-      let totalRecordsBackgroundSave = OB.UTIL.localStorage.getItem(
-        'totalRecordsBackgroundSave'
-      );
-      let totalTimeBackgroundSave = OB.UTIL.localStorage.getItem(
-        'totalTimeBackgroundSave'
-      );
-      if (Number(totalTimeBackgroundRequest) > 0) {
-        OB.info(
-          '[background-request-' +
-            processDetails +
-            '] Loaded ' +
-            totalRecordsBackgroundRequest +
-            ' records in the process. Finished after ' +
-            totalTimeBackgroundRequest +
-            ' miliseconds.'
-        );
-      }
-      if (Number(totalTimeBackgroundSave) > 0) {
-        OB.info(
-          '[background-save-' +
-            processDetails +
-            '] Saved ' +
-            totalRecordsBackgroundSave +
-            ' records in the process. Finished after ' +
-            totalTimeBackgroundSave +
-            ' miliseconds.'
-        );
-      }
-    };
-
-    const callback = function() {
-      showLogsForBackgroundProcesses();
-      OB.info(
-        '[sdrefresh] Finished loading models ' +
-          (incremental ? 'incrementally' : 'full') +
-          '.' +
-          (background ? ' (' + background + ' )' : '')
-      );
-      parentCallback();
-    };
-
-    if (OB.MobileApp.model.get('loggedOffline')) {
-      if (parentCallback instanceof Function) {
-        parentCallback();
-      }
-      return;
-    }
-
-    if (OB.UTIL.isNullOrUndefined(windows) || windows.length === 0) {
-      windows = [];
-      _.each(this.windowRegistry.registeredWindows, function(windowp) {
-        windows.push(windowp);
-      });
-    }
-
-    OB.info(
-      '[sdrefresh] Load models ' +
-        (incremental ? 'incrementally' : 'full') +
-        '.' +
-        (background ? ' (' + background + ' )' : '')
-    );
-    initLogParamsForBackgroundProcesses();
-
-    for (i = 0; i < windows.length; i++) {
-      windowClass = windows[i].windowClass;
-      windowName = windows[i].route;
-      if (OB && OB.DATA && OB.DATA[windowName]) {
-        // old way of defining datasources...
-        windowDatasources = OB.DATA[windowName];
-      } else if (
-        windowClass.prototype &&
-        windowClass.prototype.windowmodel &&
-        windowClass.prototype.windowmodel.prototype &&
-        windowClass.prototype.windowmodel.prototype.models
-      ) {
-        windowDatasources = windowClass.prototype.windowmodel.prototype.models;
-      } else if (typeof windowClass === 'string') {
-        w = window; // global window
-        path = windowClass.split('.');
-        for (c = 0; c < path.length; c++) {
-          w = w[path[c]];
-        }
-
-        if (
-          w.prototype &&
-          w.prototype.windowmodel &&
-          w.prototype.windowmodel.prototype &&
-          w.prototype.windowmodel.prototype.models
-        ) {
-          windowDatasources = w.prototype.windowmodel.prototype.models;
-        }
-      }
-
-      for (j = 0; j < windowDatasources.length; j++) {
-        if (datasources.indexOf(windowDatasources[j]) === -1) {
-          datasources.push(windowDatasources[j]);
-        }
-      }
-    }
-
-    _.extend(datasources, Backbone.Events);
-    OB.Dal.Datasources = datasources;
-
-    OB.debug(
-      '[sdrefresh] window: ' +
-        windowName +
-        (background ? '. (' + background + ' )' : '')
-    );
-
-    OB.Dal.loadModels(
-      false,
-      datasources,
-      null,
-      incremental,
-      callback,
-      background
-    );
-
-    this.postLoadModels();
-  },
-  postLoadModels: function() {},
-
-  cleanWindows: function() {
-    this.windows = new (Backbone.Collection.extend({
-      comparator: function(window) {
-        // sorts by menu position, 0 if not defined
-        var position = window.get('menuPosition');
-        return position ? position : 0;
-      }
-    }))();
-  },
-
-  registerWindow: function(window) {
-    this.windowRegistry.registerWindow(window);
-  },
-
-  /**
-   * Iterates over all registered windows loading their models
-   */
-  loadRegisteredWindows: function(callback) {
-    var me = this;
-    var func_handleRouting = function(windowName, params) {
-      //TODO default route
-      var defaultRoute = OB.MobileApp.model.get('defaultWindow');
-      //Find dest window
-      var destinationWindow = _.find(
-        OB.MobileApp.windowRegistry.registeredWindows,
-        function(win) {
-          return win.route === windowName;
-        }
-      );
-      //Check if destination window is valid. If not navigate to main window
-      if (OB.UTIL.isNullOrUndefined(destinationWindow)) {
-        OB.MobileApp.model.navigate(defaultRoute);
-      }
-      //If destination window has permission, check if user is allowed to navigate
-      //if not, navigate to main window
-      if (destinationWindow.permission) {
-        if (!OB.MobileApp.model.hasPermission(destinationWindow.permission)) {
-          OB.UTIL.showConfirmation.display(
-            OB.I18N.getLabel('OBMOBC_NotAllowed'),
-            OB.I18N.getLabel('OBMOBC_AccessNotAllowed', [
-              destinationWindow.permission
-            ]),
-            null,
-            {
-              onHideFunction: function() {
-                OB.MobileApp.model.navigate(defaultRoute);
-              }
-            }
-          );
-          return;
-        }
-      }
-
-      //Execute hook -> OBMOBC_PreWindowNavigate
-      OB.UTIL.HookManager.executeHooks(
-        'OBMOBC_PreWindowNavigate',
-        {
-          window: destinationWindow,
-          route: destinationWindow.route,
-          params: params
-        },
-        function(args) {
-          if (args && args.cancellation && args.cancellation === true) {
-            if (args.forceLogout) {
-              OB.MobileApp.model.logout();
-            } else {
-              OB.MobileApp.model.navigate(defaultRoute);
-            }
-            return;
-          }
-
-          if (args.window && args.window.navigateTo) {
-            args.window.navigateTo(
-              args,
-              function() {
-                me.renderGenericWindow(args.route, params);
-              },
-              function() {
-                OB.MobileApp.model.navigate(defaultRoute);
-              }
-            );
-          } else if (args.route) {
-            me.renderGenericWindow(args.route, params);
-          }
-        }
-      );
-    };
-
-    OB.debug('next process: renderMain');
-
-    this.cleanWindows();
-    OB.MobileApp.model.set('modelsToLoad', []);
-
-    if (
-      OB.MobileApp.model.get('permissions') &&
-      (OB.MobileApp.model.hasPermission(
-        'OBMOBC_EnableTerminalLogUserActions',
-        true
-      ) ||
-        OB.MobileApp.model.hasPermission(
-          'OBMOBC_EnableTerminalLogProcess',
-          true
-        ))
-    ) {
-      OB.UTIL.TerminalLog.activateTerminalLogSync();
-    } else {
-      OB.info(
-        'Terminal log is disabled because both preferences (OBMOBC_EnableTerminalLogUserActions and OBMOBC_EnableTerminalLogProcess) are set to false.'
-      );
-    }
-
-    var countOfLoadedWindows = 0;
-    var registeredWindows = this.windowRegistry.registeredWindows;
-    _.each(
-      registeredWindows,
-      function(windowp) {
-        var windowName = windowp.route;
-
-        this.windows.add(windowp);
-
-        this.router.route(windowName, windowName, function() {
-          func_handleRouting(windowName);
-        });
-
-        this.router.route(windowName + '/:params', windowName, function(
-          params
-        ) {
-          func_handleRouting(windowName, params);
-        });
-        countOfLoadedWindows += 1;
-      },
-      this
-    );
-    // checks if the windows loaded are more than the windows registered, which never should happen
-    var countOfRegisteredWindows = this.windowRegistry.registeredWindows.length;
-    OB.assert(
-      countOfRegisteredWindows === countOfLoadedWindows,
-      'DEVELOPER: There are ' +
-        countOfRegisteredWindows +
-        ' registered windows but ' +
-        countOfLoadedWindows +
-        ' are being loaded'
-    );
-
-    if (OB.MobileApp.model.get('loggedOffline')) {
-      // If logged offline we skip the load of masterdata in the login
-      callback();
-      return;
-    }
-
-    const validateIncrementalRefreshModelsLoaded = function(isValidCallback) {
-      const failedModels = [
-        ...OB.App.MasterdataController.getFailedMasterdataModels(),
-        ...(OB.Dal.Datasources._failedModels || [])
-      ];
-      if (failedModels.length === 0) {
-        // All models have finished the incremental load process.
-        // We can safely set the POSLastIncRefresh timestamp now.
-        OB.UTIL.localStorage.setItem('POSLastIncRefresh', new Date().getTime());
-      }
-      isValidCallback();
-    };
-
-    const validateModelsLoaded = function(isValidCallback) {
-      const failedModels = [
-        ...OB.App.MasterdataController.getFailedMasterdataModels(),
-        ...(OB.Dal.Datasources._failedModels || [])
-      ];
-      if (failedModels.length > 0) {
-        // Remove all timestamp to force a full refresh
-        OB.UTIL.localStorage.removeItem('POSLastTotalRefresh');
-        OB.UTIL.localStorage.removeItem('POSLastIncRefresh');
-        _.forEach(failedModels, function(model) {
-          OB.UTIL.localStorage.removeItem('lastUpdatedTimestamp' + model);
-        });
-        OB.UTIL.showConfirmation.display(
-          OB.I18N.getLabel('OBMOBC_MasterDataErrorHeader'),
-          OB.I18N.getLabel('OBMOBC_MasterDataErrorBody', [
-            failedModels.join(', ')
-          ]) + OB.I18N.getLabel('OBMOBC_LoadingErrorBody'),
-          [
-            {
-              label: OB.I18N.getLabel('OBMOBC_Reload'),
-              action: function() {
-                window.location.reload();
-              }
-            }
-          ],
-          {
-            onShowFunction: function(popup) {
-              popup.$.headerCloseButton.hide();
-            },
-            autoDismiss: false,
-            showLoading: true
-          }
-        );
-      } else {
-        // At this point we can ensure that all models have loaded correctly.
-        // If we are performing a full refresh of the data, now we can set the POSLastTotalRefresh timestamp.
-        OB.UTIL.localStorage.setItem(
-          'POSLastTotalRefresh',
-          new Date().getTime()
-        );
-        //Data might be old, but it should be enough to work
-        isValidCallback();
-      }
-    };
-
-    const statusCallback = function statusFunction(model, offset, limit) {
-      if (offset === 0) {
-        OB.UTIL.completeLoadingStep();
-        OB.UTIL.showLoadingMessage(
-          OB.I18N.getLabel('OBMOBC_LoadingMessageModel', [model])
-        );
-      } else {
-        OB.UTIL.showLoadingMessage(
-          OB.I18N.getLabel('OBMOBC_LoadingMessageModelPage', [
-            model,
-            offset / limit + 1
-          ])
-        );
-      }
-    };
-
-    var terminalType =
-      OB.MobileApp.model.get('terminal') &&
-      OB.MobileApp.model.get('terminal').terminalType;
-    var minTotalRefresh,
-      minIncRefresh,
-      lastTotalRefresh,
-      lastIncRefresh,
-      now,
-      intervalTotal,
-      intervalInc;
-    if (terminalType) {
-      minTotalRefresh =
-        OB.MobileApp.model.get('terminal').terminalType
-          .minutestorefreshdatatotal *
-        60 *
-        1000;
-      minIncRefresh = OB.MobileApp.model.get('terminal').terminalType
-        .minutestorefreshdatainc;
-      lastTotalRefresh = OB.UTIL.localStorage.getItem('POSLastTotalRefresh');
-      lastIncRefresh = OB.UTIL.localStorage.getItem('POSLastIncRefresh');
-
-      // lastTotalRefresh should be used to set lastIncRefresh when it is null or minor.
-      if (lastIncRefresh === null) {
-        lastIncRefresh = lastTotalRefresh;
-      } else {
-        if (lastTotalRefresh > lastIncRefresh) {
-          lastIncRefresh = lastTotalRefresh;
-        }
-      }
-      minIncRefresh =
-        (minIncRefresh > 99999 ? 99999 : minIncRefresh) * 60 * 1000;
-    }
-    const doFullRefresh = function() {
-      me.loadModels(registeredWindows, false, () =>
-        OB.App.MasterdataController.fullMasterdataRefresh(statusCallback).then(
-          () => {
-            OB.UTIL.showLoadingMessage(
-              OB.I18N.getLabel('OBMOBC_ForcingRefreshOfLocalDatabase')
-            );
-            validateModelsLoaded(callback);
-          }
-        )
-      );
-    };
-    const doIncrementalRefresh = function() {
-      OB.App.MasterdataController.setReloadAppConfiguration(true);
-      me.loadModels(registeredWindows, true, () =>
-        OB.App.MasterdataController.incrementalMasterdataRefresh(
-          statusCallback
-        ).then(() => {
-          OB.UTIL.showLoadingMessage(
-            OB.I18N.getLabel('OBMOBC_ForcingRefreshOfLocalDatabase')
-          );
-          validateIncrementalRefreshModelsLoaded(callback);
-          OB.App.MasterdataController.setReloadAppConfiguration(false);
-        })
-      );
-    };
-    if (
-      (!minTotalRefresh && !minIncRefresh) ||
-      (!lastTotalRefresh && !lastIncRefresh)
-    ) {
-      // If no configuration of the masterdata loading has been done,
-      // or an initial load has not been done, then always do
-      // a total refresh during the login
-      OB.UTIL.showLoadingTitleMessage(
-        true,
-        'OBMOBC_LblLoadingFull',
-        'OBMOBC_LblLoadingFullMsg'
-      );
-      //It's time to do a full refresh
-      doFullRefresh();
-    } else {
-      now = new Date().getTime();
-      intervalTotal = lastTotalRefresh
-        ? now - lastTotalRefresh - minTotalRefresh
-        : 0;
-      intervalInc = lastIncRefresh ? now - lastIncRefresh - minIncRefresh : 0;
-      if (intervalTotal > 0) {
-        this.set('FullRefreshWasDone', true);
-
-        //It's time to do a full refresh
-        doFullRefresh();
-      } else {
-        if (
-          OB.MobileApp.model.hasPermission(
-            'OBMOBC_NotAutoLoadIncrementalAtLogin',
-            true
-          ) &&
-          OB.UTIL.isNullOrUndefined(this.get('forceLoadModelsOnLogin'))
-        ) {
-          if (
-            intervalInc >= 0 ||
-            OB.UTIL.localStorage.getItem('POSForceIncrementalRefresh')
-          ) {
-            if (OB.UTIL.localStorage.getItem('POSForceIncrementalRefresh')) {
-              OB.UTIL.localStorage.removeItem('POSForceIncrementalRefresh');
-            }
-            // incremental refresh
-            doIncrementalRefresh();
-          } else {
-            if (callback instanceof Function) {
-              // Call the callback directly in case incremental refresh is not required.
-              callback();
-            }
-          }
-        } else {
-          if (OB.UTIL.isNullOrUndefined(lastTotalRefresh)) {
-            this.set('FullRefreshWasDone', true);
-            //It's time to do a full refresh
-            doFullRefresh();
-          } else {
-            // incremental refresh
-            doIncrementalRefresh();
-          }
-        }
-      }
-      if (this.get('FullRefreshWasDone')) {
-        OB.UTIL.showLoadingTitleMessage(
-          true,
-          'OBMOBC_LblLoadingFull',
-          'OBMOBC_LblLoadingFullMsg'
-        );
-      } else {
-        OB.UTIL.showLoadingTitleMessage(true, 'OBMOBC_LblLoadingInc');
-      }
-    }
-  },
-
-  showFrozenPopUp: function() {
-    OB.UTIL.showConfirmation.display(
-      OB.I18N.getLabel('OBMOBC_BrowserTabHeader', [
-        OB.MobileApp.model.get('appName')
-      ]),
-      OB.I18N.getLabel('OBMOBC_BrowserTabBody', [
-        OB.MobileApp.model.get('appName')
-      ]),
-      [],
-      {
-        autoDismiss: false,
-        hideCloseButton: true,
-        closeOnEscKey: false
-      }
-    );
-  },
-
-  saveBrowserTabId: function() {
-    var me = this;
-    var browserTabId = OB.UTIL.get_UUID();
-    if (OB.MobileApp.model.get('terminal')) {
-      OB.MobileApp.model.get('terminal').browserTabId = browserTabId;
-    } else {
-      OB.MobileApp.model.browserTabId = browserTabId;
-    }
-    OB.UTIL.localStorage.setItem('browserTabId', browserTabId);
-
-    // When focus the browser tab
-    window.onfocus = function() {
-      var actualBrowserTabId = OB.MobileApp.model.get('terminal')
-        ? OB.MobileApp.model.get('terminal').browserTabId
-        : OB.MobileApp.model.browserTabId;
-      if (OB.UTIL.localStorage.getItem('browserTabId') !== actualBrowserTabId) {
-        OB.MobileApp.view.applicationLocked = true;
-        me.showFrozenPopUp();
-      }
-    };
-  },
-
-  isWindowOnline: function(route) {
-    var i, windows;
-    windows = this.windows.toArray();
-    for (i = 0; i < windows.length; i++) {
-      if (windows[i].get('route') === route) {
-        return windows[i].get('online');
-      }
-    }
-    return false;
-  },
-
-  renderGenericWindow: function(windowName, params) {
-    if (!OB.MobileApp.view.$.containerWindow) {
-      OB.UTIL.Debug.execute(function() {
-        OB.error('OB.MobileApp.view.$.containerWindow must be defined');
-      });
-      OB.MobileApp.model.loadingErrorsActions('renderGenericWindow I');
-      return;
-    }
-
-    OB.MobileApp.view.currentWindow = 'unknown';
-    OB.MobileApp.model.set('currentWindow', 'unknown');
-    OB.MobileApp.view.currentWindowState = 'unknown';
-    OB.MobileApp.model.set('currentWindowState', 'unknown');
-    OB.UTIL.showLoading(true);
-
-    var windowObject = this.windows.where({
-      route: windowName
-    })[0];
-    var windowClass = windowObject.get('windowClass');
-    OB.MobileApp.view.$.containerWindow.destroyComponents();
-    OB.MobileApp.view.$.containerWindow.createComponent({
-      kind: windowClass,
-      windowName: windowName,
-      classes: 'obUiTerminal-containerWindow-windowClass-generic',
-      params: params
-    });
-
-    //remove possible external classes
-    _.each(this.windows.models, function(win) {
-      if (win && win.get('containerCssClass')) {
-        if (OB.MobileApp.view.hasClass(win.get('containerCssClass'))) {
-          OB.MobileApp.view.removeClass(win.get('containerCssClass'));
-        }
-      }
-    });
-    //Add original css-class
-    if (!OB.MobileApp.view.hasClass('pos-container')) {
-      OB.MobileApp.view.addClass('pos-container');
-    }
-    //If window is overwritting container, remove original and put new one
-    if (windowObject && windowObject.get('containerCssClass')) {
-      if (windowObject.get('overwriteOriginalContainerCssClass')) {
-        OB.MobileApp.view.removeClass('pos-container');
-      }
-      OB.MobileApp.view.addClass(windowObject.get('containerCssClass'));
-    }
-
-    OB.MobileApp.view.currentWindow = windowName;
-    OB.MobileApp.model.set('currentWindow', windowName);
-  },
-
-  renderContainerWindow: function() {
-    OB.MobileApp.view.$.containerWindow.render();
-    OB.UTIL.showLoading(false);
-    OB.MobileApp.view.$.containerWindow.resized();
-
-    OB.UTIL.HookManager.executeHooks(
-      'OBPOS_AfterRenderContainerWindow',
-      {
-        context: OB.MobileApp.view.$.containerWindow,
-        window: OB.MobileApp.view.currentWindow,
-        parameters: OB.MobileApp.view.currentWindowParameters
-      },
-      function() {}
-    );
-  },
-
-  updateSession: async function(user, callback) {
-    // argument check
-    OB.UTIL.Debug.execute(function() {
-      if (!callback) {
-        throw 'This method requires a callback';
-      }
-    });
-    try {
-      const session = await OB.App.OfflineSession.activateSession(
-        user.get('id'),
-        OB.MobileApp.model.get('terminalName')
-      );
-
-      OB.MobileApp.model.set('session', session.id);
-      callback();
-    } catch (e) {
-      OB.error(
-        'updateSession: failed to save the existing session',
-        e,
-        arguments
-      );
-    }
-  },
-
-  /**
-   * This method is invoked when closing session, it is in charge
-   * of dealing with all stuff needed to close session. After it is
-   * done it MUST do triggerLogout
-   */
-  postCloseSession: function(session) {
-    OB.MobileApp.model.triggerLogout();
-  },
-
-  closeSession: async function() {
-    const sessionId = OB.MobileApp.model.get('session');
-    if (!this.get('supportsOffline') || !sessionId) {
-      OB.MobileApp.model.triggerLogout();
-      return;
-    }
-
-    try {
-      await OB.App.OfflineSession.closeSession(sessionId);
-    } catch (e) {
-      OB.error('closeSession', e);
-    }
-    OB.MobileApp.model.triggerLogout();
-  },
-
-  /**
-   * @deprecated Use PasswordHash.generateHash instead
-   */
-  generate_sha1: function(theString) {
-    return CryptoJS.enc.Hex.stringify(CryptoJS.SHA1(theString));
-  },
-
-  attemptToLoginOffline: async function() {
-    if (
-      !OB.MobileApp.model.get('isLoggingIn') &&
-      OB.UTIL.localStorage.getItem('POSSessionActive') === 'false'
-    ) {
-      OB.MobileApp.model.navigate('login');
-      return;
-    }
-    // If the user tries to login offline and exceeded the maximum of minutes offline, don't allow login
-    if (
-      !OB.UTIL.isNullOrUndefined(
-        OB.UTIL.localStorage.getItem('maxTimeInOffline')
-      )
-    ) {
-      if (
-        !OB.UTIL.isNullOrUndefined(
-          OB.UTIL.localStorage.getItem('lastSuccessfulOnlineRequest')
-        ) &&
-        new Date().getTime() -
-          OB.UTIL.localStorage.getItem('lastSuccessfulOnlineRequest') >=
-          OB.UTIL.localStorage.getItem('maxTimeInOffline') * 60 * 1000
-      ) {
-        OB.UTIL.showConfirmation.display(
-          OB.I18N.getLabel('OBMOBC_MaximumOfflineTimeExceeded_Title'),
-          OB.I18N.getLabel('OBMOBC_MaximumOfflineTimeExceeded_Message'),
-          [
-            {
-              isConfirmButton: true,
-              label: OB.I18N.getLabel('OBMOBC_LblOk'),
-              action: function() {
-                window.location.reload();
-              }
-            }
-          ],
-          {
-            onHideFunction: function() {
-              window.location.reload();
-            }
-          }
-        );
-        return;
-      }
-    }
-    if (!this.user) {
-      // Reloading page
-      // If the user tries to login offline and exceeded the maximum of minutes offline, don't allow login
-      if (
-        !OB.UTIL.isNullOrUndefined(
-          OB.UTIL.localStorage.getItem('offlineSessionTimeExpiration')
-        ) &&
-        !OB.UTIL.isNullOrUndefined(
-          OB.UTIL.localStorage.getItem('lastUserIdLogin')
-        )
-      ) {
-        if (
-          !OB.UTIL.isNullOrUndefined(
-            OB.UTIL.localStorage.getItem('lastSuccessfulOnlineRequest')
-          ) &&
-          new Date().getTime() -
-            OB.UTIL.localStorage.getItem('lastSuccessfulOnlineRequest') <
-            OB.UTIL.localStorage.getItem('offlineSessionTimeExpiration') *
-              60 *
-              1000
-        ) {
-          OB.MobileApp.model.set('windowRegistered', undefined);
-          OB.MobileApp.model.set('loggedOffline', true);
-
-          try {
-            const session = await OB.App.OfflineSession.getActiveSessionForUser(
-              OB.UTIL.localStorage.getItem('lastUserIdLogin')
-            );
-
-            if (!session) {
-              OB.warn(
-                'No active session for user with id ' +
-                  OB.UTIL.localStorage.getItem('lastUserIdLogin') +
-                  '. Navigating to login page'
-              );
-              OB.MobileApp.model.navigate('login');
-              return;
-            }
-
-            const user = await OB.App.OfflineSession.withId(session.userId);
-            if (user) {
-              this.usermodel = new OB.Model.User(user);
-              this.set('orgUserId', user.id);
-              this.renderTerminalMain();
-              return;
-            } else {
-              OB.UTIL.showConfirmation.display(
-                '',
-                OB.I18N.getLabel('OBMOBC_OfflinePasswordNotCorrect'),
-                null,
-                {
-                  onHideFunction: () => OB.MobileApp.model.navigate('login')
-                }
-              );
-              return;
-            }
-          } catch (e) {
-            OB.error('Error getting active sessions', e);
-          }
-        }
-      }
-      OB.MobileApp.model.navigate('login');
-      return;
-    }
-
-    OB.MobileApp.model.set('windowRegistered', undefined);
-    OB.MobileApp.model.set('loggedOffline', true);
-    OB.MobileApp.model.set('datasourceLoadFailed', false);
-
-    const user = await OB.App.OfflineSession.login(this.user, this.password);
-
-    if (user) {
-      // TODO: replace backbone model with new app state
-      this.usermodel = new OB.Model.User(user);
-      this.set('orgUserId', user.id);
-      this.updateSession(this.usermodel, () => {
-        OB.UTIL.localStorage.setItem('lastUserIdLogin', user.id);
-        OB.UTIL.localStorage.setItem('lastUserNameLogin', user.name);
-        OB.UTIL.localStorage.setItem('lastLogInDate', new Date().getTime());
-        this.renderTerminalMain();
-      });
-    } else {
-      OB.UTIL.showConfirmation.display(
-        '',
-        OB.I18N.getLabel('OBMOBC_OfflinePasswordNotCorrect'),
-        null,
-        {
-          onHideFunction: function() {
-            window.location.reload();
-          }
-        }
-      );
-    }
-  },
-
-  postLoginActions: function() {
-    OB.debug('next process: none');
-  },
-
-  /**
-   * Prelogin actions is executed before login, it should take care of
-   * removing all session values specific by application.
-   *
-   * Override this in case you app needs to do something special
-   */
-  preLoginActions: function() {
-    OB.debug('next process: none. set your application start point here');
-  },
-
-  login: function(user, password, mode, command) {
-    OB.info('isLoggingIn ' + this.get('isLoggingIn'));
-    if (this.get('isLoggingIn') === true) {
-      OB.UTIL.Debug.execute(function() {
-        throw 'There is already a logging process in progress';
-      });
-      return;
-    }
-    this.set('isLoggingIn', true);
-
-    var params;
-    OB.info('Login loading');
-    OB.UTIL.showLoading(true);
-    var me = this;
-    me.user = user;
-    me.password = password;
-
-    // invoking app specific actions
-    this.preLoginActions();
-
-    params = JSON.parse(JSON.stringify(this.get('loginUtilsParams'))) || {};
-    params.user = user;
-    params.password = password;
-    params.Command = command ? command : 'DEFAULT';
-    if (params.Command === 'FORCE_RESET_PASSWORD') {
-      params.resetPassword = true;
-    }
-    params.IsAjaxCall = 1;
-    params.appName = this.get('appName');
-
-    var rr,
-      ajaxRequest = new enyo.Ajax({
-        url: this.get('loginHandlerUrl'),
-        cacheBust: false,
-        method: 'POST',
-        timeout: 5000,
-        // don't do retries as this gives side effects as re-showing login page
-        maxNumOfRequestRetries: 0,
-        contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
-        data: params,
-        success: function(inSender, inResponse) {
-          OB.info('loginHandlerUrl success');
-          if (this.alreadyProcessed) {
-            OB.info('loginHandlerUrl alreadyProcessed');
-            return;
-          }
-          this.alreadyProcessed = true;
-          if (inResponse && inResponse.sourceVersion) {
-            OB.UTIL.sourceVersionFromResponse = inResponse.sourceVersion;
-            OB.UTIL.checkSourceVersion(inResponse.sourceVersion, true, false);
-          }
-          if (OB.MobileApp.model.get('timeoutWhileLogin')) {
-            OB.info('loginHandlerUrl timeoutWhileLogin');
-            OB.MobileApp.model.set('timeoutWhileLogin', false);
-            return;
-          }
-          if (inResponse && inResponse.showMessage) {
-            if (inResponse.command === 'FORCE_NAMED_USER') {
-              OB.UTIL.showConfirmation.display(
-                inResponse.messageTitle,
-                inResponse.messageText,
-                [
-                  {
-                    label: OB.I18N.getLabel('OBMOBC_LblOk'),
-                    action: function() {
-                      OB.MobileApp.model.set('isLoggingIn', false);
-                      OB.MobileApp.model.login(
-                        user,
-                        password,
-                        mode,
-                        'FORCE_NAMED_USER'
-                      );
-                      return;
-                    }
-                  },
-                  {
-                    label: OB.I18N.getLabel('OBMOBC_LblCancel'),
-                    action: function() {
-                      OB.MobileApp.model.set('isLoggingIn', false);
-                      return;
-                    }
-                  }
-                ],
-                {
-                  autoDismiss: false
-                }
-              );
-              return;
-            } else if (inResponse.resetPassword) {
-              OB.UTIL.showLoading(false);
-              this.dialog = OB.MobileApp.view.$.confirmationContainer.createComponent(
-                {
-                  kind: 'OB.UI.ExpirationPassword',
-                  classes:
-                    'obUiTerminal-confirmationContainer-obUiExpirationPassword',
-                  context: this
-                }
-              );
-              this.dialog.show();
-
-              if (inResponse.attemptedChange) {
-                this.dialog.$.body.$.error.setContent(inResponse.messageText);
-              } else {
-                this.dialog.$.body.$.newheader.setContent(
-                  inResponse.messageTitle
-                );
-              }
-
-              return;
-            } else {
-              me.triggerLoginFail(401, mode, inResponse);
-              return;
-            }
-          }
-          if (
-            OB.MobileApp.model.get('terminalName') &&
-            !OB.UTIL.localStorage.getItem('loggedTerminalName')
-          ) {
-            OB.UTIL.localStorage.setItem(
-              'loggedTerminalName',
-              OB.MobileApp.model.get('terminalName')
-            );
-          }
-          if (
-            (!OB.UTIL.isNullOrUndefined(
-              OB.MobileApp.model.get('terminalName')
-            ) ||
-              !OB.UTIL.isNullOrUndefined(
-                OB.UTIL.localStorage.getItem('loggedTerminalName')
-              )) &&
-            OB.MobileApp.model.get('terminalName') !==
-              OB.UTIL.localStorage.getItem('loggedTerminalName')
-          ) {
-            OB.info(
-              'Terminal has been changed. Resetting database and local storage information.'
-            );
-            OB.UTIL.localStorage.clear(function() {
-              OB.MobileApp.model.logout();
-              return;
-            });
-          } else {
-            OB.MobileApp.model.set('orgUserId', inResponse.userId);
-            OB.UTIL.localStorage.setItem('lastUserIdLogin', inResponse.userId);
-            OB.UTIL.localStorage.setItem('lastUserNameLogin', me.user);
-            OB.UTIL.localStorage.setItem('lastLogInDate', new Date().getTime());
-            OB.UTIL.localStorage.setItem('POSSessionActive', true);
-            me.set('loggedOffline', false);
-            var setUserModelOnlineCallback = function() {
-              me.initializeCommonComponents();
-            };
-            if (me.get('supportsOffline')) {
-              me.setUserModelOnline(setUserModelOnlineCallback);
-            } else {
-              setUserModelOnlineCallback();
-            }
-          }
-        },
-        fail: function(inSender, inResponse) {
-          OB.info('loginHandlerUrl fail');
-          var lastTotalRefresh, lastIncRefresh;
-          if (this.alreadyProcessed) {
-            return;
-          }
-          this.alreadyProcessed = true;
-          lastTotalRefresh = OB.UTIL.localStorage.getItem(
-            'POSLastTotalRefresh'
-          );
-          lastIncRefresh = OB.UTIL.localStorage.getItem('POSLastIncRefresh');
-          if (!lastTotalRefresh && !lastIncRefresh) {
-            //There hasn't been a complete login yet, so we can't allow to login offline.
-            var msg =
-              OB.I18N.getLabel('OBMOBC_OfflineModeNoLogin') +
-              OB.I18N.getLabel('OBMOBC_LoadingErrorBody');
-            OB.UTIL.showConfirmation.display(
-              OB.I18N.getLabel('OBMOBC_Error'),
-              msg,
-              [
-                {
-                  label: OB.I18N.getLabel('OBMOBC_Reload'),
-                  action: function() {
-                    window.location.reload();
-                  }
-                }
-              ],
-              {
-                onShowFunction: function(popup) {
-                  OB.UTIL.localStorage.removeItem(
-                    'cacheAvailableForUser:' +
-                      OB.MobileApp.model.get('orgUserId')
-                  );
-                  popup.$.headerCloseButton.hide();
-                },
-                autoDismiss: false,
-                showLoading: true
-              }
-            );
-          } else {
-            me.attemptToLoginOffline();
-          }
-        }
-      });
-    rr = new OB.RR.Request({
-      ajaxRequest: ajaxRequest
-    });
-    OB.info('loginHandlerUrl request');
-    rr.exec(this.get('loginHandlerUrl'));
-  },
-
-  setUserModelOnline: function(callback) {
-    OB.debug('next process:', callback);
-    // argument checks
-    OB.UTIL.Debug.execute(function() {
-      if (!callback) {
-        throw 'This method should not be executed asynchronously. Please provide a callback';
-      }
-    });
-
-    const user = {
-      id: OB.MobileApp.model.get('orgUserId'),
-      name: this.user,
-      formatInfo: JSON.stringify(OB.Format)
-    };
-
-    OB.App.OfflineSession.upsertUser(user, this.password).then(
-      dbUser => {
-        // TODO: replace backbone model with new app state
-        const backboneUser = new OB.Model.User(dbUser);
-        this.usermodel = backboneUser;
-        this.updateSession(backboneUser, callback);
-      },
-
-      error => {
-        OB.error('setUserModelOnline', error, arguments);
-      }
-    );
-  },
-
-  /**
-   * Set of app specific actions executed before loging out.
-   *
-   *  Override this method if your app needs to do something special
-   */
-  preLogoutActions: function(callback) {
-    callback();
-  },
-
-  logout: function() {
-    var me = this;
-
-    function callback() {
-      OB.UTIL.showLoggingOut(true);
-
-      var rr,
-        ajaxRequest = new enyo.Ajax({
-          url: '../../org.openbravo.mobile.core.logout',
-          cacheBust: false,
-          method: 'GET',
-          handleAs: 'json',
-          timeout: 20000,
-          contentType: 'application/json;charset=utf-8',
-          success: function(inSender, inResponse) {
-            me.closeSession();
-          },
-          fail: function(inSender, inResponse) {
-            me.closeSession();
-          }
-        });
-      rr = new OB.RR.Request({
-        ajaxRequest: ajaxRequest
-      });
-      rr.exec(ajaxRequest.url);
-    }
-
-    this.preLogoutActions(function() {
-      OB.App.SynchronizationBuffer.internalFlush()
-        .then(() => {
-          return OB.App.State.persistence.stateStorePersistor.flush();
-        })
-        .then(() => {
-          callback();
-        });
-    });
-  },
-
-  lock: function() {
-    var me = this;
-
-    if (OB && OB.POS && OB.POS.hwserver !== undefined) {
-      OB.POS.hwserver.print(
-        new OB.DS.HWResource(OB.OBPOSPointOfSale.Print.GoodByeTemplate),
-        {}
-      );
-    }
-
-    function callback() {
-      var rr,
-        ajaxRequest = new enyo.Ajax({
-          url: '../../org.openbravo.mobile.core.logout',
-          cacheBust: false,
-          method: 'GET',
-          handleAs: 'json',
-          timeout: 20000,
-          contentType: 'application/json;charset=utf-8',
-          success: function(inSender, inResponse) {
-            me.triggerLogout();
-          },
-          fail: function(inSender, inResponse) {
-            me.triggerLogout();
-          }
-        });
-      rr = new OB.RR.Request({
-        ajaxRequest: ajaxRequest
-      });
-      rr.exec(ajaxRequest.url);
-    }
-
-    OB.App.SynchronizationBuffer.internalFlush()
-      .then(() => {
-        return OB.App.State.persistence.stateStorePersistor.flush();
-      })
-      .then(() => {
-        callback();
-      });
-  },
-
-  keepWorking: function() {
-    this.set('keepWorking', true);
-  },
-
-  isKeepWorking: function() {
-    return this.get('keepWorking');
-  },
-
-  triggerLogout: function() {
-    // deactivate the loginfail trigger
-    this.off('loginfail');
-
-    // trigger for custom applications
-    this.trigger('logout');
-
-    OB.UTIL.localStorage.setItem('POSSessionActive', false);
-
-    window.location.reload();
-  },
-
-  triggerLoginSuccess: function() {
-    this.trigger('loginsuccess');
-  },
-
-  triggerOnLine: function() {
-    // using "internal" setOnline function of backend server
-    // we are doing it to keep calls to "OB.MobileApp.model.triggerOnLine" working
-    OB.App.RemoteServerController.getRemoteServer('BackendServer').setOnline();
-  },
-
-  triggerOffLine: function() {
-    // using "internal" setOffline function of backend server
-    // we are doing it to keep calls to "OB.MobileApp.model.triggerOffLine" working
-    OB.App.RemoteServerController.getRemoteServer('BackendServer').setOffline();
-  },
-
-  triggerLoginFail: function(e, mode, data) {
-    OB.UTIL.showLoading(false);
-    if (mode === 'userImgPress') {
-      this.trigger('loginUserImgPressfail', e);
-    } else {
-      this.trigger('loginfail', e, data);
-    }
-    this.set('isLoggingIn', false);
-  },
-
-  hasPermission: function(p, checkForAutomaticRoles, smartDbPrefix) {
-    var permission;
-    var dbPrefix;
-    var separator = '_';
-    var resolvedPreference;
-    permission = p.approval ? p.approval : p;
-
-    //This code will get the preference based on the app
-    if (smartDbPrefix === true) {
-      dbPrefix = OB.MobileApp.model.get('appModulePrefix');
-      if (dbPrefix) {
-        resolvedPreference = dbPrefix + separator + permission;
-        if (
-          this.get('permissions') &&
-          this.get('permissions')[resolvedPreference] !== null &&
-          this.get('permissions')[resolvedPreference] !== undefined
-        ) {
-          permission = resolvedPreference;
-        } else {
-          resolvedPreference = dbPrefix + permission;
-          if (
-            this.get('permissions') &&
-            this.get('permissions')[resolvedPreference] !== null &&
-            this.get('permissions')[resolvedPreference] !== undefined
-          ) {
-            permission = resolvedPreference;
-          } else {
-            return false;
-          }
-        }
-      } else {
-        return false;
-      }
-    }
-
-    return (
-      (!checkForAutomaticRoles &&
-        !(this.get('context') && this.get('context').role.manual)) ||
-      (this.get('permissions') && this.get('permissions')[permission])
-    );
-  },
-
-  supportLogClient: function() {
-    var supported = true;
-    if (
-      (OB.MobileApp &&
-        OB.MobileApp.model &&
-        OB.MobileApp.model.get('supportsOffline')) === false
-    ) {
-      supported = false;
-    }
-    return supported;
-  }
-});
