[WIP] pos_restaurant, point_of_sale: almost done
Conflicts: addons/point_of_sale/static/src/js/screens.js addons/point_of_sale/static/src/xml/pos.xml
This commit is contained in:
committed by
Frédéric van der Essen
parent
c54a46e508
commit
42661572f9
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
|
||||
@@ -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'));
|
||||
|
||||
|
||||
@@ -11,11 +11,7 @@
|
||||
<span class="placeholder-UsernameWidget"></span>
|
||||
</div>
|
||||
<div class="pos-rightheader">
|
||||
<div class="order-selector">
|
||||
<span class="orders touch-scrollable"></span>
|
||||
<span class="order-button square neworder-button"><i class='fa fa-plus' /></span>
|
||||
<span class="order-button square deleteorder-button"><i class='fa fa-minus' /></span>
|
||||
</div>
|
||||
<span class="placeholder-OrderSelectorWidget"></span>
|
||||
<!-- here goes header buttons -->
|
||||
</div>
|
||||
</div>
|
||||
@@ -1111,23 +1107,39 @@
|
||||
</tr>
|
||||
</t>
|
||||
|
||||
<t t-name="OrderButtonWidget">
|
||||
<span class="order-button select-order">
|
||||
<t t-if='widget.selected'>
|
||||
<span class='order-sequence'>
|
||||
<t t-esc='widget.order.sequence_number' />
|
||||
</span>
|
||||
<t t-if="widget.order.get_client()">
|
||||
<i class='fa fa-user'/>
|
||||
<t t-name="OrderSelectorWidget">
|
||||
<div class="order-selector">
|
||||
<span class="orders touch-scrollable">
|
||||
|
||||
<t t-foreach="widget.pos.get_order_list()" t-as="order">
|
||||
<t t-if='order === widget.pos.get_order()'>
|
||||
<span class="order-button select-order selected" t-att-data-uid="order.uid">
|
||||
<span class='order-sequence'>
|
||||
<t t-esc='order.sequence_number' />
|
||||
</span>
|
||||
<t t-if="order.get_client()">
|
||||
<i class='fa fa-user'/>
|
||||
</t>
|
||||
<t t-esc="(order.get_client() ? order.get_client_name()+' : ':'Unknown Customer: ') + order.get('creationDate').toString('t')"/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if='order !== widget.pos.get_order()'>
|
||||
<span class="order-button select-order" t-att-data-uid="order.uid">
|
||||
<span class='order-sequence'>
|
||||
<t t-esc='order.sequence_number' />
|
||||
</span>
|
||||
</span>
|
||||
</t>
|
||||
</t>
|
||||
<t t-esc="(widget.order.get_client() ? widget.order.get_client_name()+' : ':'Unknown Customer: ') + moment(widget.order.get('creationDate')).format('LT')"/>
|
||||
</t>
|
||||
<t t-if='!widget.selected'>
|
||||
<span class='order-sequence'>
|
||||
<t t-esc='widget.order.sequence_number' />
|
||||
</span>
|
||||
</t>
|
||||
</span>
|
||||
|
||||
</span>
|
||||
<span class="order-button square neworder-button">
|
||||
<i class='fa fa-plus' />
|
||||
</span>
|
||||
<span class="order-button square deleteorder-button">
|
||||
<i class='fa fa-minus' />
|
||||
</span>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="UsernameWidget">
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
<t t-name="TableWidget">
|
||||
<t t-if='!widget.selected'>
|
||||
<div class='table' t-att-style='widget.table_style_str()'>
|
||||
<t t-if='widget.order_count'>
|
||||
<span class='order-count'><t t-esc='widget.order_count'/></span>
|
||||
</t>
|
||||
<span class='label'>
|
||||
<t t-esc='widget.table.name' />
|
||||
</span>
|
||||
@@ -26,6 +29,13 @@
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="BackToFloorButton">
|
||||
<span class="order-button floor-button">
|
||||
<i class='fa fa-angle-double-left'/>
|
||||
<t t-esc="floor.name"/>
|
||||
</span>
|
||||
</t>
|
||||
|
||||
<t t-name="FloorScreenWidget">
|
||||
<div class='floor-screen screen'>
|
||||
<div class='screen-content-flexbox'>
|
||||
|
||||
Reference in New Issue
Block a user