# HG changeset patch
# User Aaron Calero <aaron.calero@openbravo.com>
# Date 1427890596 -7200
#      Wed Apr 01 14:16:36 2015 +0200
# Node ID 66f9a8ed65090aa0b6774d68e1189ae25465bea7
# Parent  f49a0b14c889215340353bbd40331e6064dcdcd3
Fixed issue 29478: Provide an API to do transactional OB.Dal calls

Added a new set of functions to OB.Dal to allow transactions.
Updated the existing functions.

diff -r f49a0b14c889 -r 66f9a8ed6509 src-db/database/sourcedata/AD_MESSAGE.xml
--- a/src-db/database/sourcedata/AD_MESSAGE.xml	Mon Jun 15 17:58:07 2015 +0200
+++ b/src-db/database/sourcedata/AD_MESSAGE.xml	Wed Apr 01 14:16:36 2015 +0200
@@ -673,6 +673,18 @@
 <!--891098B21ABE4376B00B2A4B60A5571A-->  <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N>
 <!--891098B21ABE4376B00B2A4B60A5571A--></AD_MESSAGE>
 
+<!--896B39352E994EAEAD902E27366FDA2B--><AD_MESSAGE>
+<!--896B39352E994EAEAD902E27366FDA2B-->  <AD_MESSAGE_ID><![CDATA[896B39352E994EAEAD902E27366FDA2B]]></AD_MESSAGE_ID>
+<!--896B39352E994EAEAD902E27366FDA2B-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--896B39352E994EAEAD902E27366FDA2B-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--896B39352E994EAEAD902E27366FDA2B-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--896B39352E994EAEAD902E27366FDA2B-->  <VALUE><![CDATA[OBMOBC_TransactionExistsError]]></VALUE>
+<!--896B39352E994EAEAD902E27366FDA2B-->  <MSGTEXT><![CDATA[The transaction %0 already exists]]></MSGTEXT>
+<!--896B39352E994EAEAD902E27366FDA2B-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--896B39352E994EAEAD902E27366FDA2B-->  <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID>
+<!--896B39352E994EAEAD902E27366FDA2B-->  <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N>
+<!--896B39352E994EAEAD902E27366FDA2B--></AD_MESSAGE>
+
 <!--8CF8F60510AD4197BD0B8EAA5ABE515B--><AD_MESSAGE>
 <!--8CF8F60510AD4197BD0B8EAA5ABE515B-->  <AD_MESSAGE_ID><![CDATA[8CF8F60510AD4197BD0B8EAA5ABE515B]]></AD_MESSAGE_ID>
 <!--8CF8F60510AD4197BD0B8EAA5ABE515B-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
@@ -829,6 +841,18 @@
 <!--AACC82D3C8C241FE8A7ACC9F43E5D5C1-->  <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N>
 <!--AACC82D3C8C241FE8A7ACC9F43E5D5C1--></AD_MESSAGE>
 
+<!--AB6C4AC8F1DE4600A0B45FA53E60FF42--><AD_MESSAGE>
+<!--AB6C4AC8F1DE4600A0B45FA53E60FF42-->  <AD_MESSAGE_ID><![CDATA[AB6C4AC8F1DE4600A0B45FA53E60FF42]]></AD_MESSAGE_ID>
+<!--AB6C4AC8F1DE4600A0B45FA53E60FF42-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--AB6C4AC8F1DE4600A0B45FA53E60FF42-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--AB6C4AC8F1DE4600A0B45FA53E60FF42-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--AB6C4AC8F1DE4600A0B45FA53E60FF42-->  <VALUE><![CDATA[OBMOBC_TransactionNotExistsError]]></VALUE>
+<!--AB6C4AC8F1DE4600A0B45FA53E60FF42-->  <MSGTEXT><![CDATA[The transaction %0 hasn't been created or has already been commited]]></MSGTEXT>
+<!--AB6C4AC8F1DE4600A0B45FA53E60FF42-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--AB6C4AC8F1DE4600A0B45FA53E60FF42-->  <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID>
+<!--AB6C4AC8F1DE4600A0B45FA53E60FF42-->  <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N>
+<!--AB6C4AC8F1DE4600A0B45FA53E60FF42--></AD_MESSAGE>
+
 <!--AD38AD0F94E74540A0CBFB07C270EA67--><AD_MESSAGE>
 <!--AD38AD0F94E74540A0CBFB07C270EA67-->  <AD_MESSAGE_ID><![CDATA[AD38AD0F94E74540A0CBFB07C270EA67]]></AD_MESSAGE_ID>
 <!--AD38AD0F94E74540A0CBFB07C270EA67-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
diff -r f49a0b14c889 -r 66f9a8ed6509 web/org.openbravo.mobile.core/source/data/ob-dal.js
--- a/web/org.openbravo.mobile.core/source/data/ob-dal.js	Mon Jun 15 17:58:07 2015 +0200
+++ b/web/org.openbravo.mobile.core/source/data/ob-dal.js	Wed Apr 01 14:16:36 2015 +0200
@@ -309,6 +309,10 @@
     return null;
   };
 
+  OB.Dal.transaction = function(callback, errorCallback, successCallback) {
+    OB.Data.localDB.transaction(callback, errorCallback, successCallback);
+  };
+
   OB.Dal.findUsingCache = function (cacheName, model, whereClause, success, error, args) {
     if (OB.Cache.hasItem(cacheName, whereClause)) {
       OB.Dal.stackSize++;
@@ -328,7 +332,11 @@
 
   };
 
-  OB.Dal.find = function (model, whereClause, success, error, args) {
+  OB.Dal.findInTransaction = function (tx, model, whereClause, success, error, args) {
+    OB.Dal.find(model, whereClause, success, error, args, tx);
+  };
+
+  OB.Dal.find = function (model, whereClause, success, error, args, currentTransaction) {
     var callerInfo = getCallerInfo();
     var params = null,
         appendWhere = true,
@@ -392,7 +400,38 @@
     } else if (OB.Data.localDB) {
       var tableName = OB.Dal.getTableName(model),
           propertyMap = OB.Dal.getPropertyMap(model),
-          sql = 'SELECT * FROM ' + tableName;
+          sql = 'SELECT * FROM ' + tableName,
+          synchId, processResult, processError;
+
+      processResult = function (tr, result) {
+        if (synchId) {
+          OB.UTIL.SynchronizationHelper.finished(synchId, 'find');
+        }
+        var i, collectionType = OB.Collection[model.prototype.modelName + 'List'] || Backbone.Collection,
+            collection = new collectionType(),
+            len = result.rows.length;
+        if (len === 0) {
+          success(collection, args);
+        } else {
+          for (i = 0; i < len; i++) {
+            collection.add(OB.Dal.transform(model, result.rows.item(i)));
+          }
+          success(collection, args);
+        }
+      };
+
+      processError = function (txError, e) {
+        if (synchId) {
+          OB.UTIL.SynchronizationHelper.finished(synchId, 'find');
+        }
+        if (!args || !args.doNotShowErrors) {
+          executeSqlErrorHandler('error', "OB.Dal.find: table", tableName, txError, e, callerInfo);
+        }
+        if (error) {
+          error();
+        }
+      };
+
       // websql
       // arguments check
       if (tableName === null) {
@@ -434,38 +473,16 @@
         sql = sql + ' LIMIT ' + limit;
       }
 
-      OB.Data.localDB.readTransaction(function (tx) {
-        var synchId;
-        if (model.prototype.modelName !== 'LogClient') {
-          synchId = OB.UTIL.SynchronizationHelper.busyUntilFinishes('find ' + model.prototype.modelName);
-        }
-        tx.executeSql(sql, params, function (tr, result) {
-          if (synchId) {
-            OB.UTIL.SynchronizationHelper.finished(synchId, 'find');
+      if (currentTransaction) {
+        currentTransaction.executeSql(sql, params, processResult, processError);
+      } else {
+        OB.Data.localDB.readTransaction(function (tx) {
+          if (model.prototype.modelName !== 'LogClient') {
+            synchId = OB.UTIL.SynchronizationHelper.busyUntilFinishes('find ' + model.prototype.modelName);
           }
-          var i, collectionType = OB.Collection[model.prototype.modelName + 'List'] || Backbone.Collection,
-              collection = new collectionType(),
-              len = result.rows.length;
-          if (len === 0) {
-            success(collection, args);
-          } else {
-            for (i = 0; i < len; i++) {
-              collection.add(OB.Dal.transform(model, result.rows.item(i)));
-            }
-            success(collection, args);
-          }
-        }, function (txError, e) {
-          if (synchId) {
-            OB.UTIL.SynchronizationHelper.finished(synchId, 'find');
-          }
-          if (!args || !args.doNotShowErrors) {
-            executeSqlErrorHandler('error', "OB.Dal.find: table", tableName, txError, e, callerInfo);
-          }
-          if (error) {
-            error();
-          }
+          tx.executeSql(sql, params, processResult, processError);
         });
-      });
+      }
     } else {
       this.missingLocalStorageLogic();
     }
@@ -489,37 +506,54 @@
     }
   };
 
-  OB.Dal.query = function (model, sql, params, success, error, args) {
+  OB.Dal.queryInTransaction = function (tx, model, sql, params, success, error, args) {
+    OB.Dal.query(model, sql, params, success, error, args, tx);
+  };
+
+  OB.Dal.query = function (model, sql, params, success, error, args, currentTransaction) {
+    var processResult, processError;
+    processResult = function (tr, result) {
+      var i, collectionType = OB.Collection[model.prototype.modelName + 'List'] || Backbone.Collection,
+          collection = new collectionType(),
+          len = result.rows.length;
+      if (len === 0) {
+        success(collection, args);
+      } else {
+        for (i = 0; i < len; i++) {
+          collection.add(OB.Dal.transform(model, result.rows.item(i)));
+        }
+        success(collection, args);
+      }
+    };
+
+    processError = function (txError, e) {
+      executeSqlErrorHandler('error', "OB.Dal.query: table", model.prototype.modelName, txError, e);
+      if (_.isFunction(error)) {
+        error();
+      }
+    };
+
     if (OB.Data.localDB) {
       if (model.prototype.dataLimit) {
         sql = sql + ' LIMIT ' + model.prototype.dataLimit;
       }
-      OB.Data.localDB.readTransaction(function (tx) {
-        tx.executeSql(sql, _.isEmpty(params) ? [] : params, function (tr, result) {
-          var i, collectionType = OB.Collection[model.prototype.modelName + 'List'] || Backbone.Collection,
-              collection = new collectionType(),
-              len = result.rows.length;
-          if (len === 0) {
-            success(collection, args);
-          } else {
-            for (i = 0; i < len; i++) {
-              collection.add(OB.Dal.transform(model, result.rows.item(i)));
-            }
-            success(collection, args);
-          }
-        }, function (txError, e) {
-          executeSqlErrorHandler('error', "OB.Dal.query: table", model.prototype.modelName, txError, e);
-          if (_.isFunction(error)) {
-            error();
-          }
+      if (currentTransaction) {
+        currentTransaction.executeSql(sql, params, processResult, processError);
+      } else {
+        OB.Data.localDB.transaction(function (tx) {
+          tx.executeSql(sql, params, processResult, processError);
         });
-      });
+      }
     } else {
       this.missingLocalStorageLogic();
     }
   };
 
-  OB.Dal.save = function (model, success, error, forceInsert) {
+  OB.Dal.saveInTransaction = function (tx, model, success, error, forceInsert) {
+    OB.Dal.save(model, success, error, forceInsert, tx);
+  };
+
+  OB.Dal.save = function (model, success, error, forceInsert, currentTransaction) {
     var callerInfo = getCallerInfo();
     var modelProto = model.constructor.prototype,
         xhr, data = {};
@@ -554,7 +588,15 @@
           primaryKeyColumn, sql = '',
           params = null,
           firstParam = true,
-          uuid, propertyName, filterVal;
+          uuid, propertyName, filterVal, processError;
+
+      processError = function (txError, e) {
+        executeSqlErrorHandler('error', "OB.Dal.save: table", tableName, txError, e, callerInfo);
+        if (_.isFunction(error)) {
+          error();
+        }
+      };
+
       // websql
       // argument checks
       if (!tableName) {
@@ -683,33 +725,48 @@
           }
         }
       }
-      OB.Data.localDB.transaction(function (tx) {
+
+      if (currentTransaction) {
         try {
-          tx.executeSql(sql, params, silentFunction(success), function (txError, e) {
-            executeSqlErrorHandler('error', "OB.Dal.save: table", tableName, txError, e, callerInfo);
-            if (_.isFunction(error)) {
-              error();
-            }
-          });
+          currentTransaction.executeSql(sql, params, silentFunction(success), processError);
         } catch (e) {
           executeSqlErrorHandler('error', "OB.Dal.save: table", tableName, null, e, callerInfo);
-          // OB.Data.localDB = undefined;
-          // OB.Dal.openWebSQL();
         }
-      });
+      } else {
+        OB.Data.localDB.transaction(function (tx) {
+          try {
+            tx.executeSql(sql, params, silentFunction(success), processError);
+          } catch (e) {
+            executeSqlErrorHandler('error', "OB.Dal.save: table", tableName, null, e, callerInfo);
+          }
+        });
+      }
     } else {
       this.missingLocalStorageLogic();
     }
   };
 
-  OB.Dal.remove = function (model, success, error) {
+  OB.Dal.removeInTransaction = function (tx, model, success, error) {
+    OB.Dal.remove(model, success, error, tx);
+  };
+
+
+  OB.Dal.remove = function (model, success, error, currentTransaction) {
     if (OB.Data.localDB) {
       var modelDefinition = OB.Model[model.constructor.prototype.modelName],
           modelProto = model.constructor.prototype,
           tableName = OB.Dal.getTableName(modelDefinition),
           pk, pkProperty = 'id',
           pkColumn, sql = '',
-          params = [];
+          params = [],
+          processError;
+
+      processError = function (txError, e) {
+        executeSqlErrorHandler('error', "OB.Dal.remove: table", tableName, txError, e);
+        if (_.isFunction(error)) {
+          error();
+        }
+      };
 
       // websql
       if (!tableName) {
@@ -742,26 +799,35 @@
         });
       }
 
-      //OB.info(sql);
-      //OB.info(params);
-      OB.Data.localDB.transaction(function (tx) {
-        tx.executeSql(sql, params, silentFunction(success), function (txError, e) {
-          executeSqlErrorHandler('error', "OB.Dal.remove: table", tableName, txError, e);
-          if (_.isFunction(error)) {
-            error();
-          }
+      if (currentTransaction) {
+        currentTransaction.executeSql(sql, params, silentFunction(success), processError);
+      } else {
+        OB.Data.localDB.transaction(function (tx) {
+          tx.executeSql(sql, params, silentFunction(success), processError);
         });
-      });
+      }
     } else {
       this.missingLocalStorageLogic();
     }
   };
 
-  OB.Dal.removeAll = function (model, criteria, success, error) {
+  OB.Dal.removeAllInTransaction = function (tx, model, criteria, success, error) {
+      OB.Dal.removeAll(model, criteria, success, error, tx);
+  };
+
+  OB.Dal.removeAll = function (model, criteria, success, error, currentTransaction) {
     if (OB.Data.localDB) {
       var tableName = OB.Dal.getTableName(model),
           propertyMap = OB.Dal.getPropertyMap(model),
-          sql, params, whereClause;
+          sql, params, whereClause, processError;
+
+      processError = function (txError, e) {
+        executeSqlErrorHandler('error', "OB.Dal.removeAll: table", tableName, txError, e);
+        if (_.isFunction(error)) {
+          error();
+        }
+      };
+
       // websql
       if (!tableName) {
         console.warn("OB.Dal.removeAll: tableName not found");
@@ -774,20 +840,24 @@
       whereClause = OB.Dal.getWhereClause(criteria, propertyMap);
       sql = sql + whereClause.sql;
       params = _.isEmpty(whereClause.params) ? [] : whereClause.params;
-      OB.Data.localDB.transaction(function (tx) {
-        tx.executeSql(sql, params, silentFunction(success), function (txError, e) {
-          executeSqlErrorHandler('error', "OB.Dal.removeAll: table", tableName, txError, e);
-          if (_.isFunction(error)) {
-            error();
-          }
+
+      if (currentTransaction) {
+        currentTransaction.executeSql(sql, params, silentFunction(success), processError);
+      } else {
+        OB.Data.localDB.transaction(function (tx) {
+          tx.executeSql(sql, params, silentFunction(success), processError);
         });
-      });
+      }
     } else {
       this.missingLocalStorageLogic();
     }
   };
 
-  OB.Dal.get = function (model, id, success, error, empty) {
+  OB.Dal.getInTransaction = function (tx, model, id, success, error, empty) {
+    OB.Dal.get(model, id, success, error, empty, tx);
+  };
+
+  OB.Dal.get = function (model, id, success, error, empty, currentTransaction) {
     OB.UTIL.Debug.execute(function () {
       if (!id) {
         throw "OB.Dal.get: id not found";
@@ -795,27 +865,36 @@
     });
     if (OB.Data.localDB) {
       var tableName = OB.Dal.getTableName(model),
-          sql = 'SELECT * FROM ' + tableName + ' WHERE ' + tableName + '_id = ?';
+          sql = 'SELECT * FROM ' + tableName + ' WHERE ' + tableName + '_id = ?',
+          processResult, processError;
+
+      processResult = function (tr, result) {
+        if (result.rows.length === 0) {
+          if (empty) {
+            empty();
+          } else {
+            return null;
+          }
+        } else {
+          success(OB.Dal.transform(model, result.rows.item(0)));
+        }
+      };
+
+      processError = function (txError, e) {
+        executeSqlErrorHandler('error', "OB.Dal.get: table", tableName, txError, e);
+        if (_.isFunction(error)) {
+          error();
+        }
+      };
 
       // websql
-      OB.Data.localDB.readTransaction(function (tx) {
-        tx.executeSql(sql, [id], function (tr, result) {
-          if (result.rows.length === 0) {
-            if (empty) {
-              empty();
-            } else {
-              return null;
-            }
-          } else {
-            success(OB.Dal.transform(model, result.rows.item(0)));
-          }
-        }, function (txError, e) {
-          executeSqlErrorHandler('error', "OB.Dal.get: table", tableName, txError, e);
-          if (_.isFunction(error)) {
-            error();
-          }
+      if (currentTransaction) {
+        currentTransaction.executeSql(sql, [id], processResult, processError);
+      } else {
+        OB.Data.localDB.readTransaction(function (tx) {
+          tx.executeSql(sql, [id], processResult, processError);
         });
-      });
+      }
     } else {
       this.missingLocalStorageLogic();
     }
