diff --git a/src-db/database/sourcedata/AD_MESSAGE.xml b/src-db/database/sourcedata/AD_MESSAGE.xml
--- a/src-db/database/sourcedata/AD_MESSAGE.xml
+++ b/src-db/database/sourcedata/AD_MESSAGE.xml
@@ -447,6 +447,18 @@
 <!--4125E049FC3942C39597DA7AAE82FC8C-->  <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N>
 <!--4125E049FC3942C39597DA7AAE82FC8C--></AD_MESSAGE>
 
+<!--441A964522074E10BA95E9417DF83455--><AD_MESSAGE>
+<!--441A964522074E10BA95E9417DF83455-->  <AD_MESSAGE_ID><![CDATA[441A964522074E10BA95E9417DF83455]]></AD_MESSAGE_ID>
+<!--441A964522074E10BA95E9417DF83455-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--441A964522074E10BA95E9417DF83455-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--441A964522074E10BA95E9417DF83455-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--441A964522074E10BA95E9417DF83455-->  <VALUE><![CDATA[OBMOBC_TransactionFailedTitle]]></VALUE>
+<!--441A964522074E10BA95E9417DF83455-->  <MSGTEXT><![CDATA[Transaction Failed]]></MSGTEXT>
+<!--441A964522074E10BA95E9417DF83455-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--441A964522074E10BA95E9417DF83455-->  <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID>
+<!--441A964522074E10BA95E9417DF83455-->  <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N>
+<!--441A964522074E10BA95E9417DF83455--></AD_MESSAGE>
+
 <!--44E2FBBC2D3C4B43B4A28D993C743297--><AD_MESSAGE>
 <!--44E2FBBC2D3C4B43B4A28D993C743297-->  <AD_MESSAGE_ID><![CDATA[44E2FBBC2D3C4B43B4A28D993C743297]]></AD_MESSAGE_ID>
 <!--44E2FBBC2D3C4B43B4A28D993C743297-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
@@ -663,6 +675,18 @@
 <!--5DB7BD0ABD15432FB907215C3A16D2BF-->  <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N>
 <!--5DB7BD0ABD15432FB907215C3A16D2BF--></AD_MESSAGE>
 
+<!--60099D85E7F743C9888C79501C2B2689--><AD_MESSAGE>
+<!--60099D85E7F743C9888C79501C2B2689-->  <AD_MESSAGE_ID><![CDATA[60099D85E7F743C9888C79501C2B2689]]></AD_MESSAGE_ID>
+<!--60099D85E7F743C9888C79501C2B2689-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--60099D85E7F743C9888C79501C2B2689-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--60099D85E7F743C9888C79501C2B2689-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--60099D85E7F743C9888C79501C2B2689-->  <VALUE><![CDATA[OBMOBC_TransactionFailed]]></VALUE>
+<!--60099D85E7F743C9888C79501C2B2689-->  <MSGTEXT><![CDATA[The transaction failed on the server, change your input or try again. Detailed error message: %0]]></MSGTEXT>
+<!--60099D85E7F743C9888C79501C2B2689-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--60099D85E7F743C9888C79501C2B2689-->  <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID>
+<!--60099D85E7F743C9888C79501C2B2689-->  <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N>
+<!--60099D85E7F743C9888C79501C2B2689--></AD_MESSAGE>
+
 <!--609E83AFE22040819F66D76230246225--><AD_MESSAGE>
 <!--609E83AFE22040819F66D76230246225-->  <AD_MESSAGE_ID><![CDATA[609E83AFE22040819F66D76230246225]]></AD_MESSAGE_ID>
 <!--609E83AFE22040819F66D76230246225-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
@@ -1047,6 +1071,18 @@
 <!--9925F9856B92417CA4119158FDA68B12-->  <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N>
 <!--9925F9856B92417CA4119158FDA68B12--></AD_MESSAGE>
 
+<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50--><AD_MESSAGE>
+<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50-->  <AD_MESSAGE_ID><![CDATA[9C0ACBDEB67E4C9582BDA8BEC7C8BC50]]></AD_MESSAGE_ID>
+<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50-->  <VALUE><![CDATA[OBMOBC_ProcessingTransaction]]></VALUE>
+<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50-->  <MSGTEXT><![CDATA[Your transaction is being processed on the server.]]></MSGTEXT>
+<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50-->  <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID>
+<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50-->  <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N>
+<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50--></AD_MESSAGE>
+
 <!--9C1E55F357A14DCCAECA6A0A2CCB62FA--><AD_MESSAGE>
 <!--9C1E55F357A14DCCAECA6A0A2CCB62FA-->  <AD_MESSAGE_ID><![CDATA[9C1E55F357A14DCCAECA6A0A2CCB62FA]]></AD_MESSAGE_ID>
 <!--9C1E55F357A14DCCAECA6A0A2CCB62FA-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
@@ -1059,6 +1095,18 @@
 <!--9C1E55F357A14DCCAECA6A0A2CCB62FA-->  <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N>
 <!--9C1E55F357A14DCCAECA6A0A2CCB62FA--></AD_MESSAGE>
 
+<!--9C3E5839CE344A16A8B1F9D119BDC116--><AD_MESSAGE>
+<!--9C3E5839CE344A16A8B1F9D119BDC116-->  <AD_MESSAGE_ID><![CDATA[9C3E5839CE344A16A8B1F9D119BDC116]]></AD_MESSAGE_ID>
+<!--9C3E5839CE344A16A8B1F9D119BDC116-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--9C3E5839CE344A16A8B1F9D119BDC116-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--9C3E5839CE344A16A8B1F9D119BDC116-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--9C3E5839CE344A16A8B1F9D119BDC116-->  <VALUE><![CDATA[OBMOBC_ProcessingTransactionTitle]]></VALUE>
+<!--9C3E5839CE344A16A8B1F9D119BDC116-->  <MSGTEXT><![CDATA[Processing Transaction]]></MSGTEXT>
+<!--9C3E5839CE344A16A8B1F9D119BDC116-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--9C3E5839CE344A16A8B1F9D119BDC116-->  <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID>
+<!--9C3E5839CE344A16A8B1F9D119BDC116-->  <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N>
+<!--9C3E5839CE344A16A8B1F9D119BDC116--></AD_MESSAGE>
+
 <!--9D1EB89366C2466F9E06097F98BB9DDD--><AD_MESSAGE>
 <!--9D1EB89366C2466F9E06097F98BB9DDD-->  <AD_MESSAGE_ID><![CDATA[9D1EB89366C2466F9E06097F98BB9DDD]]></AD_MESSAGE_ID>
 <!--9D1EB89366C2466F9E06097F98BB9DDD-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
diff --git a/src-db/database/sourcedata/AD_REF_LIST.xml b/src-db/database/sourcedata/AD_REF_LIST.xml
--- a/src-db/database/sourcedata/AD_REF_LIST.xml
+++ b/src-db/database/sourcedata/AD_REF_LIST.xml
@@ -187,6 +187,18 @@
 <!--80AB4F4D0FBE4352BF331C2F4467F819-->  <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID>
 <!--80AB4F4D0FBE4352BF331C2F4467F819--></AD_REF_LIST>
 
+<!--86A147DD51D041729DDD7EFD12C54B1C--><AD_REF_LIST>
+<!--86A147DD51D041729DDD7EFD12C54B1C-->  <AD_REF_LIST_ID><![CDATA[86A147DD51D041729DDD7EFD12C54B1C]]></AD_REF_LIST_ID>
+<!--86A147DD51D041729DDD7EFD12C54B1C-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--86A147DD51D041729DDD7EFD12C54B1C-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--86A147DD51D041729DDD7EFD12C54B1C-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--86A147DD51D041729DDD7EFD12C54B1C-->  <VALUE><![CDATA[OBMOBC_SynchronizedData]]></VALUE>
+<!--86A147DD51D041729DDD7EFD12C54B1C-->  <NAME><![CDATA[Synchronized Data]]></NAME>
+<!--86A147DD51D041729DDD7EFD12C54B1C-->  <DESCRIPTION><![CDATA[Common message containing several actions which are to be executed synchronized]]></DESCRIPTION>
+<!--86A147DD51D041729DDD7EFD12C54B1C-->  <AD_REFERENCE_ID><![CDATA[11F86B630ECB4A57B28927193F8AB99D]]></AD_REFERENCE_ID>
+<!--86A147DD51D041729DDD7EFD12C54B1C-->  <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID>
+<!--86A147DD51D041729DDD7EFD12C54B1C--></AD_REF_LIST>
+
 <!--92882D283E614160A1BEE6DB99A354BE--><AD_REF_LIST>
 <!--92882D283E614160A1BEE6DB99A354BE-->  <AD_REF_LIST_ID><![CDATA[92882D283E614160A1BEE6DB99A354BE]]></AD_REF_LIST_ID>
 <!--92882D283E614160A1BEE6DB99A354BE-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
@@ -316,6 +328,18 @@
 <!--D7110BA3D93D4EC693E27F867B196A24-->  <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID>
 <!--D7110BA3D93D4EC693E27F867B196A24--></AD_REF_LIST>
 
+<!--E279FC43FF7540A9881519B81C15E8C4--><AD_REF_LIST>
+<!--E279FC43FF7540A9881519B81C15E8C4-->  <AD_REF_LIST_ID><![CDATA[E279FC43FF7540A9881519B81C15E8C4]]></AD_REF_LIST_ID>
+<!--E279FC43FF7540A9881519B81C15E8C4-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--E279FC43FF7540A9881519B81C15E8C4-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--E279FC43FF7540A9881519B81C15E8C4-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--E279FC43FF7540A9881519B81C15E8C4-->  <VALUE><![CDATA[OBMOBC_SynchronizedMode]]></VALUE>
+<!--E279FC43FF7540A9881519B81C15E8C4-->  <NAME><![CDATA[WebPOS Synchronized Mode]]></NAME>
+<!--E279FC43FF7540A9881519B81C15E8C4-->  <DESCRIPTION><![CDATA[Determines if webpos is run in synchronized mode]]></DESCRIPTION>
+<!--E279FC43FF7540A9881519B81C15E8C4-->  <AD_REFERENCE_ID><![CDATA[A26BA480E2014707B47257024C3CBFF7]]></AD_REFERENCE_ID>
+<!--E279FC43FF7540A9881519B81C15E8C4-->  <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID>
+<!--E279FC43FF7540A9881519B81C15E8C4--></AD_REF_LIST>
+
 <!--E2E70AA926FA43EFB24014784724AA88--><AD_REF_LIST>
 <!--E2E70AA926FA43EFB24014784724AA88-->  <AD_REF_LIST_ID><![CDATA[E2E70AA926FA43EFB24014784724AA88]]></AD_REF_LIST_ID>
 <!--E2E70AA926FA43EFB24014784724AA88-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
diff --git a/src-db/database/sourcedata/OBMOBC_SERVICES.xml b/src-db/database/sourcedata/OBMOBC_SERVICES.xml
--- a/src-db/database/sourcedata/OBMOBC_SERVICES.xml
+++ b/src-db/database/sourcedata/OBMOBC_SERVICES.xml
@@ -1,5 +1,16 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <data>
+<!--0C097F5EE22249758CA26F8CDF4C61F9--><OBMOBC_SERVICES>
+<!--0C097F5EE22249758CA26F8CDF4C61F9-->  <OBMOBC_SERVICES_ID><![CDATA[0C097F5EE22249758CA26F8CDF4C61F9]]></OBMOBC_SERVICES_ID>
+<!--0C097F5EE22249758CA26F8CDF4C61F9-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--0C097F5EE22249758CA26F8CDF4C61F9-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--0C097F5EE22249758CA26F8CDF4C61F9-->  <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID>
+<!--0C097F5EE22249758CA26F8CDF4C61F9-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--0C097F5EE22249758CA26F8CDF4C61F9-->  <SERVICE><![CDATA[org.openbravo.mobile.core.servercontroller.SynchronizedServerProcessCaller]]></SERVICE>
+<!--0C097F5EE22249758CA26F8CDF4C61F9-->  <DESCRIPTION><![CDATA[Is used as a fail over request for synchronized mode combining several requests in one call]]></DESCRIPTION>
+<!--0C097F5EE22249758CA26F8CDF4C61F9-->  <ROUTINGTYPE><![CDATA[Failover]]></ROUTINGTYPE>
+<!--0C097F5EE22249758CA26F8CDF4C61F9--></OBMOBC_SERVICES>
+
 <!--35BC4C9BE6624E76AE57395FD8AF11E4--><OBMOBC_SERVICES>
 <!--35BC4C9BE6624E76AE57395FD8AF11E4-->  <OBMOBC_SERVICES_ID><![CDATA[35BC4C9BE6624E76AE57395FD8AF11E4]]></OBMOBC_SERVICES_ID>
 <!--35BC4C9BE6624E76AE57395FD8AF11E4-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
diff --git a/src/org/openbravo/mobile/core/process/DataSynchronizationProcess.java b/src/org/openbravo/mobile/core/process/DataSynchronizationProcess.java
--- a/src/org/openbravo/mobile/core/process/DataSynchronizationProcess.java
+++ b/src/org/openbravo/mobile/core/process/DataSynchronizationProcess.java
@@ -37,6 +37,8 @@
 import org.openbravo.dal.core.TriggerHandler;
 import org.openbravo.dal.service.OBDal;
 import org.openbravo.dal.service.OBQuery;
+import org.openbravo.mobile.core.utils.OBMOBCUtils;
+import org.openbravo.service.db.DbUtility;
 import org.openbravo.service.importprocess.ImportEntryManager;
 import org.openbravo.service.importprocess.ImportProcessUtils;
 import org.openbravo.service.json.JsonConstants;
@@ -204,8 +206,10 @@
           }
           if (i % 1 == 0) {
             OBDal.getInstance().flush();
-            OBDal.getInstance().getConnection(false).commit();
-            OBDal.getInstance().getSession().clear();
+            if (!isRunInSynchronizedMode()) {
+              OBDal.getInstance().getConnection(false).commit();
+              OBDal.getInstance().getSession().clear();
+            }
           }
           log.debug("Total process " + this.getClass().getName() + " time: "
               + (System.currentTimeMillis() - t1));
@@ -218,6 +222,14 @@
             error = true;
           }
 
+          // in synched mode return the error to the caller
+          // don't do anything more
+          if (isRunInSynchronizedMode()) {
+            Throwable localThrowable = DbUtility.getUnderlyingSQLException(t);
+            log.error(localThrowable.getMessage(), localThrowable);
+            return OBMOBCUtils.createSimpleErrorJson(localThrowable.getMessage());
+          }
+
           // check if there is a record with the same id. If it exists it means that it is a
           // duplicated record. Then, this error will not be stored
           List<Object> parameters = new ArrayList<Object>();
diff --git a/src/org/openbravo/mobile/core/process/MobileService.java b/src/org/openbravo/mobile/core/process/MobileService.java
--- a/src/org/openbravo/mobile/core/process/MobileService.java
+++ b/src/org/openbravo/mobile/core/process/MobileService.java
@@ -15,14 +15,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Set;
 
-import javax.enterprise.inject.spi.Bean;
-import javax.enterprise.inject.spi.BeanManager;
 import javax.enterprise.util.AnnotationLiteral;
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletException;
@@ -33,7 +26,6 @@
 import org.codehaus.jettison.json.JSONArray;
 import org.codehaus.jettison.json.JSONException;
 import org.codehaus.jettison.json.JSONObject;
-import org.openbravo.base.session.OBPropertiesProvider;
 import org.openbravo.base.weld.WeldUtils;
 import org.openbravo.service.json.JsonUtils;
 import org.openbravo.service.web.InvalidRequestException;
@@ -51,12 +43,8 @@
 
   private static String SERVLET_PATH = "org.openbravo.mobile.core.service.jsonrest";
 
-  private boolean bypassImportEntry = false;
-
   public void init(ServletConfig config) {
     super.init(config);
-    bypassImportEntry = OBPropertiesProvider.getInstance().getBooleanProperty(
-        "import.bypass.entry.logic");
   }
 
   @Override
@@ -98,7 +86,7 @@
             // writer
             final Writer w = new StringWriter();
             w.write("{\"response\":{");
-            execServiceName(w, pathparts[1], (JSONObject) jsonsent);
+            new MobileServiceProcessor().execServiceName(w, pathparts[1], (JSONObject) jsonsent);
             w.write("}}");
             w.close();
 
@@ -163,7 +151,7 @@
 
     if (jsonsent.has("className")) {
       try {
-        execServiceName(w, jsonsent.getString("className"), jsonsent);
+        new MobileServiceProcessor().execServiceName(w, jsonsent.getString("className"), jsonsent);
       } catch (JSONException e) {
         JSONRowConverter.addJSONExceptionFields(w, e);
       } catch (ClassNotFoundException e) {
@@ -178,128 +166,6 @@
   }
 
   /**
-   * Executes the JSONProcess implementing the serviceName. The JSONProcesses are sorted by priority
-   * and each one can define if it is needed to call the next JSONProcess or not. The response
-   * writer is filled with the result of the last executed JSONProcess. Each JSONProcess can
-   * determine if the next class has to be executed.
-   * 
-   * @param w
-   *          Writer where the result is stored.
-   * @param serviceName
-   *          the name of the Mobile Service to execute.
-   * @param jsonsent
-   *          JSONObject with the Mobile Service input parameters.
-   * 
-   */
-  private void execServiceName(Writer w, String serviceName, JSONObject jsonsent) throws Exception {
-    List<? extends JSONProcess> processes = getServiceClassInstances(serviceName);
-    // Create a new writer for each process. Only write on the given writer the last execution
-    // result.
-    Writer tmpwriter = null;
-    int i = 0;
-    for (JSONProcess process : processes) {
-      i++;
-      tmpwriter = new StringWriter();
-      try {
-        execProcess(tmpwriter, process, jsonsent);
-      } catch (Exception e) {
-        if (processes.size() == i
-            || (process instanceof SecuredJSONProcess && !((SecuredJSONProcess) process)
-                .executeNextServiceClassOnFailure())) {
-          tmpwriter.close();
-          throw e;
-        }
-      }
-      tmpwriter.close();
-      if (!(process instanceof SecuredJSONProcess && ((SecuredJSONProcess) process)
-          .executeNextServiceClass())) {
-        break;
-      }
-    }
-    if (tmpwriter != null) {
-      w.write(tmpwriter.toString());
-    }
-  }
-
-  /**
-   * Executes a JSONProcess with the data sent in the JSONObject.
-   * 
-   * @param w
-   *          Writer where the result is stored.
-   * @param process
-   *          JSONProcess to execute.
-   * @param jsonsent
-   *          JSONObject with the process input parameters.
-   */
-  private void execProcess(Writer w, JSONProcess process, JSONObject jsonsent) throws IOException,
-      ServletException {
-
-    if (process instanceof SecuredJSONProcess) {
-      if (!bypassImportEntry && process instanceof DataSynchronizationImportProcess) {
-        ((DataSynchronizationImportProcess) process).executeCreateImportEntry(w, jsonsent);
-      } else {
-        ((SecuredJSONProcess) process).secureExec(w, jsonsent);
-      }
-    } else {
-      log.warn("Executing unsecure process " + process.getClass());
-      if (process instanceof DataSynchronizationImportProcess) {
-        ((DataSynchronizationImportProcess) process).executeCreateImportEntry(w, jsonsent);
-      } else {
-        process.exec(w, jsonsent);
-      }
-    }
-  }
-
-  /**
-   * Builds a sorted List of instances that implement the serviceName. The implementation is done
-   * using the MobileServiceClassSelector. To ensure backwards compatibility in case that exists a
-   * class with the same name than the service name and that it does not implement the
-   * MobileServiceClassSelector it is also added to the List.
-   * 
-   * @param serviceName
-   *          The Mobile Service name that is going to be executed.
-   * @return The sorted list of classes implementing the Mobile Service.
-   * @throws ClassNotFoundException
-   *           Exception thrown when no class implementing the service name is found.
-   */
-  private List<? extends JSONProcess> getServiceClassInstances(String serviceName)
-      throws ClassNotFoundException {
-    BeanManager bm = WeldUtils.getStaticInstanceBeanManager();
-    List<JSONProcess> processes = new ArrayList<JSONProcess>();
-    boolean isDefaultClassMissing = true;
-    Set<Bean<?>> beans = bm.getBeans(JSONProcess.class, WeldUtils.ANY_LITERAL,
-        new MobileServiceClassSelector(serviceName));
-    for (Bean<?> bean : beans) {
-      processes.add((JSONProcess) bm.getReference(bean, JSONProcess.class,
-          bm.createCreationalContext(bean)));
-      if (bean.getBeanClass().getName().equals(serviceName)) {
-        isDefaultClassMissing = false;
-      }
-    }
-    // If no bean with classname like the service name is added try to add to the list. This is
-    // added for backwards compatibility to include service classes that are not implementing the
-    // qualifier.
-    try {
-      if (isDefaultClassMissing) {
-        @SuppressWarnings("unchecked")
-        Class<JSONProcess> process = (Class<JSONProcess>) Class.forName(serviceName);
-        JSONProcess proc = WeldUtils.getInstanceFromStaticBeanManager(process);
-
-        processes.add(proc);
-      }
-    } catch (ClassNotFoundException ignore) {
-      // Only throw ClassNotFoundException if no JSONProcess is found implementing the service name.
-    }
-
-    if (processes.isEmpty()) {
-      throw new ClassNotFoundException();
-    }
-    Collections.sort(processes, new ServiceProcessComparator());
-
-    return processes;
-  }
-
-  /**
    * Executes the Procedure set in the jsonsent JSONObject.
    * 
    * @param w
@@ -340,21 +206,6 @@
     return pathParts;
   }
 
-  private static class ServiceProcessComparator implements Comparator<JSONProcess> {
-    private int getProcessPriority(JSONProcess proc) {
-      if (proc instanceof SecuredJSONProcess) {
-        return ((SecuredJSONProcess) proc).getPriority();
-      }
-      return 100;
-    }
-
-    @Override
-    public int compare(JSONProcess proc1, JSONProcess proc2) {
-      return getProcessPriority(proc1) - getProcessPriority(proc2);
-    }
-
-  }
-
   @javax.inject.Qualifier
   @Retention(RetentionPolicy.RUNTIME)
   @Target({ ElementType.TYPE })
diff --git a/src/org/openbravo/mobile/core/process/MobileServiceProcessor.java b/src/org/openbravo/mobile/core/process/MobileServiceProcessor.java
new file mode 100644
--- /dev/null
+++ b/src/org/openbravo/mobile/core/process/MobileServiceProcessor.java
@@ -0,0 +1,199 @@
+/*
+ ************************************************************************************
+ * Copyright (C) 2016 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.
+ ************************************************************************************
+ */
+package org.openbravo.mobile.core.process;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.servlet.ServletException;
+
+import org.apache.log4j.Logger;
+import org.codehaus.jettison.json.JSONObject;
+import org.openbravo.base.session.OBPropertiesProvider;
+import org.openbravo.base.weld.WeldUtils;
+
+/**
+ * A class which finds the implementation for a service and executes it.
+ * 
+ * @author mtaal
+ */
+public class MobileServiceProcessor {
+
+  private static final Logger log = Logger.getLogger(MobileServiceProcessor.class);
+
+  private boolean bypassImportEntry;
+  private boolean synchronizedMode;
+
+  public boolean isSynchronizedMode() {
+    return synchronizedMode;
+  }
+
+  public void setSynchronizedMode(boolean synchronizedMode) {
+    this.synchronizedMode = synchronizedMode;
+  }
+
+  public MobileServiceProcessor() {
+    bypassImportEntry = OBPropertiesProvider.getInstance().getBooleanProperty(
+        "import.bypass.entry.logic");
+  }
+
+  /**
+   * Executes the JSONProcess implementing the serviceName. The JSONProcesses are sorted by priority
+   * and each one can define if it is needed to call the next JSONProcess or not. The response
+   * writer is filled with the result of the last executed JSONProcess. Each JSONProcess can
+   * determine if the next class has to be executed.
+   * 
+   * @param w
+   *          Writer where the result is stored.
+   * @param serviceName
+   *          the name of the Mobile Service to execute.
+   * @param jsonsent
+   *          JSONObject with the Mobile Service input parameters.
+   * 
+   */
+  public void execServiceName(Writer w, String serviceName, JSONObject jsonsent) throws Exception {
+    List<? extends JSONProcess> processes = getServiceClassInstances(serviceName);
+
+    // Create a new writer for each process. Only write on the given writer the last execution
+    // result.
+    Writer tmpwriter = null;
+    int i = 0;
+    for (JSONProcess process : processes) {
+      i++;
+      tmpwriter = new StringWriter();
+      try {
+        execProcess(tmpwriter, process, jsonsent);
+      } catch (Exception e) {
+        if (processes.size() == i
+            || (process instanceof SecuredJSONProcess && !((SecuredJSONProcess) process)
+                .executeNextServiceClassOnFailure())) {
+          tmpwriter.close();
+          throw e;
+        }
+      }
+      tmpwriter.close();
+      if (!(process instanceof SecuredJSONProcess && ((SecuredJSONProcess) process)
+          .executeNextServiceClass())) {
+        break;
+      }
+    }
+    if (tmpwriter != null) {
+      w.write(tmpwriter.toString());
+    }
+  }
+
+  /**
+   * Executes a JSONProcess with the data sent in the JSONObject.
+   * 
+   * @param w
+   *          Writer where the result is stored.
+   * @param process
+   *          JSONProcess to execute.
+   * @param jsonsent
+   *          JSONObject with the process input parameters.
+   */
+  private void execProcess(Writer w, JSONProcess process, JSONObject jsonsent) throws IOException,
+      ServletException {
+
+    if (process instanceof SecuredJSONProcess) {
+      if (!synchronizedMode && !bypassImportEntry
+          && process instanceof DataSynchronizationImportProcess) {
+        ((DataSynchronizationImportProcess) process).executeCreateImportEntry(w, jsonsent);
+      } else {
+        ((SecuredJSONProcess) process).secureExec(w, jsonsent);
+      }
+    } else {
+      log.warn("Executing unsecure process " + process.getClass());
+      if (!synchronizedMode && process instanceof DataSynchronizationImportProcess) {
+        ((DataSynchronizationImportProcess) process).executeCreateImportEntry(w, jsonsent);
+      } else {
+        process.exec(w, jsonsent);
+      }
+    }
+  }
+
+  /**
+   * Builds a sorted List of instances that implement the serviceName. The implementation is done
+   * using the MobileServiceClassSelector. To ensure backwards compatibility in case that exists a
+   * class with the same name than the service name and that it does not implement the
+   * MobileServiceClassSelector it is also added to the List.
+   * 
+   * @param serviceName
+   *          The Mobile Service name that is going to be executed.
+   * @return The sorted list of classes implementing the Mobile Service.
+   * @throws ClassNotFoundException
+   *           Exception thrown when no class implementing the service name is found.
+   */
+  private List<? extends JSONProcess> getServiceClassInstances(String serviceName)
+      throws ClassNotFoundException {
+    BeanManager bm = WeldUtils.getStaticInstanceBeanManager();
+    List<JSONProcess> processes = new ArrayList<JSONProcess>();
+    boolean isDefaultClassMissing = true;
+    Set<Bean<?>> beans = bm.getBeans(JSONProcess.class, WeldUtils.ANY_LITERAL,
+        new MobileService.MobileServiceClassSelector(serviceName));
+    for (Bean<?> bean : beans) {
+      processes.add((JSONProcess) bm.getReference(bean, JSONProcess.class,
+          bm.createCreationalContext(bean)));
+      if (bean.getBeanClass().getName().equals(serviceName)) {
+        isDefaultClassMissing = false;
+      }
+    }
+    // If no bean with classname like the service name is added try to add to the list. This is
+    // added for backwards compatibility to include service classes that are not implementing the
+    // qualifier.
+    try {
+      if (isDefaultClassMissing) {
+        @SuppressWarnings("unchecked")
+        Class<JSONProcess> process = (Class<JSONProcess>) Class.forName(serviceName);
+        JSONProcess proc = WeldUtils.getInstanceFromStaticBeanManager(process);
+
+        processes.add(proc);
+      }
+    } catch (ClassNotFoundException ignore) {
+      // Only throw ClassNotFoundException if no JSONProcess is found implementing the service name.
+    }
+
+    if (processes.isEmpty()) {
+      throw new ClassNotFoundException();
+    }
+    Collections.sort(processes, new ServiceProcessComparator());
+
+    // set synchronized mode
+    for (JSONProcess proc : processes) {
+      if (proc instanceof JSONProcessSimple) {
+        ((JSONProcessSimple) proc).setRunInSynchronizedMode(synchronizedMode);
+      }
+    }
+
+    return processes;
+  }
+
+  private static class ServiceProcessComparator implements Comparator<JSONProcess> {
+    private int getProcessPriority(JSONProcess proc) {
+      if (proc instanceof SecuredJSONProcess) {
+        return ((SecuredJSONProcess) proc).getPriority();
+      }
+      return 100;
+    }
+
+    @Override
+    public int compare(JSONProcess proc1, JSONProcess proc2) {
+      return getProcessPriority(proc1) - getProcessPriority(proc2);
+    }
+
+  }
+}
diff --git a/src/org/openbravo/mobile/core/process/SecuredJSONProcess.java b/src/org/openbravo/mobile/core/process/SecuredJSONProcess.java
--- a/src/org/openbravo/mobile/core/process/SecuredJSONProcess.java
+++ b/src/org/openbravo/mobile/core/process/SecuredJSONProcess.java
@@ -33,6 +33,16 @@
 
   private final String secureKey = "SECURE_JSON" + this.getClass().getName();
 
+  private boolean runInSynchronizedMode = false;
+
+  public boolean isRunInSynchronizedMode() {
+    return runInSynchronizedMode;
+  }
+
+  public void setRunInSynchronizedMode(boolean runInSynchronizedMode) {
+    this.runInSynchronizedMode = runInSynchronizedMode;
+  }
+
   @Override
   public abstract void exec(Writer w, JSONObject jsonsent) throws IOException, ServletException;
 
diff --git a/src/org/openbravo/mobile/core/servercontroller/SynchronizedServerProcessCaller.java b/src/org/openbravo/mobile/core/servercontroller/SynchronizedServerProcessCaller.java
new file mode 100644
--- /dev/null
+++ b/src/org/openbravo/mobile/core/servercontroller/SynchronizedServerProcessCaller.java
@@ -0,0 +1,184 @@
+/*
+ ************************************************************************************
+ * Copyright (C) 2016 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.
+ ************************************************************************************
+ */
+package org.openbravo.mobile.core.servercontroller;
+
+import java.io.StringWriter;
+import java.io.Writer;
+
+import javax.enterprise.context.ApplicationScoped;
+
+import org.codehaus.jettison.json.JSONArray;
+import org.codehaus.jettison.json.JSONException;
+import org.codehaus.jettison.json.JSONObject;
+import org.hibernate.Query;
+import org.openbravo.base.exception.OBException;
+import org.openbravo.base.weld.WeldUtils;
+import org.openbravo.dal.core.DalUtil;
+import org.openbravo.dal.core.OBContext;
+import org.openbravo.dal.service.OBDal;
+import org.openbravo.mobile.core.process.JSONProcessSimple;
+import org.openbravo.mobile.core.process.MobileImportEntryProcessorRunnable;
+import org.openbravo.mobile.core.process.MobileServiceProcessor;
+import org.openbravo.service.importprocess.ImportEntry;
+import org.openbravo.service.importprocess.ImportEntryManager.ImportEntryQualifier;
+import org.openbravo.service.importprocess.ImportEntryProcessor;
+import org.openbravo.service.json.JsonConstants;
+
+/**
+ * Handler which receives a json which calls other json processes in order and does one commit at
+ * the end. Exceptions are returned directly to the client.
+ * 
+ * The class has a main flow logic which calls central server or processes locally depending on
+ * being online or offline or being store or central server.
+ * 
+ * For more information see these wiki pages:
+ * http://wiki.openbravo.com/wiki/Multi-Server_Process_Calls_Concept
+ * http://wiki.openbravo.com/wiki/Retail:Store_Server#Synchronized_Transactions
+ * 
+ * @author mtaal
+ */
+public class SynchronizedServerProcessCaller extends MultiServerJSONProcess {
+
+  public static final String SYNCHRONIZED_DATA_TYPE = "OBMOBC_SynchronizedData";
+
+  @Override
+  protected String getImportEntryDataType() {
+    return SYNCHRONIZED_DATA_TYPE;
+  }
+
+  protected boolean executeFirstInCentral(JSONObject json) throws JSONException {
+    return true;
+  }
+
+  protected JSONObject execute(JSONObject jsonSent) {
+    try {
+      final MobileServiceProcessor processor = new MobileServiceProcessor();
+      processor.setSynchronizedMode(true);
+
+      final Writer w = new StringWriter();
+      w.write("{\"result\":[");
+      final JSONArray data = jsonSent.getJSONArray("data");
+      for (int i = 0; i < data.length(); i++) {
+        final JSONObject content = data.getJSONObject(i);
+        final String serviceName = content.getString("_serviceName");
+        if (i > 0) {
+          w.write(",");
+        }
+
+        final StringWriter localWriter = new StringWriter();
+        localWriter.write("{");
+        localWriter.write("\"_serviceName\": \"" + serviceName + "\",");
+        processor.execServiceName(localWriter, serviceName, content);
+
+        localWriter.write("}");
+        final JSONObject checkResult = new JSONObject(localWriter.toString());
+        // if error then return it
+        if (isErrorJson(checkResult)) {
+          return checkResult;
+        }
+        w.write(localWriter.toString());
+      }
+      w.write("]");
+      w.write("}");
+      w.close();
+
+      final JSONObject result = new JSONObject(w.toString());
+      // important to put the same message id in the return!
+      // this so that symmetric ds can detect that the message
+      // has already been replicated/created
+      result.put("messageId", jsonSent.getString("messageId"));
+      // note: this is mobile core, posterminal is a strange one
+      // to have here, to solve one day
+      if (jsonSent.has("posTerminal")) {
+        result.put("posTerminal", jsonSent.getString("posTerminal"));
+      }
+      result.put("source",
+          (MobileServerController.getInstance().isThisACentralServer() ? SOURCE_CENTRAL
+              : SOURCE_STORE));
+      result.put(JsonConstants.RESPONSE_STATUS, JsonConstants.RPCREQUEST_STATUS_SUCCESS);
+
+      return result;
+    } catch (Exception e) {
+      throw new OBException(e);
+    }
+  }
+
+  @ImportEntryQualifier(entity = SYNCHRONIZED_DATA_TYPE)
+  @ApplicationScoped
+  public static class SynchronizedProcessImportEntryProcessor extends ImportEntryProcessor {
+
+    protected ImportEntryProcessRunnable createImportEntryProcessRunnable() {
+      return WeldUtils.getInstanceFromStaticBeanManager(SynchronizedProcessRunnable.class);
+    }
+
+    protected boolean canHandleImportEntry(ImportEntry importEntryInformation) {
+      return SYNCHRONIZED_DATA_TYPE.equals(importEntryInformation.getTypeofdata());
+    }
+
+    protected String getProcessSelectionKey(ImportEntry importEntry) {
+      return (String) DalUtil.getId(importEntry.getOrganization());
+    }
+  }
+
+  private static class SynchronizedProcessRunnable extends MobileImportEntryProcessorRunnable {
+    protected Class<? extends JSONProcessSimple> getJSONProcessorClass() {
+      return SynchronizedServerProcessCaller.class;
+    }
+
+    protected void processEntry(ImportEntry importEntry) throws Exception {
+      // check that there are no other import entries for the terminal
+      // which have not yet been processed
+
+      try {
+        OBContext.setAdminMode(false);
+        if (thereIsDataInImportQueue(importEntry)) {
+          // close and commit
+          OBDal.getInstance().commitAndClose();
+          return;
+        }
+
+      } finally {
+        OBContext.restorePreviousMode();
+      }
+      super.processEntry(importEntry);
+    }
+
+    private boolean thereIsDataInImportQueue(ImportEntry importEntry) {
+      try {
+        OBContext.setAdminMode(false);
+
+        if (0 < countEntries("Error", importEntry)) {
+          // if there are related error entries before this one then this is an error
+          // throw an exception to move this entry also to error status
+          throw new OBException("There are error records before this record " + importEntry
+              + ", moving this entry also to error status.");
+        }
+
+        return 0 < countEntries("Initial", importEntry);
+      } finally {
+        OBContext.restorePreviousMode();
+      }
+    }
+
+    private int countEntries(String importStatus, ImportEntry importEntry) {
+      final String whereClause = ImportEntry.PROPERTY_IMPORTSTATUS + "='" + importStatus + "' and "
+          + ImportEntry.PROPERTY_TYPEOFDATA + "='OBMOBC_SynchronizedData' and "
+          + ImportEntry.PROPERTY_CREATIONDATE + "<:creationDate and "
+          + ImportEntry.PROPERTY_ORGANIZATION + "=:org and id!=:id";
+      final Query qry = OBDal.getInstance().getSession()
+          .createQuery("select count(*) from " + ImportEntry.ENTITY_NAME + " where " + whereClause);
+      qry.setParameter("id", importEntry.getId());
+      qry.setTimestamp("creationDate", importEntry.getCreationDate());
+      qry.setParameter("org", importEntry.getOrganization());
+
+      return ((Number) qry.uniqueResult()).intValue();
+    }
+  }
+
+}
diff --git a/web/org.openbravo.mobile.core/source/component/ob-commonbuttons.js b/web/org.openbravo.mobile.core/source/component/ob-commonbuttons.js
--- a/web/org.openbravo.mobile.core/source/component/ob-commonbuttons.js
+++ b/web/org.openbravo.mobile.core/source/component/ob-commonbuttons.js
@@ -588,6 +588,10 @@
       this.$.header.setContent(this.header);
     }
 
+    if (this.hideCloseButton) {
+      this.$.headerCloseButton.hide();
+    }
+
     if (this.maxheight) {
       this.$.bodyParent.setStyle('max-height: ' + this.maxheight + ';');
     }
diff --git a/web/org.openbravo.mobile.core/source/component/ob-menu.js b/web/org.openbravo.mobile.core/source/component/ob-menu.js
--- a/web/org.openbravo.mobile.core/source/component/ob-menu.js
+++ b/web/org.openbravo.mobile.core/source/component/ob-menu.js
@@ -205,7 +205,12 @@
       if (args && args.cancellation && args.cancellation === true) {
         return true;
       }
-      if (me.route) {
+      var window = _.filter(args.windows, function (wind) {
+        return wind.route === args.context.route;
+      });
+      if (window && window[0] && window[0].navigateTo) {
+        window[0].navigateTo(args);
+      } else if (me.route) {
         OB.MobileApp.model.navigate(me.route);
       }
       if (me.url) {
diff --git a/web/org.openbravo.mobile.core/source/data/ob-dal.js b/web/org.openbravo.mobile.core/source/data/ob-dal.js
--- a/web/org.openbravo.mobile.core/source/data/ob-dal.js
+++ b/web/org.openbravo.mobile.core/source/data/ob-dal.js
@@ -7,7 +7,7 @@
  ************************************************************************************
  */
 
-/*global OB, _, console, Backbone, enyo, localStorage */
+/*global OB, _, console, Backbone, enyo, localStorage, Promise */
 
 OB.Dal = OB.Dal || {};
 
@@ -431,7 +431,7 @@
         data.parameters = {};
       }
       data.parameters.forceRemote = whereClause && whereClause.forceRemote;
-      
+
       //replace _filter column with all columns marked as filterable
       if (whereClause && whereClause.remoteFilters) {
         var filter = _.find(whereClause.remoteFilters, function (filter) {
@@ -1067,6 +1067,71 @@
     }
   };
 
+  OB.Dal.createDataDump = function (models, callback) {
+    var result = [],
+        cnt = 0,
+        promises = [];
+
+    if (models.length === 0) {
+      if (callback) {
+        callback();
+      }
+      return;
+    }
+
+    _.each(models, function (model) {
+      promises.push(new Promise(function (resolve, reject) {
+        OB.Dal.find(model, null, function (data) {
+          cnt++;
+          // arbitrary high number we can't load more in memory
+          if (cnt > 5000) {
+            var msg = "Creating backup of more 5000 records, this it probably not supported, last record " + JSON.stringify(data);
+            OB.UTIL.showError(msg);
+            OB.error(msg);
+            throw msg;
+          }
+          result.push({
+            'model': model,
+            'data': data.models
+          });
+          resolve();
+        }, function () {
+          reject();
+        });
+      }));
+    });
+
+    Promise.all(promises).then(function () {
+      if (callback) {
+        callback(result);
+      }
+    });
+  };
+
+  OB.Dal.restoreDataDump = function (dataDump, callback) {
+    if (!dataDump) {
+      if (callback) {
+        callback();
+      }
+      return;
+    }
+
+    OB.Dal.transaction(function (tx) {
+      _.each(dataDump, function (dataDumpEntry) {
+        OB.Dal.removeAllInTransaction(tx, dataDumpEntry.model);
+        _.each(dataDumpEntry.data, function (dataEntry) {
+          OB.Dal.saveInTransaction(tx, dataEntry, null, null, true);
+        });
+      });
+    }, function () {
+      OB.error("The restore dump failed failed to be commited. data: " + JSON.stringify(dataDump));
+    }, function () {
+      if (callback) {
+        callback();
+      }
+    });
+  };
+
   OB.Dal.remove = function (model, success, error, currentTransaction) {
     if (OB.Data.localDB) {
       var modelDefinition = OB.Model[model.constructor.prototype.modelName],
diff --git a/web/org.openbravo.mobile.core/source/data/ob-datasource.js b/web/org.openbravo.mobile.core/source/data/ob-datasource.js
--- a/web/org.openbravo.mobile.core/source/data/ob-datasource.js
+++ b/web/org.openbravo.mobile.core/source/data/ob-datasource.js
@@ -67,6 +67,8 @@
         }
         exception.invalidPermission = response.error.invalidPermission;
         exception.message = response.error.message;
+      } else if (response.error) {
+        exception.message = response.error;
       }
 
       // argument checks
@@ -196,7 +198,7 @@
     this.source = source;
   };
 
-  OB.DS.Process.prototype.exec = function (params, callback, callbackError, async, timeout) {
+  OB.DS.Process.prepareData = function (params) {
     var data = {},
         i, attr;
 
@@ -215,8 +217,45 @@
     }
 
     data.appName = OB.MobileApp.model.get('appName') || 'OBMOBC';
+    return data;
+  };
 
-    servicePOST(this.source, data, callback, callbackError, async, timeout);
+  OB.DS.Process.prototype.exec = function (params, callback, callbackError, async, timeout) {
+    var data = OB.DS.Process.prepareData(params);
+
+    // run all transactional services synchronized if synchronized mode is enabled
+    if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true) && OB.RR.RequestRouter.isTransactionalService(this.source)) {
+      var contentData = [];
+      data._serviceName = this.source;
+
+      contentData.push(data);
+
+      OB.MobileApp.model.showSynchronizingDialog();
+      this.source = 'org.openbravo.mobile.core.servercontroller.SynchronizedServerProcessCaller';
+      var syncData = {
+        messageId: params.messageId ? params.messageId : OB.UTIL.get_UUID(),
+        _source: 'WEBPOS',
+        posTerminal: OB.MobileApp.model.get('terminal').id,
+        data: contentData
+      };
+      syncData = OB.DS.Process.prepareData(syncData);
+
+      servicePOST(this.source, syncData, function (args) {
+        if (callback) {
+          callback(args);
+        }
+        OB.MobileApp.model.hideSynchronizingDialog();
+      }, function (args) {
+        OB.MobileApp.model.hideSynchronizingDialog();
+        if (callbackError) {
+          callbackError(args);
+        }
+      }, async, timeout);
+
+    } else {
+      servicePOST(this.source, data, callback, callbackError, async, timeout);
+    }
+
   };
 
   // Source object
diff --git a/web/org.openbravo.mobile.core/source/data/ob-requestrouter.js b/web/org.openbravo.mobile.core/source/data/ob-requestrouter.js
--- a/web/org.openbravo.mobile.core/source/data/ob-requestrouter.js
+++ b/web/org.openbravo.mobile.core/source/data/ob-requestrouter.js
@@ -816,7 +816,29 @@
           OB.UTIL.localStorage.setItem('authenticationToken', encodeURIComponent(data.authenticationToken));
         }
       }, function () {}, true, 20000);
+    },
+
+    isTransactionalService: function (serviceName) {
+      var service, services = _.filter(OB.RR.RequestRouter.availableServices.models, function (srvc) {
+        return serviceName.indexOf(srvc.get('name')) !== -1;
+      });
+      if (services.length > 1) {
+        //In case of having more than one service, get longest name service. Longest name service will be the most similar to serviceName
+        _.each(services, function (iterSrvc) {
+          if (!service || service.get('name').length < iterSrvc.get('name').length) {
+            service = iterSrvc;
+          }
+        });
+
+      } else {
+        service = services[0];
+      }
+      if (!service) {
+        return false;
+      }
+      return service.get('type') === OB.RR.ServTypeTransaction;
     }
+
   };
 
   OB.RR.RequestRouter.initialize();
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
--- a/web/org.openbravo.mobile.core/source/model/ob-terminal-model.js
+++ b/web/org.openbravo.mobile.core/source/model/ob-terminal-model.js
@@ -13,6 +13,9 @@
 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: [],
 
@@ -761,6 +764,152 @@
     });
   },
 
+
+  /**
+   * 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,
+  setSynchronizedCheckpoint: function (callback) {
+    var me = OB.MobileApp.model;
+
+    if (!OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) {
+      return;
+    }
+
+    // already show the dialog now
+    me.showSynchronizingDialog();
+
+    OB.Dal.createDataDump(me._synchronizedCheckpointModels, function (checkPoint) {
+      me._prechangeCheckpoint = checkPoint;
+      if (callback) {
+        callback();
+      }
+    });
+  },
+  showSynchronizingDialog: function () {
+    var me = OB.MobileApp.model;
+
+    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();
+
+  },
+  hideSynchronizingDialog: function () {
+    var me = OB.MobileApp.model;
+    if (me.showSynchronizedDialog) {
+      me.showSynchronizedDialog.hide();
+      me.showSynchronizedDialog = null;
+    }
+  },
+  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) {
+    var me = OB.MobileApp.model;
+    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);
+    });
+  },
+
   /**
    * Should not be called directly. syncAllModels should be used instead
    *
@@ -777,8 +926,46 @@
     // 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 element to synchronize
-      me.syncModelExecuteSuccessCallbacks();
+      //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
+        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',
+          posTerminal: OB.MobileApp.model.get('terminal').id,
+          data: me.synchronizedData
+        };
+
+        // clear some memory
+        me.synchronizedData = [];
+
+        // and execute the complete request, first do the presync actions
+        me.doPreSynchronizedCallActions(function () {
+          syncProc.exec(syncData, me.syncModelExecuteSuccessCallbacks, me.syncModelExecuteErrorCallbacks, null, me.synchronizedTimeOut);
+        });
+      } else {
+        me.syncModelExecuteSuccessCallbacks();
+      }
       return;
     }
 
@@ -844,77 +1031,127 @@
         }
       });
 
-      var proc = new OB.DS.Process(className);
       var timeout = modelObj.timeout || 20000;
       var timePerRecord = modelObj.timePerRecord || 1000;
-      proc.exec({
+      var data = {
         messageId: OB.UTIL.get_UUID(),
         data: dataToSend
-      }, function (data, message) {
-        // 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 () {}
-            }]);
+      };
+
+      // 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 () {
+          var promises = [];
+
+          // proc.exec  mcallbackerror
+          OB.warn("Error while synchronizing model '" + OB.Dal.getTableName(model) + "'");
+
+          me.syncModelExecuteErrorCallbacks();
+          };
+
+      var procSuccessCallBack = function (data, message) {
+
+          // 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;
           }
-          me.syncModelExecuteErrorCallbacks();
-          return;
-        }
-        // success. Elements can be now deleted from the database
-        var removeSyncedElemsCallback = function () {
-            OB.info("Purging the '" + OB.Dal.getTableName(model) + "' table");
-            var promises = [];
-            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 () {
-                    resolve();
-                  }, function (tx, err) {
-                    reject();
-                  });
-                } else {
-                  // no persistent model (Default).
-                  OB.Dal.remove(record, function () {
-                    resolve();
-                  }, function (tx, err) {
-                    OB.UTIL.showError(err);
-                    reject();
-                  });
+          // success. Elements can be now deleted from the database
+          var removeSyncedElemsCallback = function () {
+              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 () {
+                      resolve();
+                    }, function (tx, err) {
+                      reject();
+                    });
+                  } else {
+                    // no persistent model (Default).
+                    OB.Dal.remove(record, function () {
+                      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.postProcessingFunction) {
+            modelObj.postProcessingFunction(newDataToSync, removeSyncedElemsCallback);
+          } else {
+            removeSyncedElemsCallback();
+          }
+          };
 
-            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);
-            });
-            me.syncModel();
-            };
-        if (modelObj.postProcessingFunction) {
-          modelObj.postProcessingFunction(newDataToSync, removeSyncedElemsCallback);
-        } else {
-          removeSyncedElemsCallback();
-        }
-      }, function () {
-        // proc.exec  mcallbackerror
-        OB.warn("Error while synchronizing model '" + OB.Dal.getTableName(model) + "'");
-        me.syncModelExecuteErrorCallbacks();
-      }, null, timeout + timePerRecord * newDataToSync.length);
-    }, function () {
+      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);
+        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();
     }, {
@@ -924,21 +1161,65 @@
   },
   syncModelSuccessCallbacks: [],
   syncModelErrorCallbacks: [],
-  syncModelExecuteSuccessCallbacks: function () {
+  syncModelExecuteSuccessCallbacks: function (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;
+    }
+
+    OB.MobileApp.model.hideSynchronizingDialog();
+
     OB.MobileApp.model.syncModelQueue = [];
     OB.MobileApp.model.syncModelErrorCallbacks = [];
-    OB.UTIL.executeCallbackQueue(OB.MobileApp.model.syncModelSuccessCallbacks);
+    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);
+    });
   },
   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";
+
+      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 () {
+          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)
    *
@@ -969,6 +1250,9 @@
       return;
     }
 
+    me.syncModelSuccessCallbacks = [];
+    me.syncModelErrorCallbacks = [];
+
     // remember the callbacks in the callbacks queue
     me.syncModelSuccessCallbacks.push(successCallback);
     me.syncModelErrorCallbacks.push(errorCallback);
@@ -984,8 +1268,13 @@
       var modelObj = this.get('dataSyncModels')[i];
       me.syncModelQueue.push(modelObj);
     }
+
     // start the synchronization if it was not already in progress
     if (!isCurrentlySynchronizing) {
+      // reset some members used in synchronized comms
+      me.synchronizedData = [];
+      me.synchronizedTimeOut = 0;
+
       me.syncModel(this.syncModelExecuteSuccessCallbacks, this.syncModelExecuteErrorCallbacks);
     }
   },
diff --git a/web/org.openbravo.mobile.core/source/utils/ob-utilities.js b/web/org.openbravo.mobile.core/source/utils/ob-utilities.js
--- a/web/org.openbravo.mobile.core/source/utils/ob-utilities.js
+++ b/web/org.openbravo.mobile.core/source/utils/ob-utilities.js
@@ -771,11 +771,11 @@
     }
   };
 
-  OB.UTIL.executeCallbackQueue = function (queue) {
+  OB.UTIL.executeCallbackQueue = function (queue, arg) {
     while (queue.length > 0) {
       var f = queue.shift();
       if (f) {
-        f();
+        f(arg);
       }
     }
   };
diff --git a/web/org.openbravo.mobile.core/source/utils/ob-utilitiesui.js b/web/org.openbravo.mobile.core/source/utils/ob-utilitiesui.js
--- a/web/org.openbravo.mobile.core/source/utils/ob-utilitiesui.js
+++ b/web/org.openbravo.mobile.core/source/utils/ob-utilitiesui.js
@@ -240,6 +240,7 @@
           name: 'dynamicConfirmationPopup',
           header: title,
           bodyContent: bodyContent,
+          hideCloseButton: options && options.hideCloseButton,
           autoDismiss: !OB.UTIL.isNullOrUndefined(options) && !OB.UTIL.isNullOrUndefined(options.autoDismiss) ? options.autoDismiss : true,
           executeOnShow: function () {
             if (options && options.onShowFunction) {
@@ -330,6 +331,7 @@
       dialog.show();
 
       OB.UTIL.showLoading(false);
+      return dialog;
     }
   }
 });
