[IMP] point_of_sale: order widget is now complete
bzr revid: fva@openerp.com-20120628123825-hrat3tlhtyz8yv1i
This commit is contained in:
parent
1f0d6e4cb0
commit
f69643a4a1
File diff suppressed because one or more lines are too long
|
@ -76,8 +76,13 @@
|
|||
height: 100%;
|
||||
}
|
||||
.point-of-sale #topheader {
|
||||
position:absolute;
|
||||
left:0;
|
||||
top:0;
|
||||
width: 100%;
|
||||
height: 54px;
|
||||
height: 33px;
|
||||
margin:0;
|
||||
padding:0;
|
||||
color: gray;
|
||||
border-top: solid 1px #d3d3d3;
|
||||
border-bottom: solid 1px black;
|
||||
|
@ -87,40 +92,47 @@
|
|||
}
|
||||
.point-of-sale #topheader button {
|
||||
color: black;
|
||||
height:29px;
|
||||
margin:2px;
|
||||
margin-right:0px;
|
||||
border: 1px solid black;
|
||||
background: #7f82ac;
|
||||
background: -moz-linear-gradient(#b2b3d7, #7f82ac);
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#b2b3d7), to(#7f82ac));
|
||||
}
|
||||
.point-of-sale #branding, .point-of-sale #rightheader {
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
height: 35px;
|
||||
padding: 10px;
|
||||
}
|
||||
.point-of-sale #rightheader {
|
||||
float: none;
|
||||
margin-left: 440px;
|
||||
}
|
||||
.point-of-sale #branding {
|
||||
.point-of-sale #branding{
|
||||
position: absolute;
|
||||
display: table-cell;
|
||||
left:0;
|
||||
top:0;
|
||||
width:439px;
|
||||
height:100%;
|
||||
margin:0;
|
||||
padding:0;
|
||||
border-right: 1px solid #373737;
|
||||
text-align: left;
|
||||
width: 419px;
|
||||
text-align:left;
|
||||
line-height:100%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.point-of-sale #branding img {
|
||||
height: 32px;
|
||||
width: 116px;
|
||||
margin-left:5px;
|
||||
vertical-align:middle;
|
||||
}
|
||||
.point-of-sale #rightheader {
|
||||
position: absolute;
|
||||
left:440px;
|
||||
right:0;
|
||||
top:0;
|
||||
height:100%;
|
||||
}
|
||||
.point-of-sale #neworder-button {
|
||||
width: 32px;
|
||||
padding: 4px 10px;
|
||||
margin-left:5px;
|
||||
}
|
||||
.point-of-sale #loggedas {
|
||||
float: right;
|
||||
padding: 5px 9px;
|
||||
text-align: center;
|
||||
color: white;
|
||||
border-left: 1px solid #373737;
|
||||
}
|
||||
.point-of-sale #loggedas p {
|
||||
margin: 0 0 3px 0;
|
||||
|
@ -128,7 +140,7 @@
|
|||
.point-of-sale #content {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 56px;
|
||||
top: 35px;
|
||||
bottom: 0;
|
||||
background: #F0EEEE; //#E6E4E4; //yellow; //#F0EEEE;
|
||||
}
|
||||
|
@ -228,8 +240,11 @@
|
|||
}
|
||||
.point-of-sale .product-list {
|
||||
padding:10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.point-of-sale .product-list-scroller{
|
||||
width:100%;
|
||||
height:100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.point-of-sale .product-list-container {
|
||||
position:absolute;
|
||||
|
@ -311,7 +326,8 @@
|
|||
display: inline-block;
|
||||
font-size: 11px;
|
||||
margin: 5px;
|
||||
max-width: 120px;
|
||||
width: 120px;
|
||||
height:120px;
|
||||
background:#fff;
|
||||
border: 1px solid #fff;
|
||||
-moz-border-radius: 2px;
|
||||
|
@ -320,7 +336,6 @@
|
|||
-moz-box-shadow: 0px 1px 8px #777777;
|
||||
-webkit-box-shadow: 0px 1px 8px rgba(0,0,0,0.2);
|
||||
-box-shadow: 0px 1px 8px rgba(0,0,0,0.9);
|
||||
-webkit-filter: blur(3px);
|
||||
}
|
||||
.point-of-sale .product .product-img {
|
||||
position: relative;
|
||||
|
@ -361,6 +376,7 @@
|
|||
top:auto;
|
||||
width:100%;
|
||||
background: -webkit-linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1));
|
||||
/*background:#FFF;*/
|
||||
padding: 3px;
|
||||
padding-top:15px;
|
||||
}
|
||||
|
@ -517,9 +533,13 @@
|
|||
.point-of-sale .order-container{
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
bottom: 229px;
|
||||
bottom: 232px;
|
||||
width:100%;
|
||||
background: #F0EEEE;
|
||||
}
|
||||
.point-of-sale .order-scroller{
|
||||
width:100%;
|
||||
height:100%;
|
||||
overflow:hidden;
|
||||
}
|
||||
.point-of-sale .order{
|
||||
|
@ -530,10 +550,12 @@
|
|||
margin-left:16px;
|
||||
margin-right:16px;
|
||||
margin-top:16px;
|
||||
margin-bottom:16px;
|
||||
font-size:16px;
|
||||
-webkit-box-shadow: 0px 5px 16px rgba(0,0,0, 0.3);
|
||||
|
||||
}
|
||||
.point-of-sale .orderline{
|
||||
.point-of-sale .order .orderline{
|
||||
width:100%;
|
||||
margin:0px;
|
||||
padding-top:3px;
|
||||
|
@ -544,39 +566,62 @@
|
|||
-webkit-box-sizing: border-box;
|
||||
-webkit-transition: background 250ms ease-in-out;
|
||||
}
|
||||
.point-of-sale .orderline:hover{
|
||||
.point-of-sale .order .empty{
|
||||
text-align:center;
|
||||
margin-top: 15px;
|
||||
margin-bottom: 5px;
|
||||
color:#999;
|
||||
font-weight: normal;
|
||||
|
||||
}
|
||||
.point-of-sale .order .orderline:hover{
|
||||
background: rgba(140,143,183,0.05);
|
||||
-webkit-transition: background 50ms ease-in-out;
|
||||
}
|
||||
|
||||
.point-of-sale .orderline.selected{
|
||||
.point-of-sale .order .orderline.selected{
|
||||
background: rgba(140,143,183,0.2);
|
||||
-webkit-transition: background 250ms ease-in-out;
|
||||
cursor: default;
|
||||
}
|
||||
.point-of-sale .orderline .product-name{
|
||||
.point-of-sale .order .orderline .product-name{
|
||||
padding:0;
|
||||
display:inline-block;
|
||||
font-size:18px;
|
||||
font-weight: bold;
|
||||
width:80%;
|
||||
overflow:hidden;
|
||||
}
|
||||
.point-of-sale .orderline .price{
|
||||
.point-of-sale .order .orderline .price{
|
||||
padding:0;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
float:right;
|
||||
}
|
||||
.point-of-sale .orderline .info-list{
|
||||
.point-of-sale .order .orderline .info-list{
|
||||
color: #888;
|
||||
margin-left:10px;
|
||||
}
|
||||
.point-of-sale .orderline .info-list em{
|
||||
.point-of-sale .order .orderline .info-list em{
|
||||
color: #777;
|
||||
font-weight: bold;
|
||||
font-style:normal;
|
||||
}
|
||||
.point-of-sale .order .summary{
|
||||
width:100%;
|
||||
text-align:right;
|
||||
font-weight: bold;
|
||||
margin-top:20px;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
.point-of-sale .order .summary .line{
|
||||
margin-right:15px;
|
||||
padding-top:5px;
|
||||
border-top: solid 2px;
|
||||
border-color:#777;
|
||||
}
|
||||
.point-of-sale .order .summary .line.empty{
|
||||
border-color:#BBB;
|
||||
color:#999;
|
||||
}
|
||||
|
||||
/* ----------------------- ACTION BAR ---------------------- */
|
||||
|
||||
|
@ -637,13 +682,6 @@
|
|||
background: -webkit-gradient(linear, left top, left bottom, from(#f0f0f0), to(#e2e2e2));
|
||||
-webkit-box-shadow: 0px 2px 2px rgba(0,0,0, 0.3);
|
||||
}
|
||||
.point-of-sale .total{
|
||||
line-height: 105px;
|
||||
font-size: 26px;
|
||||
margin: 0;
|
||||
margin-left: 180px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.point-of-sale .pos-actionbar .button .label{
|
||||
margin-top: 37px;
|
||||
}
|
||||
|
@ -762,10 +800,10 @@
|
|||
|
||||
.point-of-sale .scrollbar{
|
||||
position:absolute;
|
||||
top:0px;
|
||||
right:0px;
|
||||
top:4px;
|
||||
right:7px;
|
||||
width:48px;
|
||||
height:100%;
|
||||
bottom:4px;
|
||||
background: rgba(0,0,0,0.1);
|
||||
|
||||
}
|
||||
|
|
|
@ -92,13 +92,16 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
'shop': null,
|
||||
'company': null,
|
||||
'user': null,
|
||||
'user_list': null,
|
||||
'cashier': null,
|
||||
'customer': null,
|
||||
|
||||
'orders': new module.OrderCollection(),
|
||||
//this is the product list as seen by the product list widgets, it will change based on the category filters
|
||||
'products': new module.ProductCollection(),
|
||||
'cashRegisters': null,
|
||||
|
||||
'product_list': null, // the list of all products.
|
||||
'product_list': null, // the list of all products, does not change.
|
||||
'bank_statements': null,
|
||||
'taxes': null,
|
||||
'pos_session': null,
|
||||
|
@ -119,12 +122,34 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
|
||||
var prod_def = fetch(
|
||||
'product.product',
|
||||
['name', 'list_price', 'pos_categ_id', 'taxes_id','product_image_small', 'ean13', 'to_weight'],
|
||||
['name', 'list_price', 'pos_categ_id', 'taxes_id','product_image_small', 'ean13', 'to_weight', 'uom_id', 'uos_id', 'uos_coeff', 'mes_type'],
|
||||
[['pos_categ_id','!=', false]]
|
||||
).then(function(result){
|
||||
self.set({'product_list': result});
|
||||
});
|
||||
|
||||
var uom_def = fetch( //unit of measure
|
||||
'product.uom',
|
||||
null,
|
||||
null
|
||||
).then(function(result){
|
||||
self.set({'units': result});
|
||||
var units_by_id = {};
|
||||
for(var i = 0, len = result.length; i < len; i++){
|
||||
units_by_id[result[i].id] = result[i];
|
||||
}
|
||||
self.set({'units_by_id':units_by_id});
|
||||
});
|
||||
|
||||
var user_def = fetch(
|
||||
'res.users',
|
||||
['name','ean13']
|
||||
[['ean13', '!=', false]]
|
||||
).then(function(result){
|
||||
self.set({'user_list':result});
|
||||
});
|
||||
|
||||
|
||||
// associate the products with their categories
|
||||
var prod_process_def = $.when(cat_def, prod_def)
|
||||
.pipe(function(){
|
||||
|
@ -221,7 +246,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
});
|
||||
|
||||
// when all the data has loaded, we compute some stuff, and declare the Pos ready to be used.
|
||||
$.when(cat_def, prod_def, session_def, tax_def, prod_process_def, this.get_app_data(), this.flush())
|
||||
$.when(cat_def, prod_def, user_def, uom_def, session_def, tax_def, prod_process_def, this.get_app_data(), this.flush())
|
||||
.then(function(){
|
||||
//self.build_tree();
|
||||
self.build_categories();
|
||||
|
@ -241,6 +266,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
console.log('PosModel data has been loaded:');
|
||||
console.log('PosModel: categories:',this.get('categories'));
|
||||
console.log('PosModel: product_list:',this.get('product_list'));
|
||||
console.log('PosModel: units:',this.get('units'));
|
||||
console.log('PosModel: bank_statements:',this.get('bank_statements'));
|
||||
console.log('PosModel: journals:',this.get('journals'));
|
||||
console.log('PosModel: taxes:',this.get('taxes'));
|
||||
|
@ -250,6 +276,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
console.log('PosModel: shop:',this.get('shop'));
|
||||
console.log('PosModel: company:',this.get('company'));
|
||||
console.log('PosModel: currency:',this.get('currency'));
|
||||
console.log('PosModel: user_list:',this.get('user_list'));
|
||||
console.log('PosModel.session:',this.session);
|
||||
console.log('PosModel.categories:',this.categories);
|
||||
console.log('PosModel end of data log.');
|
||||
|
@ -493,7 +520,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
discount: 0,
|
||||
weighted: false,
|
||||
product_type: 'unit',
|
||||
unit: 'Unit',
|
||||
selected: false,
|
||||
},
|
||||
initialize: function(attributes) {
|
||||
this.pos = attributes.pos;
|
||||
|
@ -504,29 +531,44 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
this.set({weighted: true});
|
||||
this.set({product_type: 'weight'});
|
||||
}
|
||||
|
||||
this.bind('change:quantity', function(unused, qty) {
|
||||
if (qty == 0)
|
||||
this.trigger('killme');
|
||||
}, this);
|
||||
},
|
||||
|
||||
// we override the attributes set to prevent some out of range values
|
||||
// we also round the quantity according to the unit of measure rounding methods
|
||||
set: function(attributes, options){
|
||||
var attributes = _.clone(attributes); //so we don't modify the argument
|
||||
if(attributes.discount > 100){
|
||||
attributes.discount = 100;
|
||||
}else if(attributes.discount < 0){
|
||||
attributes.discount = 0;
|
||||
}
|
||||
if(attributes.quantity < 0){
|
||||
attributes.quantity = 0;
|
||||
}
|
||||
if(attributes.list_price < 0){
|
||||
attributes.list_price = 0;
|
||||
if(_.isNaN(attributes.quantity)){
|
||||
console.log(this.get('order'));
|
||||
this.get('order').removeOrderline(this);
|
||||
return this;
|
||||
}else if(attributes.quantity !== undefined){
|
||||
attributes.quantity = Math.max(0,attributes.quantity);
|
||||
var unit = this.get_unit();
|
||||
if(unit && attributes.quantity){
|
||||
attributes.quantity = Math.max(unit.rounding, Math.round( attributes.quantity / unit.rounding) * unit.rounding);
|
||||
}
|
||||
}
|
||||
Backbone.Model.prototype.set.call(this,attributes,options);
|
||||
return this;
|
||||
},
|
||||
// returns the unit of measure associated with the product if there is one, undefined otherwise
|
||||
get_unit: function(){
|
||||
var unit_id = (this.get('uos_id') || this.get('uom_id'));
|
||||
if(!unit_id){
|
||||
return undefined;
|
||||
}
|
||||
unit_id = unit_id[0];
|
||||
if(!this.pos){
|
||||
return undefined;
|
||||
}
|
||||
return this.pos.get('units_by_id')[unit_id];
|
||||
},
|
||||
|
||||
|
||||
// when we add an new orderline we want to merge it with the last line to see reduce the number of items
|
||||
// in the orderline. This returns true if it makes sense to merge the two
|
||||
|
@ -669,6 +711,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
// there is always an active ('selected') order in the Pos, a new one is created
|
||||
// automaticaly once an order is completed and sent to the server.
|
||||
|
||||
|
||||
module.Order = Backbone.Model.extend({
|
||||
initialize: function(attributes){
|
||||
Backbone.Model.prototype.initialize.apply(this, arguments);
|
||||
|
@ -680,7 +723,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
});
|
||||
this.pos = attributes.pos; //TODO put that in set and remember to use 'get' to read it ...
|
||||
this.pos_widget = attributes.pos_widget; //FIXME we shouldn't depend on pos_widget in the models
|
||||
this.last_orderline = undefined;
|
||||
this.selected_orderline = undefined;
|
||||
return this;
|
||||
},
|
||||
generateUniqueId: function() {
|
||||
|
@ -689,41 +732,24 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
addProduct: function(product){
|
||||
var attr = product.toJSON();
|
||||
attr.pos = this.pos;
|
||||
attr.order = this;
|
||||
var line = new module.Orderline(attr);
|
||||
var self = this;
|
||||
|
||||
if( this.last_orderline && this.last_orderline.can_be_merged_with(line) ){
|
||||
this.last_orderline.merge(line);
|
||||
var last_orderline = this.getLastOrderline();
|
||||
if( last_orderline && last_orderline.can_be_merged_with(line) ){
|
||||
last_orderline.merge(line);
|
||||
}else{
|
||||
this.get('orderLines').add(line);
|
||||
line.bind('killme', function() {
|
||||
this.get('orderLines').remove(line);
|
||||
}, this);
|
||||
this.last_orderline = line;
|
||||
}
|
||||
this.selectLine(this.getLastOrderline());
|
||||
},
|
||||
addProductOld: function(product) {
|
||||
var existing;
|
||||
|
||||
existing = (this.get('orderLines')).get(product.id);
|
||||
if (existing != null) {
|
||||
this.last_orderline = existing;
|
||||
if(existing.get('weighted')){
|
||||
existing.incrementWeight(product.attributes.weight);
|
||||
}else{
|
||||
existing.incrementQuantity();
|
||||
}
|
||||
} else {
|
||||
var attr = product.toJSON();
|
||||
attr.pos = this.pos;
|
||||
var line = new module.Orderline(attr);
|
||||
console.log('new Orderline:',line,attr);
|
||||
this.last_orderline = line;
|
||||
this.get('orderLines').add(line);
|
||||
line.bind('killme', function() {
|
||||
this.get('orderLines').remove(line);
|
||||
}, this);
|
||||
}
|
||||
removeOrderline: function( line ){
|
||||
this.get('orderLines').remove(line);
|
||||
this.selectLine(this.getLastOrderline());
|
||||
},
|
||||
getLastOrderline: function(){
|
||||
return this.get('orderLines').at(this.get('orderLines').length -1);
|
||||
},
|
||||
addPaymentLine: function(cashRegister) {
|
||||
var newPaymentline;
|
||||
|
@ -787,6 +813,23 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
pos_session_id: this.pos.get('pos_session').id,
|
||||
};
|
||||
},
|
||||
getSelectedLine: function(){
|
||||
return this.selected_orderline;
|
||||
},
|
||||
selectLine: function(line){
|
||||
if(line){
|
||||
if(line !== this.selected_orderline){
|
||||
if(this.selected_orderline){
|
||||
this.selected_orderline.set({'selected':false});
|
||||
}
|
||||
this.selected_orderline = line;
|
||||
this.selected_orderline.set({'selected':true});
|
||||
}
|
||||
}else{
|
||||
this.selected_orderline = undefined;
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
module.OrderCollection = Backbone.Collection.extend({
|
||||
|
@ -821,15 +864,18 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
this.updateTarget();
|
||||
},
|
||||
deleteLastChar: function() {
|
||||
var tempNewBuffer;
|
||||
tempNewBuffer = (this.get('buffer')).slice(0, -1) || "0";
|
||||
if (isNaN(tempNewBuffer)) {
|
||||
tempNewBuffer = "0";
|
||||
var tempNewBuffer = this.get('buffer').slice(0, -1);
|
||||
|
||||
if(!tempNewBuffer){
|
||||
this.set({ buffer: "0" });
|
||||
this.killTarget();
|
||||
}else{
|
||||
if (isNaN(tempNewBuffer)) {
|
||||
tempNewBuffer = "0";
|
||||
}
|
||||
this.set({ buffer: tempNewBuffer });
|
||||
this.updateTarget();
|
||||
}
|
||||
this.set({
|
||||
buffer: tempNewBuffer
|
||||
});
|
||||
this.updateTarget();
|
||||
},
|
||||
switchSign: function() {
|
||||
var oldBuffer;
|
||||
|
@ -858,5 +904,8 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
this.trigger('set_value', parseFloat(bufferContent));
|
||||
}
|
||||
},
|
||||
killTarget: function(){
|
||||
this.trigger('set_value',Number.NaN);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -238,7 +238,6 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
|
||||
show_numpad: true,
|
||||
show_leftpane: true,
|
||||
show_total: true,
|
||||
|
||||
help_button_action: function(){
|
||||
this.pos_widget.screen_selector.show_popup('help');
|
||||
|
@ -290,7 +289,6 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
this.pos_widget.set_numpad_visible(this.show_numpad && cashier_mode);
|
||||
this.pos_widget.set_leftpane_visible(this.show_leftpane);
|
||||
this.pos_widget.set_cashier_controls_visible(cashier_mode);
|
||||
this.pos_widget.action_bar.set_element_visible('total', this.show_total);
|
||||
this.pos_widget.action_bar.set_element_visible('help-button', !cashier_mode, function(){ self.help_button_action(); });
|
||||
this.pos_widget.action_bar.set_element_visible('logout-button', cashier_mode, function(){ self.logout_button_action(); });
|
||||
this.pos_widget.action_bar.set_element_visible('close-button', cashier_mode);
|
||||
|
@ -345,8 +343,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
|
||||
module.ScaleProductScreenWidget = module.BaseScreenWidget.extend({
|
||||
template:'ScaleProductSelectionScreenWidget',
|
||||
renderElement: function(){
|
||||
this._super();
|
||||
start: function(){
|
||||
this.product_categories_widget = new module.ProductCategoriesWidget(this,{
|
||||
pos:this.pos,
|
||||
product_type: 'weightable',
|
||||
|
@ -465,7 +462,6 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
|
||||
show_numpad: false,
|
||||
show_leftpane: false,
|
||||
show_total: false,
|
||||
|
||||
show: function(){
|
||||
this._super();
|
||||
|
@ -488,7 +484,6 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
|
||||
show_numpad: false,
|
||||
show_leftpane: true,
|
||||
show_total: true,
|
||||
|
||||
show: function(){
|
||||
this._super();
|
||||
|
@ -519,10 +514,8 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
|
||||
show_numpad: true,
|
||||
show_leftpane: true,
|
||||
show_total: true,
|
||||
|
||||
renderElement: function(){
|
||||
this._super();
|
||||
start: function(){ //FIXME this should work as renderElement... but then the categories aren't properly set. explore why
|
||||
this.product_categories_widget = new module.ProductCategoriesWidget(this,{});
|
||||
this.product_categories_widget.replace($('.placeholder-ProductCategoriesWidget'));
|
||||
|
||||
|
@ -562,7 +555,6 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
|
||||
show_numpad: true,
|
||||
show_leftpane: true,
|
||||
show_total: true,
|
||||
|
||||
init: function(parent, options) {
|
||||
this._super(parent,options);
|
||||
|
|
|
@ -8,8 +8,11 @@
|
|||
* jquery selector string that will match on the widget's dom element. If there is no widget provided,
|
||||
* it will match on the document
|
||||
* step: on each click, the target will be scrolled by it's deplayed size multiplied by this value.
|
||||
* delay: this is the duration of the scrolling animation
|
||||
* duration: this is the duration of the scrolling animation
|
||||
* wheel_step: the target will be scrolled by wheel_step pixels on each mouse scroll.
|
||||
* track_bottom: the target will be kept on bottom when it's on the bottom and the size has changed
|
||||
* on_show: this function will be called with the scrollbar as sole argument when the scrollbar is shown
|
||||
* on_hide: this function will be called with the scrollbar as sole argument when the scrollbar is hidden
|
||||
*/
|
||||
function openerp_pos_scrollbar(instance, module){ //module is instance.point_of_sale
|
||||
|
||||
|
@ -17,17 +20,39 @@ function openerp_pos_scrollbar(instance, module){ //module is instance.point_of_
|
|||
template:'ScrollbarWidget',
|
||||
|
||||
init: function(parent,options){
|
||||
var self = this;
|
||||
options = options || {};
|
||||
this._super(parent,options);
|
||||
this.target_widget = options.target_widget;
|
||||
this.target_selector = options.target_selector;
|
||||
this.scroll_target = this.target().scrollTop();
|
||||
this.scroll_step = options.step || 0.8;
|
||||
this.scroll_delay = options.delay || 250;
|
||||
this.scroll_duration = options.duration || 250;
|
||||
this.wheel_step = options.wheel_step || 80;
|
||||
this.name = options.name || 'unnamed';
|
||||
this.bottom = false; // true if the scroller cannot be scrolled further
|
||||
this.track_bottom = options.track_bottom || false;
|
||||
this.on_show = options.on_show || function(){};
|
||||
this.on_hide = options.on_hide || function(){};
|
||||
|
||||
// these handlers are declared once for the object's lifetime so that we can bind and unbind them.
|
||||
this.resize_handler = function(){
|
||||
setTimeout(function(){
|
||||
if(self.bottom && self.track_bottom){
|
||||
self.set_position(Number.MAX_VALUE);
|
||||
}
|
||||
self.update_scroller_dimensions();
|
||||
self.update_button_status();
|
||||
self.auto_hide(false);
|
||||
},0);
|
||||
};
|
||||
this.target_mousewheel_handler = function(event,delta){
|
||||
self.scroll(delta*self.wheel_step);
|
||||
}
|
||||
},
|
||||
|
||||
start: function(){
|
||||
renderElement: function(){
|
||||
this._super();
|
||||
var self = this;
|
||||
this.$('.up-button').off('click').click(function(){
|
||||
self.page_up();
|
||||
|
@ -35,17 +60,9 @@ function openerp_pos_scrollbar(instance, module){ //module is instance.point_of_
|
|||
this.$('.down-button').off('click').click(function(){
|
||||
self.page_down();
|
||||
});
|
||||
this.update_scroller_dimensions();
|
||||
this.update_scroller_dimensions(false);
|
||||
this.update_button_status();
|
||||
this.auto_hide(false);
|
||||
$(window).resize(function(){ //FIXME REMOVE HANDLER ...
|
||||
self.update_scroller_dimensions();
|
||||
self.update_button_status();
|
||||
self.auto_hide(false);
|
||||
});
|
||||
this.target().bind('mousewheel',function(event,delta){
|
||||
self.scroll(delta*self.wheel_step);
|
||||
});
|
||||
this.$element.bind('mousewheel',function(event,delta){
|
||||
self.scroll(delta*self.wheel_step);
|
||||
});
|
||||
|
@ -59,7 +76,29 @@ function openerp_pos_scrollbar(instance, module){ //module is instance.point_of_
|
|||
self.page_down();
|
||||
}
|
||||
});
|
||||
$(window).unbind('resize',this.resize_handler);
|
||||
$(window).bind('resize',this.resize_handler);
|
||||
|
||||
this.target().unbind('mousewheel',this.target_mousweheel_handler);
|
||||
this.target().bind('mousewheel',this.target_mousewheel_handler);
|
||||
|
||||
// because the rendering is asynchronous we must wait for the next javascript update
|
||||
// for good dimensions values
|
||||
setTimeout(function(){
|
||||
self.update_scroller_dimensions(false);
|
||||
self.update_button_status();
|
||||
self.auto_hide(false);
|
||||
},0);
|
||||
},
|
||||
|
||||
// binds the window resize and the target scrolling events.
|
||||
// it is good advice not to bind these multiple_times
|
||||
bind_events:function(){
|
||||
$(window).resize(function(){
|
||||
});
|
||||
this.target().bind('mousewheel',function(event,delta){
|
||||
self.scroll(delta*self.wheel_step);
|
||||
});
|
||||
},
|
||||
|
||||
// shows the scrollbar. if animated is true, it will do it in an animated fashion
|
||||
|
@ -69,6 +108,7 @@ function openerp_pos_scrollbar(instance, module){ //module is instance.point_of_
|
|||
}else{
|
||||
this.$element.show().css('width','48px');
|
||||
}
|
||||
this.on_show(this);
|
||||
},
|
||||
|
||||
// hides the scrollbar. if animated is true, it will do it in a animated fashion
|
||||
|
@ -79,6 +119,7 @@ function openerp_pos_scrollbar(instance, module){ //module is instance.point_of_
|
|||
}else{
|
||||
this.$element.hide().css('width','0px');
|
||||
}
|
||||
this.on_hide(this);
|
||||
},
|
||||
|
||||
// returns the scroller position and other information as a dictionnary with the following fields:
|
||||
|
@ -88,12 +129,12 @@ function openerp_pos_scrollbar(instance, module){ //module is instance.point_of_
|
|||
// bar_height: the height of the scrollbar's inner region
|
||||
scroller_dimensions: function(){
|
||||
var target = this.target()[0];
|
||||
var scroller_height = target.clientHeight / target.scrollHeight;
|
||||
var scroller_pos = this.scroll_target / target.scrollHeight;
|
||||
var button_up_height = this.$('.up-button')[0].offsetHeight;
|
||||
var button_down_height = this.$('.down-button')[0].offsetHeight;
|
||||
var scroller_height = target.clientHeight / target.scrollHeight || 0;
|
||||
var scroller_pos = this.scroll_target / target.scrollHeight || 0;
|
||||
var button_up_height = this.$('.up-button')[0].offsetHeight || 48;
|
||||
var button_down_height = this.$('.down-button')[0].offsetHeight || 48;
|
||||
|
||||
var bar_height = this.$element[0].offsetHeight;
|
||||
var bar_height = this.$element[0].offsetHeight || 96;
|
||||
var scrollbar_height = bar_height - button_up_height - button_down_height;
|
||||
|
||||
scroller_pos = scroller_pos * scrollbar_height + button_up_height;
|
||||
|
@ -105,15 +146,6 @@ function openerp_pos_scrollbar(instance, module){ //module is instance.point_of_
|
|||
bar_height: scrollbar_height };
|
||||
},
|
||||
|
||||
//scrolls up or down by pixels
|
||||
scroll: function(pixels){
|
||||
var target = this.target()[0];
|
||||
this.scroll_target = this.scroll_target - pixels;
|
||||
this.scroll_target = Math.max(0,Math.min(target.scrollHeight-target.clientHeight, this.scroll_target));
|
||||
this.target().scrollTop(this.scroll_target);
|
||||
this.update_scroller_dimensions();
|
||||
this.update_button_status();
|
||||
},
|
||||
|
||||
//checks if it should show or hide the scrollbar based on the target content and then show or hide it
|
||||
// if animated is true, then the scrollbar will be shown or hidden with an animation
|
||||
|
@ -139,11 +171,17 @@ function openerp_pos_scrollbar(instance, module){ //module is instance.point_of_
|
|||
//if animated is true, the scroller will move smoothly to its destination
|
||||
update_scroller_dimensions: function(animated){
|
||||
var dim = this.scroller_dimensions();
|
||||
var target = this.target()[0];
|
||||
if(animated){
|
||||
this.$('.scroller').animate({'top':dim.pos+'px', 'height': dim.height+'px'},this.scroll_delay);
|
||||
this.$('.scroller').animate({'top':dim.pos+'px', 'height': dim.height+'px'},this.scroll_duration);
|
||||
}else{
|
||||
this.$('.scroller').css({'top':dim.pos+'px', 'height': dim.height+'px'});
|
||||
}
|
||||
if(this.scroll_target + target.clientHeight >= target.scrollHeight){
|
||||
this.bottom = true;
|
||||
}else{
|
||||
this.bottom = false;
|
||||
}
|
||||
},
|
||||
|
||||
//disable or enable the up/down buttons according to the scrolled position
|
||||
|
@ -176,32 +214,54 @@ function openerp_pos_scrollbar(instance, module){ //module is instance.point_of_
|
|||
|
||||
//scroll one page up
|
||||
page_up: function(){
|
||||
var target = this.target()[0]
|
||||
if(this.scroll_target <= 0){
|
||||
return;
|
||||
}
|
||||
this.scroll_target = this.scroll_target - this.get_scroll_step();
|
||||
this.scroll_target = Math.max(0,this.scroll_target);
|
||||
this.target().animate({'scrollTop':this.scroll_target},this.scroll_delay);
|
||||
this.update_scroller_dimensions(true);
|
||||
this.update_button_status();
|
||||
return this.set_position(this.scroll_target - this.get_scroll_step(), true);
|
||||
},
|
||||
|
||||
//scroll one page down
|
||||
page_down: function(){
|
||||
var target = this.target()[0];
|
||||
var max_scroll = target.scrollHeight - target.clientHeight;
|
||||
|
||||
if(this.scroll_target >= max_scroll){
|
||||
this.scroll_target = max_scroll;
|
||||
this.target().scrollTop(max_scroll);
|
||||
return;
|
||||
}
|
||||
this.scroll_target = this.scroll_target + this.get_scroll_step();
|
||||
this.scroll_target = Math.min(this.scroll_target, max_scroll);
|
||||
this.target().animate({'scrollTop':this.scroll_target},this.scroll_delay);
|
||||
this.update_scroller_dimensions(true);
|
||||
this.update_button_status();
|
||||
return this.set_position(this.scroll_target + this.get_scroll_step(), true);
|
||||
},
|
||||
|
||||
//scrolls up or down by pixels
|
||||
scroll: function(pixels){
|
||||
return this.set_position(this.scroll_target - pixels, false);
|
||||
},
|
||||
|
||||
//scroll to a specific position (in pixels).
|
||||
//if animated is true, it will do this in an animated fashion with a duration equal to scroll_duration
|
||||
set_position: function(position,animated){
|
||||
var self = this;
|
||||
var target = this.target()[0];
|
||||
var bottom = target.scrollHeight-target.clientHeight;
|
||||
this.scroll_target = Math.max(0,Math.min(bottom,position));
|
||||
if(this.scroll_target === 0){
|
||||
this.position = 'top';
|
||||
}else if(this.scroll_target === 'bottom'){
|
||||
this.position = 'bottom';
|
||||
}else{
|
||||
this.position = 'center';
|
||||
}
|
||||
if(animated){
|
||||
this.target().animate({'scrollTop':this.scroll_target},this.scroll_duration);
|
||||
this.update_button_status();
|
||||
this.update_scroller_dimensions(true);
|
||||
}else{
|
||||
this.target().scrollTop(this.scroll_target);
|
||||
this.update_scroller_dimensions(false);
|
||||
this.update_button_status();
|
||||
}
|
||||
return this.scroll_target;
|
||||
},
|
||||
|
||||
//returns the current position of the scrollbar
|
||||
get_position: function(){
|
||||
return this.scroll_target;
|
||||
},
|
||||
|
||||
//returns true if it cannot be scrolled further down
|
||||
is_at_bottom: function(){
|
||||
return this.bottom;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -78,65 +78,41 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
|
|||
},
|
||||
});
|
||||
|
||||
// ---------- "Shopping Carts" ----------
|
||||
|
||||
module.OrderlineWidget = module.PosBaseWidget.extend({
|
||||
template: 'OrderlineWidget',
|
||||
init: function(parent, options) {
|
||||
this._super(parent,options);
|
||||
|
||||
this.model = options.model;
|
||||
this.order = options.order;
|
||||
|
||||
this.model.bind('change', _.bind( function() {
|
||||
this.refresh();
|
||||
}, this));
|
||||
this.model.bind('remove', _.bind( function() {
|
||||
this.$element.remove();
|
||||
}, this));
|
||||
this.order = options.order;
|
||||
|
||||
if(options.selected){
|
||||
this.select();
|
||||
}else{
|
||||
this.selected = false;
|
||||
}
|
||||
},
|
||||
clickHandler: function() {
|
||||
this.select();
|
||||
click_handler: function() {
|
||||
this.order.selectLine(this.model);
|
||||
this.on_selected();
|
||||
},
|
||||
renderElement: function() {
|
||||
this._super();
|
||||
this.$element.click(_.bind(this.clickHandler, this));
|
||||
if(this.selected){
|
||||
this.$element.click(_.bind(this.click_handler, this));
|
||||
if(this.model.get('selected')){
|
||||
this.$element.addClass('selected');
|
||||
}
|
||||
},
|
||||
refresh: function(){
|
||||
this.renderElement();
|
||||
},
|
||||
select: function() {
|
||||
console.log('SELECT:',this);
|
||||
if(this.order.selected_widget){
|
||||
this.order.selected_widget.deselect();
|
||||
}
|
||||
this.selected = true;
|
||||
this.order.selected_widget = this;
|
||||
this.order.selected = this.model;
|
||||
this.on_selected();
|
||||
this.$element.addClass('selected');
|
||||
},
|
||||
deselect: function(){
|
||||
this.selected = false;
|
||||
this.order.selected_widget = null;
|
||||
this.order.selected = null;
|
||||
this.$element.removeClass('selected');
|
||||
this.on_refresh();
|
||||
},
|
||||
on_selected: function() {},
|
||||
on_refresh: function(){},
|
||||
});
|
||||
|
||||
|
||||
module.OrderWidget = module.PosBaseWidget.extend({
|
||||
template:'OrderWidget',
|
||||
init: function(parent, options) {
|
||||
this._super(parent,options);
|
||||
console.log('OrderWidget init:',options)
|
||||
this.set_numpad_state(options.numpadState);
|
||||
this.pos.bind('change:selectedOrder', this.change_selected_order, this);
|
||||
this.bind_orderline_events();
|
||||
|
@ -152,11 +128,11 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
|
|||
}
|
||||
},
|
||||
set_value: function(val) {
|
||||
var param = {};
|
||||
param[this.numpadState.get('mode')] = val;
|
||||
var order = this.pos.get('selectedOrder');
|
||||
if (order.get('orderLines').length !== 0) {
|
||||
order.selected.set(param);
|
||||
var param = {};
|
||||
param[this.numpadState.get('mode')] = val;
|
||||
order.getSelectedLine().set(param);
|
||||
} else {
|
||||
this.pos.get('selectedOrder').destroy();
|
||||
}
|
||||
|
@ -168,42 +144,61 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
|
|||
},
|
||||
bind_orderline_events: function() {
|
||||
this.currentOrderLines = (this.pos.get('selectedOrder')).get('orderLines');
|
||||
this.currentOrderLines.bind('add', this.add_line, this);
|
||||
this.currentOrderLines.bind('add', this.renderElement, this);
|
||||
this.currentOrderLines.bind('remove', this.renderElement, this);
|
||||
},
|
||||
add_line: function(newLine) {
|
||||
var line = new module.OrderlineWidget(null, {
|
||||
model: newLine,
|
||||
pos: this.pos,
|
||||
order: this.pos.get('selectedOrder'),
|
||||
selected:true,
|
||||
});
|
||||
line.on_selected.add(_.bind(this.selected_line, this));
|
||||
this.selected_line();
|
||||
line.appendTo(this.$('.order'));
|
||||
},
|
||||
selected_line: function() {
|
||||
update_numpad: function() {
|
||||
var reset = false;
|
||||
if (this.currentSelected !== this.pos.get('selectedOrder').selected) {
|
||||
if (this.selected_line !== this.pos.get('selectedOrder').getSelectedLine()) {
|
||||
reset = true;
|
||||
}
|
||||
this.currentSelected = this.pos.get('selectedOrder').selected;
|
||||
this.selected_line = this.pos.get('selectedOrder').getSelectedLine();
|
||||
if (reset && this.numpadState)
|
||||
this.numpadState.reset();
|
||||
},
|
||||
renderElement: function() {
|
||||
var self = this;
|
||||
this._super();
|
||||
var $content = this.$('.order');
|
||||
$content.empty();
|
||||
var $content = this.$('.orderlines');
|
||||
this.currentOrderLines.each(_.bind( function(orderLine) {
|
||||
var line = new module.OrderlineWidget(null, {
|
||||
var line = new module.OrderlineWidget(this, {
|
||||
model: orderLine,
|
||||
order: this.pos.get('selectedOrder'),
|
||||
selected:true,
|
||||
});
|
||||
line.on_selected.add(_.bind(this.selected_line, this));
|
||||
line.on_selected.add(_.bind(this.update_numpad, this));
|
||||
line.on_refresh.add(_.bind(this.update_summary, this));
|
||||
line.appendTo($content);
|
||||
}, this));
|
||||
this.update_numpad();
|
||||
this.update_summary();
|
||||
|
||||
var position = this.scrollbar ? this.scrollbar.get_position() : 0;
|
||||
var at_bottom = this.scrollbar ? this.scrollbar.is_at_bottom() : false;
|
||||
|
||||
this.scrollbar = new module.ScrollbarWidget(this,{
|
||||
target_widget: this,
|
||||
target_selector: '.order-scroller',
|
||||
name: 'order',
|
||||
track_bottom: true,
|
||||
on_show: function(){
|
||||
self.$('.order-scroller').css({'width':'89%'},100);
|
||||
},
|
||||
on_hide: function(){
|
||||
self.$('.order-scroller').css({'width':'100%'},100);
|
||||
},
|
||||
});
|
||||
|
||||
this.scrollbar.replace(this.$('.placeholder-ScrollbarWidget'));
|
||||
this.scrollbar.set_position(position);
|
||||
|
||||
if( at_bottom ){
|
||||
this.scrollbar.set_position(Number.MAX_VALUE, false);
|
||||
}
|
||||
},
|
||||
update_summary: function(){
|
||||
var order = this.pos.get('selectedOrder');
|
||||
var total = order ? order.getTotal() : 0;
|
||||
this.$('.summary .value.total').html(this.format_currency(total));
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -218,7 +213,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
|
|||
this.model.attributes.weight = options.weight || undefined;
|
||||
this.next_screen = options.next_screen || undefined;
|
||||
},
|
||||
addToOrder: function(event) {
|
||||
add_to_order: function(event) {
|
||||
/* Preserve the category URL */
|
||||
event.preventDefault();
|
||||
return (this.pos.get('selectedOrder')).addProduct(this.model);
|
||||
|
@ -234,7 +229,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
|
|||
this._super();
|
||||
var self = this;
|
||||
$("a", this.$element).click(function(e){
|
||||
self.addToOrder(e);
|
||||
self.add_to_order(e);
|
||||
if(self.next_screen){
|
||||
self.pos_widget.screen_selector.set_current_screen(self.next_screen); //FIXME There ought to be a better way to do this ...
|
||||
}
|
||||
|
@ -334,10 +329,6 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
|
|||
this.button_list = [];
|
||||
this.fake_buttons = {};
|
||||
this.visibility = {};
|
||||
this.total_visibility = true;
|
||||
this.help_visibility = true;
|
||||
this.logout_visibility = true;
|
||||
this.close_visibility = true;
|
||||
},
|
||||
set_element_visible: function(element, visible, action){
|
||||
if(visible != this.visibility[element]){
|
||||
|
@ -352,9 +343,6 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
|
|||
this.$('.'+element).off('click').click(action);
|
||||
}
|
||||
},
|
||||
set_total_value: function(value){
|
||||
this.$('.value').html(value);
|
||||
},
|
||||
destroy_buttons:function(){
|
||||
for(var i = 0; i < this.button_list.length; i++){
|
||||
this.button_list[i].destroy();
|
||||
|
@ -397,6 +385,8 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
|
|||
}else{
|
||||
this.category = category;
|
||||
}
|
||||
console.log('setting categories:',this.category);
|
||||
|
||||
this.breadcrumb = [];
|
||||
for(var i = 1; i < this.category.ancestors.length; i++){
|
||||
this.breadcrumb.push(this.category.ancestors[i]);
|
||||
|
@ -419,7 +409,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
|
|||
renderElement: function(){
|
||||
var self = this;
|
||||
this._super();
|
||||
this.$element.find(".oe-pos-categories-list a").click(function(event){
|
||||
this.$(".oe-pos-categories-list a").click(function(event){
|
||||
var id = $(event.target).data("category-id");
|
||||
var category = self.pos.categories_by_id[id];
|
||||
self.set_category(category);
|
||||
|
@ -535,7 +525,8 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
|
|||
|
||||
this.scrollbar = new module.ScrollbarWidget(this,{
|
||||
target_widget: this,
|
||||
target_selector: '.product-list',
|
||||
target_selector: '.product-list-scroller',
|
||||
name: 'product-list',
|
||||
});
|
||||
|
||||
this.scrollbar.replace(this.$('.placeholder-ScrollbarWidget'));
|
||||
|
@ -745,7 +736,6 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
|
|||
window.screen_selector = this.screen_selector; //DEBUG
|
||||
|
||||
this.pos.barcode_reader.connect();
|
||||
|
||||
},
|
||||
|
||||
//FIXME this method is probably not at the right place ...
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
</div>
|
||||
<div id="loggedas">
|
||||
<span class="placeholder-SynchNotificationWidget"></span>
|
||||
<button>Close</button>
|
||||
</div>
|
||||
<div id="rightheader">
|
||||
<div id="order-selector">
|
||||
|
@ -120,8 +119,10 @@
|
|||
|
||||
<t t-name="ProductListWidget">
|
||||
<div class='product-list-container'>
|
||||
<ol id="products-screen-ol" class="product-list">
|
||||
</ol>
|
||||
<div class="product-list-scroller">
|
||||
<ol id="products-screen-ol" class="product-list">
|
||||
</ol>
|
||||
</div>
|
||||
<span class="placeholder-ScrollbarWidget" />
|
||||
</div>
|
||||
</t>
|
||||
|
@ -333,8 +334,24 @@
|
|||
|
||||
<t t-name="OrderWidget">
|
||||
<div class="order-container">
|
||||
<ul class="order">
|
||||
</ul>
|
||||
<div class="order-scroller">
|
||||
<div class="order">
|
||||
<ul class="orderlines">
|
||||
<t t-if="widget.pos.get('selectedOrder').get('orderLines').length === 0">
|
||||
<li class="orderline empty">
|
||||
Your shopping cart is empty
|
||||
</li>
|
||||
</t>
|
||||
|
||||
</ul>
|
||||
<div class="summary">
|
||||
<span t-attf-class="line #{widget.pos.get('selectedOrder').get('orderLines').length === 0 ? 'empty' : ''}">
|
||||
<span class="label total">Total:</span> <span class="value total">0.00 €</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="placeholder-ScrollbarWidget"></span>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
|
@ -352,11 +369,11 @@
|
|||
<em>
|
||||
<t t-esc="widget.model.get('quantity')" />
|
||||
</em>
|
||||
<t t-esc="widget.model.get('unit')" />
|
||||
<t t-esc="widget.model.get_unit().name" />
|
||||
at
|
||||
<t t-esc="widget.format_currency(widget.model.get('list_price'))" />
|
||||
/
|
||||
<t t-esc="widget.model.get('unit')" />
|
||||
<t t-esc="widget.model.get_unit().name" />
|
||||
</li>
|
||||
</t>
|
||||
<t t-if="widget.model.get('discount') > 0">
|
||||
|
@ -470,9 +487,6 @@
|
|||
<div class='iconlabel'>Client Mode</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="total">
|
||||
Total: <span class="value"> 0 </span>€
|
||||
</p>
|
||||
</div>
|
||||
<ul class="pos-actionbar-button-list">
|
||||
<!-- <li class="button">BUTTOOON</li>
|
||||
|
|
Loading…
Reference in New Issue