From 5979662ea825e57077a92f150fa540bf749fe2d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20van=20der=20Essen?= Date: Wed, 29 Apr 2015 16:30:46 +0200 Subject: [PATCH] [IMP] point_of_sale: various improvements for failed orders handling - The POS will retry sending unsent orders before closing the pos. - A warning is emitted before closing the POS with unsent orders. - Errors message will not be repeated on each order posting. - The status widget shows a different icon for offline and server crashes. --- addons/point_of_sale/static/src/js/chrome.js | 4 +-- addons/point_of_sale/static/src/js/gui.js | 32 ++++++++++++++++++ addons/point_of_sale/static/src/js/models.js | 35 +++++++++++--------- addons/point_of_sale/static/src/xml/pos.xml | 3 ++ 4 files changed, 57 insertions(+), 17 deletions(-) diff --git a/addons/point_of_sale/static/src/js/chrome.js b/addons/point_of_sale/static/src/js/chrome.js index e4ad8aff759..5e397951c46 100644 --- a/addons/point_of_sale/static/src/js/chrome.js +++ b/addons/point_of_sale/static/src/js/chrome.js @@ -316,7 +316,7 @@ var DebugWidget = PosBaseWidget.extend({ // status in the point of sale header. var StatusWidget = PosBaseWidget.extend({ - status: ['connected','connecting','disconnected','warning'], + status: ['connected','connecting','disconnected','warning','error'], set_status: function(status,msg){ for(var i = 0; i < this.status.length; i++){ this.$('.js_'+this.status[i]).addClass('oe_hidden'); @@ -344,7 +344,7 @@ var SynchNotificationWidget = StatusWidget.extend({ self.set_status(synch.state, synch.pending); }); this.$el.click(function(){ - self.pos.push_order(); + self.pos.push_order(null,{'show_error':true}); }); }, }); diff --git a/addons/point_of_sale/static/src/js/gui.js b/addons/point_of_sale/static/src/js/gui.js index a996b85c649..01bdd958adb 100644 --- a/addons/point_of_sale/static/src/js/gui.js +++ b/addons/point_of_sale/static/src/js/gui.js @@ -265,6 +265,38 @@ var Gui = core.Class.extend({ /* ---- Gui: CLOSING THE POINT OF SALE ---- */ close: function() { + var self = this; + var pending = this.pos.db.get_orders().length; + + if (!pending) { + this._close(); + } else { + this.pos.push_order().always(function() { + var pending = self.pos.db.get_orders().length; + if (!pending) { + self._close(); + } else { + var reason = self.pos.get('failed') ? + 'configuration errors' : + 'internet connection issues'; + + self.show_popup('confirm', { + 'title': _t('Offline Orders'), + 'body': _t(['Some orders could not be submitted to', + 'the server due to ' + reason + '.', + 'You can exit the Point of Sale, but do', + 'not close the session before the issue', + 'has been resolved.'].join(' ')), + 'confirm': function() { + self._close(); + }, + }); + } + }); + } + }, + + _close: function() { var self = this; this.chrome.loading_show(); this.chrome.loading_message(_t('Closing ...')); diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 499dbc1714e..f88deefe960 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -71,15 +71,6 @@ exports.PosModel = Backbone.Model.extend({ 'selectedOrder': null, }); - this.bind('change:synch',function(pos,synch){ - clearTimeout(self.synch_timeout); - self.synch_timeout = setTimeout(function(){ - if(synch.state !== 'disconnected' && synch.pending > 0){ - self.set('synch',{state:'disconnected', pending:synch.pending}); - } - },3000); - }); - this.get('orders').bind('remove', function(order,_unused_,options){ self.on_removed_order(order,options.index,options.reason); }); @@ -617,7 +608,8 @@ exports.PosModel = Backbone.Model.extend({ // saves the order locally and try to send it to the backend. // it returns a deferred that succeeds after having tried to send the order and all the other pending orders. - push_order: function(order) { + push_order: function(order, opts) { + opts = opts || {}; var self = this; if(order){ @@ -627,7 +619,7 @@ exports.PosModel = Backbone.Model.extend({ var pushed = new $.Deferred(); this.flush_mutex.exec(function(){ - var flushed = self._flush_orders(self.db.get_orders()); + var flushed = self._flush_orders(self.db.get_orders(), opts); flushed.always(function(ids){ pushed.resolve(); @@ -705,6 +697,13 @@ exports.PosModel = Backbone.Model.extend({ }); return server_ids; + }).fail(function(error, event){ + var pending = self.db.get_orders().length; + if (self.get('failed')) { + self.set('synch', { state: 'error', pending: pending }); + } else { + self.set('synch', { state: 'disconnected', pending: pending }); + } }); }, @@ -742,6 +741,7 @@ exports.PosModel = Backbone.Model.extend({ _.each(orders, function (order) { self.db.remove_order(order.id); }); + self.set('failed',false); return server_ids; }).fail(function (error, event){ if(error.code === 200 ){ // Business Logic Error, not a connection problem @@ -749,10 +749,15 @@ exports.PosModel = Backbone.Model.extend({ if (error.data.exception_type == 'warning') { delete error.data.debug; } - self.gui.show_popup('error-traceback',{ - 'title': error.data.message, - 'body': error.data.debug - }); + + // Hide error if already shown before ... + if ((!self.get('failed') || options.show_error) && !options.to_invoice) { + self.gui.show_popup('error-traceback',{ + 'title': error.data.message, + 'body': error.data.debug + }); + } + self.set('failed',error) } // prevent an error popup creation by the rpc failure // we want the failure to be silent as we send the orders in the background diff --git a/addons/point_of_sale/static/src/xml/pos.xml b/addons/point_of_sale/static/src/xml/pos.xml index 5f898f15e34..d9c78f88b30 100644 --- a/addons/point_of_sale/static/src/xml/pos.xml +++ b/addons/point_of_sale/static/src/xml/pos.xml @@ -60,6 +60,9 @@
+
+ +