[IMP] point_of_sale: order widget is now complete

bzr revid: fva@openerp.com-20120628123825-hrat3tlhtyz8yv1i
This commit is contained in:
Frédéric van der Essen 2012-06-28 14:38:25 +02:00
parent 1f0d6e4cb0
commit f69643a4a1
7 changed files with 422 additions and 233 deletions

File diff suppressed because one or more lines are too long

View File

@ -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);
}

View File

@ -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);
},
});
}

View File

@ -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);

View File

@ -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;
}
});
}

View File

@ -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 ...

View File

@ -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>