diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index e7b401e9bfa..d22c35cd036 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -447,7 +447,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal // order and a valid selected order on_removed_order: function(removed_order,index,reason){ var order_list = this.get_order_list(); - if( (reason === 'abandon' || removed_order.temporary) && this.order_list.length > 0){ + if( (reason === 'abandon' || removed_order.temporary) && order_list.length > 0){ // when we intentionally remove an unfinished order, and there is another existing one this.set_order(order_list[index] || order_list[order_list.length -1]); }else{ @@ -482,7 +482,10 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal //removes the current order delete_current_order: function(){ - this.get('selectedOrder').destroy({'reason':'abandon'}); + var order = this.get_order(); + if (order) { + order.destroy({'reason':'abandon'}); + } }, // saves the order locally and try to send it to the backend. diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js index 6219969739b..46614f1e2ae 100644 --- a/addons/point_of_sale/static/src/js/screens.js +++ b/addons/point_of_sale/static/src/js/screens.js @@ -24,17 +24,12 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa module.ScreenSelector = instance.web.Class.extend({ init: function(options){ this.pos = options.pos; - - this.screen_set = options.screen_set || {}; - - this.popup_set = options.popup_set || {}; - + this.screen_set = options.screen_set || {}; + this.popup_set = options.popup_set || {}; this.default_screen = options.default_screen; - - this.current_popup = null; - - this.current_mode = options.default_mode || 'cashier'; - + this.startup_screen = options.startup_screen; + this.current_popup = null; + this.current_mode = options.default_mode || 'cashier'; this.current_screen = null; for(screen_name in this.screen_set){ @@ -45,9 +40,11 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa this.popup_set[popup_name].hide(); } - this.pos.get_order().set_screen_data({ - 'screen': this.default_screen, - }); + if (this.pos.get_order()) { + this.pos.get_order().set_screen_data({ + 'screen': this.default_screen, + }); + } this.pos.bind('change:selectedOrder', this.load_saved_screen, this); }, diff --git a/addons/point_of_sale/static/src/js/widgets.js b/addons/point_of_sale/static/src/js/widgets.js index 4f2c069d501..dba0328b3d1 100644 --- a/addons/point_of_sale/static/src/js/widgets.js +++ b/addons/point_of_sale/static/src/js/widgets.js @@ -115,7 +115,9 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa this.client_change_handler = function(event){ self.update_summary(); } - this.bind_order_events(); + if (this.pos.get_order()) { + this.bind_order_events(); + } }, enable_numpad: function(){ this.disable_numpad(); //ensure we don't register the callbacks twice @@ -133,12 +135,15 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa } }, set_editable: function(editable){ - this.editable = editable; - if(editable){ - this.enable_numpad(); - }else{ - this.disable_numpad(); - this.pos.get_order().deselectLine(); + var order = this.pos.get_order(); + if (order) { + this.editable = editable; + if (editable) { + this.enable_numpad(); + }else{ + this.disable_numpad(); + order.deselectLine(); + } } }, set_value: function(val) { @@ -215,6 +220,9 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa this.pos_widget.numpad.state.reset(); var order = this.pos.get_order(); + if (!order) { + return; + } var orderlines = order.get('orderLines').models; var el_str = openerp.qweb.render('OrderWidget',{widget:this, order:order, orderlines:orderlines}); @@ -251,6 +259,64 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa }, }); + module.OrderSelectorWidget = module.PosBaseWidget.extend({ + template: 'OrderSelectorWidget', + init: function(parent, options) { + this._super(parent, options); + this.pos.get('orders').bind('add remove change',this.renderElement,this); + this.pos.bind('change:selectedOrder',this.renderElement,this); + }, + get_order_by_uid: function(uid) { + var orders = this.pos.get_order_list(); + for (var i = 0; i < orders.length; i++) { + if (orders[i].uid === uid) { + return orders[i]; + } + } + return undefined; + }, + order_click_handler: function(event,$el) { + var order = this.get_order_by_uid($el.data('uid')); + if (order) { + this.pos.set_order(order); + } + }, + neworder_click_handler: function(event, $el) { + this.pos.add_new_order(); + }, + deleteorder_click_handler: function(event, $el) { + var self = this; + var order = this.pos.get_order(); + if (!order) { + return; + } else if ( !order.is_empty() ){ + this.screen_selector.show_popup('confirm',{ + message: _t('Destroy Current Order ?'), + comment: _t('You will lose any data associated with the current order'), + confirm: function(){ + self.pos.delete_current_order(); + }, + }); + } else { + this.pos.delete_current_order(); + } + }, + renderElement: function(){ + var self = this; + console.log('Re-Rendering Orders...',this.pos.get_order_list()); + this._super(); + this.$('.order-button.select-order').click(function(event){ + self.order_click_handler(event,$(this)); + }); + this.$('.neworder-button').click(function(event){ + self.neworder_click_handler(event,$(this)); + }); + this.$('.deleteorder-button').click(function(event){ + self.deleteorder_click_handler(event,$(this)); + }); + }, + }); + module.OrderButtonWidget = module.PosBaseWidget.extend({ template:'OrderButtonWidget', init: function(parent, options) { @@ -864,34 +930,6 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa self.renderElement(); - self.$('.neworder-button').click(function(){ - self.pos.add_new_order(); - }); - - self.$('.deleteorder-button').click(function(){ - if( !self.pos.get_order().is_empty() ){ - self.screen_selector.show_popup('confirm',{ - message: _t('Destroy Current Order ?'), - comment: _t('You will lose any data associated with the current order'), - confirm: function(){ - self.pos.delete_current_order(); - }, - }); - }else{ - self.pos.delete_current_order(); - } - }); - - //when a new order is created, add an order button widget - self.pos.get('orders').bind('add', function(new_order){ - var new_order_button = new module.OrderButtonWidget(null, { - order: new_order, - pos: self.pos - }); - new_order_button.appendTo(this.$('.orders')); - new_order_button.selectOrder(); - }, self); - self.pos.add_new_order(); self.build_widgets(); @@ -1018,6 +1056,9 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa // -------- Misc --------- + this.order_selector = new module.OrderSelectorWidget(this,{}); + this.order_selector.replace(this.$('.placeholder-OrderSelectorWidget')); + this.notification = new module.SynchNotificationWidget(this,{}); this.notification.appendTo(this.$('.pos-rightheader')); diff --git a/addons/point_of_sale/static/src/xml/pos.xml b/addons/point_of_sale/static/src/xml/pos.xml index 85f6badec96..c98c9eb0fed 100644 --- a/addons/point_of_sale/static/src/xml/pos.xml +++ b/addons/point_of_sale/static/src/xml/pos.xml @@ -11,11 +11,7 @@
-
- - - -
+
@@ -1111,23 +1107,39 @@ - - - - - - - - + +
+ + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + +
diff --git a/addons/pos_restaurant/static/src/css/restaurant.css b/addons/pos_restaurant/static/src/css/restaurant.css index 162b29c710a..8e7a353cbff 100644 --- a/addons/pos_restaurant/static/src/css/restaurant.css +++ b/addons/pos_restaurant/static/src/css/restaurant.css @@ -180,7 +180,33 @@ .floor-map .table .table-handle.left { left: 0; } .floor-map .table .table-handle.right { left: 100%; } - +.floor-map .table .order-count { + position: absolute; + top: 0; + left: 50%; + background: black; + width: 20px; + margin-top: -10px; + margin-left: -10px; + height: 20px; + line-height: 20px; + border-radius: 10px; +} + + +/* ------ FLOOR BUTTON IN THE ORDER SELECTOR ------- */ + +.pos .order-button.floor-button { + background: #35D374; + font-weight: bold; + font-size: 16px; + min-width: 128px; + padding-left: 16px; + padding-right: 16px; +} +.pos .order-button.floor-button .fa{ + font-size: 24px; +} diff --git a/addons/pos_restaurant/static/src/js/floors.js b/addons/pos_restaurant/static/src/js/floors.js index f661de5ae23..e55ba6e7b90 100644 --- a/addons/pos_restaurant/static/src/js/floors.js +++ b/addons/pos_restaurant/static/src/js/floors.js @@ -1,4 +1,5 @@ function openerp_restaurant_floors(instance,module){ + var QWeb = instance.web.qweb; var _t = instance.web._t; // At POS Startup, load the floors, and add them to the pos model @@ -26,6 +27,7 @@ function openerp_restaurant_floors(instance,module){ var floor = self.floors_by_id[tables[i].floor_id[0]]; if (floor) { floor.tables.push(tables[i]); + tables[i].floor = floor; } } }, @@ -212,7 +214,17 @@ function openerp_restaurant_floors(instance,module){ var model = new instance.web.Model('restaurant.table'); var fields = _.find(this.pos.models,function(model){ return model.model === 'restaurant.table'; }).fields; - model.call('create_from_ui',[this.table]).then(function(table_id){ + // we need a serializable copy of the table, containing only the fields defined on the server + var serializable_table = {}; + for (var i = 0; i < fields.length; i++) { + if (typeof this.table[fields[i]] !== 'undefined') { + serializable_table[fields[i]] = this.table[fields[i]]; + } + } + // and the id ... + serializable_table.id = this.table.id + + model.call('create_from_ui',[serializable_table]).then(function(table_id){ model.query(fields).filter([['id','=',table_id]]).first().then(function(table){ for (field in table) { self.table[field] = table[field]; @@ -253,6 +265,7 @@ function openerp_restaurant_floors(instance,module){ }, renderElement: function(){ var self = this; + this.order_count = this.pos.get_table_orders(this.table).length; this._super(); this.$el.on('mouseup', function(event){ self.click_handler(event,$(this)); }); @@ -281,16 +294,17 @@ function openerp_restaurant_floors(instance,module){ this.selected_table = null; this.editing = false; }, - show: function(){ - this._super(); - this.pos_widget.$('.order-selector').addClass('oe_invisible'); - }, hide: function(){ this._super(); if (this.editing) { this.toggle_editing(); } - this.pos_widget.$('.order-selector').removeClass('oe_invisible'); + }, + show: function(){ + this._super(); + for (var i = 0; i < this.table_widgets.length; i++) { + this.table_widgets[i].renderElement(); + } }, click_floor_button: function(event,$el){ var floor = this.pos.floors_by_id[$el.data('id')]; @@ -559,13 +573,35 @@ function openerp_restaurant_floors(instance,module){ } }); + // We need to modify the OrderSelector to hide itself when we're on + // the floor plan + module.OrderSelectorWidget.include({ + floor_button_click_handler: function(){ + this.pos.set_table(null); + }, + renderElement: function(){ + var self = this; + this._super(); + if (this.pos.get_order()) { + if (this.pos.table && this.pos.table.floor) { + this.$('.orders').prepend(QWeb.render('BackToFloorButton',{floor:this.pos.table.floor})); + this.$('.floor-button').click(function(){ + self.floor_button_click_handler(); + }); + } + this.$el.removeClass('oe_invisible'); + } else { + this.$el.addClass('oe_invisible'); + } + }, + }); + // We need to change the way the regular UI sees the orders, it // needs to only see the orders associated with the current table, // and when an order is validated, it needs to go back to the floor map. // // And when we change the table, we must create an order for that table // if there is none. - var _super_posmodel = module.PosModel.prototype; module.PosModel = module.PosModel.extend({ initialize: function(session, attributes) { @@ -588,6 +624,16 @@ function openerp_restaurant_floors(instance,module){ } }, + // we need to prevent the creation of orders when there is no + // table selected. + add_new_order: function() { + if (this.table) { + _super_posmodel.add_new_order.call(this); + } else { + console.warn("WARNING: orders cannot be created when there is no active table in restaurant mode"); + } + }, + // get the list of unpaid orders (associated to the current table) get_order_list: function() { var orders = _super_posmodel.get_order_list.call(this); @@ -604,12 +650,24 @@ function openerp_restaurant_floors(instance,module){ } }, + // get the list of orders associated to a table. FIXME: should be O(1) + get_table_orders: function(table) { + var orders = _super_posmodel.get_order_list.call(this); + var t_orders = []; + for (var i = 0; i < orders.length; i++) { + if (orders[i].table === table) { + t_orders.push(orders[i]); + } + } + return t_orders; + }, + // When we validate an order we go back to the floor plan. // When we cancel an order and there is multiple orders // on the table, stay on the table. on_removed_order: function(removed_order,index,reason){ var order_list = this.get_order_list(); - if( (reason === 'abandon' || removed_order.temporary) && this.order_list.length > 0){ + if( (reason === 'abandon' || removed_order.temporary) && order_list.length > 0){ this.set_order(order_list[index] || order_list[order_list.length -1]); }else{ // back to the floor plan diff --git a/addons/pos_restaurant/static/src/xml/floors.xml b/addons/pos_restaurant/static/src/xml/floors.xml index 8b2e2a5d4fe..16efe1f1aa7 100644 --- a/addons/pos_restaurant/static/src/xml/floors.xml +++ b/addons/pos_restaurant/static/src/xml/floors.xml @@ -4,6 +4,9 @@
+ + + @@ -26,6 +29,13 @@ + + + + + + +