diff --git a/src/org/openbravo/retail/posterminal/OrderLoader.java b/src/org/openbravo/retail/posterminal/OrderLoader.java
--- a/src/org/openbravo/retail/posterminal/OrderLoader.java
+++ b/src/org/openbravo/retail/posterminal/OrderLoader.java
@@ -144,6 +144,11 @@
       executeHooks(orderPreProcesses, jsonorder, null, null, null);
       boolean wasPaidOnCredit = false;
       boolean isQuotation = jsonorder.has("isQuotation") && jsonorder.getBoolean("isQuotation");
+
+      if (jsonorder.has("deletedLines")) {
+        mergeDeletedLines(jsonorder);
+      }
+
       if (jsonorder.getLong("orderType") != 2 && !jsonorder.getBoolean("isLayaway") && !isQuotation
           && verifyOrderExistance(jsonorder)
           && (!jsonorder.has("preserveId") || jsonorder.getBoolean("preserveId"))) {
@@ -346,6 +351,20 @@
     }
   }
 
+  private void mergeDeletedLines(JSONObject jsonorder) {
+    try {
+      JSONArray deletedLines = jsonorder.getJSONArray("deletedLines");
+      JSONArray lines = jsonorder.getJSONArray("lines");
+      for (int i = 0; i < deletedLines.length(); i++) {
+        lines.put(deletedLines.get(i));
+      }
+      jsonorder.put("lines", lines);
+    } catch (JSONException e) {
+      log.error("JSON information couldn't be read when merging deleted lines", e);
+      return;
+    }
+  }
+
   @Override
   protected boolean additionalCheckForDuplicates(JSONObject record) {
     try {
diff --git a/web/org.openbravo.retail.posterminal/js/model/order.js b/web/org.openbravo.retail.posterminal/js/model/order.js
--- a/web/org.openbravo.retail.posterminal/js/model/order.js
+++ b/web/org.openbravo.retail.posterminal/js/model/order.js
@@ -729,7 +729,6 @@
         } else {
           // sets the new quantity
           line.set('qty', qty);
-          line.calculateGross();
           // sets the undo action
           this.set('undo', {
             text: text || OB.I18N.getLabel('OBPOS_SetUnits', [line.get('qty'), line.get('product').get('_identifier')]),
@@ -828,24 +827,39 @@
       // trigger
       line.trigger('removed', line);
 
-      // remove the line
-      this.get('lines').remove(line);
-      // set the undo action
-      this.set('undo', {
-        text: OB.I18N.getLabel('OBPOS_DeleteLine', [line.get('qty'), line.get('product').get('_identifier')]),
-        line: line,
-        undo: function () {
-          me.get('lines').add(line, {
-            at: index
-          });
+      function finishDelete() {
+        me.get('lines').remove(line);
+        // set the undo action
+        me.set('undo', {
+          text: OB.I18N.getLabel('OBPOS_DeleteLine', [line.get('qty'), line.get('product').get('_identifier')]),
+          line: line,
+          undo: function () {
+            line.unset('obposIsDeleted');
+            me.get('lines').add(line, {
+              at: index
+            });
+            me.calculateGross();
+            me.set('undo', null);
+          }
+        });
+        me.adjustPayment();
+        if (!doNotSave) {
+          me.save();
           me.calculateGross();
-          me.set('undo', null);
         }
-      });
-      this.adjustPayment();
-      if (!doNotSave) {
-        this.save();
-        this.calculateGross();
+      }
+
+      // If the OBPOS_remove_ticket preference is active then mark the line as deleted
+      if (OB.MobileApp.model.hasPermission('OBPOS_remove_ticket', true)) {
+        if (!this.get('deletedLines')) {
+          this.set('deletedLines', []);
+        }
+        line.set('obposIsDeleted', true);
+        this.get('deletedLines').push(new OrderLine(line.attributes));
+        this.save(finishDelete);
+      } else {
+        // remove the line
+        finishDelete();
       }
     },
     //Attrs is an object of attributes that will be set in order
@@ -1304,9 +1318,24 @@
           OB.UTIL.Approval.requestApproval(
           this.model, 'OBPOS_approval.deleteLine', function (approved, supervisor, approvalType) {
             if (approved) {
-              me.get('lines').remove(newline);
-              me.calculateGross();
-              me.set('undo', null);
+              // If the OBPOS_remove_ticket preference is active then mark the line as deleted
+              if (OB.MobileApp.model.hasPermission('OBPOS_remove_ticket', true)) {
+                if (!me.get('deletedLines')) {
+                  me.set('deletedLines', []);
+                }
+                newline.set('obposIsDeleted', true);
+                me.get('deletedLines').push(new OrderLine(newline.attributes));
+                me.save(function () {
+                  me.get('lines').remove(newline);
+                  me.calculateGross();
+                  me.set('undo', null);
+                });
+              } else {
+                // remove the line
+                me.get('lines').remove(newline);
+                me.calculateGross();
+                me.set('undo', null);
+              }
             }
           });
         }
diff --git a/web/org.openbravo.retail.posterminal/js/pointofsale/view/keyboardorder.js b/web/org.openbravo.retail.posterminal/js/pointofsale/view/keyboardorder.js
--- a/web/org.openbravo.retail.posterminal/js/pointofsale/view/keyboardorder.js
+++ b/web/org.openbravo.retail.posterminal/js/pointofsale/view/keyboardorder.js
@@ -272,7 +272,8 @@
     this.addCommand('+', {
       stateless: true,
       action: function (keyboard, txt) {
-        var qty = 1, value;
+        var qty = 1,
+            value;
         if ((!_.isNull(txt) || !_.isUndefined(txt)) && !_.isNaN(OB.I18N.parseNumber(txt))) {
           qty = OB.I18N.parseNumber(txt);
         }
@@ -318,6 +319,9 @@
     this.addCommand('line:delete', {
       stateless: true,
       action: function (keyboard) {
+        if (!keyboard.line) {
+          return;
+        }
         OB.UTIL.Approval.requestApproval(me.model, 'OBPOS_approval.deleteLine', function (approved, supervisor, approvalType) {
           if (approved) {
             keyboard.line.set('deleteApproved', true);
diff --git a/web/org.openbravo.retail.posterminal/js/pointofsale/view/pointofsale.js b/web/org.openbravo.retail.posterminal/js/pointofsale/view/pointofsale.js
--- a/web/org.openbravo.retail.posterminal/js/pointofsale/view/pointofsale.js
+++ b/web/org.openbravo.retail.posterminal/js/pointofsale/view/pointofsale.js
@@ -380,6 +380,20 @@
           context.model.get('orderList').saveCurrent();
           OB.Dal.remove(context.model.get('orderList').current, null, null);
         }
+      } else if (receipt.has('deletedLines')) {
+        if (OB.MobileApp.model.hasPermission('OBPOS_remove_ticket', true)) {
+          receipt.set('obposIsDeleted', true);
+          receipt.calculateGross();
+          receipt.save();
+          receipt.trigger('closed', {
+            callback: function () {
+              context.model.get('orderList').deleteCurrent();
+              context.model.get('orderList').synchronizeCurrentOrder();
+            }
+          });
+        } else {
+          context.model.get('orderList').deleteCurrent();
+        }
       } else {
         context.model.get('orderList').deleteCurrent();
       }
