[IMP] point_of_sale: big reworking of the scale screens:
- no welcome scale in cashier mode, as it was an unnecessary delay for people who use it all day - no more parallel calls to the proxy which could reorder or make the driver crash - auto throttling of the proxy calls -> max 20 reads per seconds, but can go slower as well. - faster and cleaner update of the weight in the scale screen bzr revid: fva@openerp.com-20130911154155-rs600cixvftvkhoi
This commit is contained in:
parent
44967200e4
commit
b38c271031
|
@ -3,12 +3,17 @@ import logging
|
|||
import simplejson
|
||||
import os
|
||||
import openerp
|
||||
import time
|
||||
import random
|
||||
|
||||
from openerp.addons.web import http
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.addons.web.controllers.main import manifest_list, module_boot, html_template
|
||||
|
||||
class PointOfSaleController(http.Controller):
|
||||
def __init__(self):
|
||||
self.scale = 'closed'
|
||||
self.scale_weight = 0.0
|
||||
|
||||
@http.route('/pos/app', type='http', auth='admin')
|
||||
def app(self):
|
||||
|
@ -64,6 +69,10 @@ class PointOfSaleController(http.Controller):
|
|||
|
||||
return m
|
||||
|
||||
@http.route('/pos/test_connection', type='json', auth='admin')
|
||||
def test_connection(self):
|
||||
return
|
||||
|
||||
@http.route('/pos/scan_item_success', type='json', auth='admin')
|
||||
def scan_item_success(self, ean):
|
||||
"""
|
||||
|
@ -98,18 +107,38 @@ class PointOfSaleController(http.Controller):
|
|||
|
||||
@http.route('/pos/weighting_start', type='json', auth='admin')
|
||||
def weighting_start(self):
|
||||
print "weighting_start"
|
||||
if self.scale == 'closed':
|
||||
print "Opening (Fake) Connection to Scale..."
|
||||
self.scale = 'open'
|
||||
self.scale_weight = 0.0
|
||||
time.sleep(0.1)
|
||||
print "... Scale Open."
|
||||
else:
|
||||
print "WARNING: Scale already Connected !!!"
|
||||
return
|
||||
|
||||
@http.route('/pos/weighting_read_kg', type='json', auth='admin')
|
||||
def weighting_read_kg(self):
|
||||
print "weighting_read_kg"
|
||||
return 3.14
|
||||
if self.scale == 'open':
|
||||
print "Reading Scale..."
|
||||
time.sleep(0.025)
|
||||
self.scale_weight += 0.01
|
||||
print "... Done."
|
||||
return self.scale_weight
|
||||
else:
|
||||
print "WARNING: Reading closed scale !!!"
|
||||
return 0.0
|
||||
|
||||
@http.route('/pos/weighting_end', type='json', auth='admin')
|
||||
def weighting_end(self):
|
||||
print "weighting_end"
|
||||
return
|
||||
if self.scale == 'open':
|
||||
print "Closing Connection to Scale ..."
|
||||
self.scale = 'closed'
|
||||
self.scale_weight = 0.0
|
||||
time.sleep(0.1)
|
||||
print "... Scale Closed."
|
||||
else:
|
||||
print "WARNING: Scale already Closed !!!"
|
||||
|
||||
@http.route('/pos/payment_request', type='json', auth='admin')
|
||||
def payment_request(self, price):
|
||||
|
|
|
@ -1,6 +1,81 @@
|
|||
|
||||
function openerp_pos_devices(instance,module){ //module is instance.point_of_sale
|
||||
|
||||
// the JobQueue schedules a sequence of 'jobs'. each job is
|
||||
// a function returning a deferred. the queue waits for each job to finish
|
||||
// before launching the next. Each job can also be scheduled with a delay.
|
||||
// the is used to prevent parallel requests to the proxy.
|
||||
|
||||
module.JobQueue = function(){
|
||||
var queue = [];
|
||||
var running = false;
|
||||
var scheduled_end_time = 0;
|
||||
var end_of_queue = (new $.Deferred()).resolve();
|
||||
var stoprepeat = false;
|
||||
|
||||
var run = function(){
|
||||
if(end_of_queue.state() === 'resolved'){
|
||||
end_of_queue = new $.Deferred();
|
||||
}
|
||||
if(queue.length > 0){
|
||||
running = true;
|
||||
var job = queue[0];
|
||||
if(!job.opts.repeat || stoprepeat){
|
||||
queue.shift();
|
||||
stoprepeat = false;
|
||||
}
|
||||
|
||||
// the time scheduled for this job
|
||||
scheduled_end_time = (new Date()).getTime() + (job.opts.duration || 0);
|
||||
|
||||
// we run the job and put in def when it finishes
|
||||
var def = job.fun() || (new $.Deferred()).resolve();
|
||||
|
||||
// we don't care if a job fails ...
|
||||
def.always(function(){
|
||||
// we run the next job after the scheduled_end_time, even if it finishes before
|
||||
setTimeout(function(){
|
||||
run();
|
||||
}, Math.max(0, scheduled_end_time - (new Date()).getTime()) );
|
||||
});
|
||||
}else{
|
||||
running = false;
|
||||
end_of_queue.resolve();
|
||||
}
|
||||
};
|
||||
|
||||
// adds a job to the schedule.
|
||||
// opts : {
|
||||
// duration : the job is guaranteed to finish no quicker than this (milisec)
|
||||
// repeat : if true, the job will be endlessly repeated
|
||||
// important : if true, the scheduled job cannot be canceled by a queue.clear()
|
||||
// }
|
||||
this.schedule = function(fun, opts){
|
||||
queue.push({fun:fun, opts:opts || {}});
|
||||
if(!running){
|
||||
run();
|
||||
}
|
||||
}
|
||||
|
||||
// remove all jobs from the schedule (except the ones marked as important)
|
||||
this.clear = function(){
|
||||
queue = _.filter(queue,function(job){job.opts.important === true});
|
||||
};
|
||||
|
||||
// end the repetition of the current job
|
||||
this.stoprepeat = function(){
|
||||
stoprepeat = true;
|
||||
};
|
||||
|
||||
// returns a deferred that resolves when all scheduled
|
||||
// jobs have been run.
|
||||
// ( jobs added after the call to this method are considered as well )
|
||||
this.finished = function(){
|
||||
return end_of_queue;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// this object interfaces with the local proxy to communicate to the various hardware devices
|
||||
// connected to the Point of Sale. As the communication only goes from the POS to the proxy,
|
||||
// methods are used both to signal an event, and to fetch information.
|
||||
|
@ -10,7 +85,6 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
|
|||
options = options || {};
|
||||
url = options.url || 'http://localhost:8069';
|
||||
|
||||
this.weight = 0;
|
||||
this.weighting = false;
|
||||
this.debug_weight = 0;
|
||||
this.use_debug_weight = false;
|
||||
|
@ -35,18 +109,11 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
|
|||
this.connection.destroy();
|
||||
},
|
||||
message : function(name,params){
|
||||
var ret = new $.Deferred();
|
||||
var callbacks = this.notifications[name] || [];
|
||||
for(var i = 0; i < callbacks.length; i++){
|
||||
callbacks[i](params);
|
||||
}
|
||||
|
||||
this.connection.rpc('/pos/' + name, params || {}).done(function(result) {
|
||||
ret.resolve(result);
|
||||
}).fail(function(error) {
|
||||
ret.reject(error);
|
||||
});
|
||||
return ret;
|
||||
return this.connection.rpc('/pos/' + name, params || {});
|
||||
},
|
||||
|
||||
// this allows the client to be notified when a proxy call is made. The notification
|
||||
|
@ -82,14 +149,32 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
|
|||
|
||||
//the client is starting to weight
|
||||
weighting_start: function(){
|
||||
var ret = new $.Deferred();
|
||||
if(!this.weighting){
|
||||
this.weighting = true;
|
||||
this.weight = 0;
|
||||
return this.message('weighting_start');
|
||||
this.message('weighting_start').always(function(){
|
||||
ret.resolve();
|
||||
});
|
||||
}else{
|
||||
console.error('Weighting already started!!!');
|
||||
this.weight = 0;
|
||||
ret.resolve();
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
|
||||
// the client has finished weighting products
|
||||
weighting_end: function(){
|
||||
var ret = new $.Deferred();
|
||||
if(this.weighting){
|
||||
this.weighting = false;
|
||||
this.message('weighting_end').always(function(){
|
||||
ret.resolve();
|
||||
});
|
||||
}else{
|
||||
console.error('Weighting already ended !!!');
|
||||
ret.resolve();
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
|
||||
//returns the weight on the scale.
|
||||
|
@ -97,20 +182,14 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
|
|||
// and a weighting_end()
|
||||
weighting_read_kg: function(){
|
||||
var self = this;
|
||||
if(!this.weighting){
|
||||
console.error('Weighting while not started!!!');
|
||||
}
|
||||
var ret = new $.Deferred();
|
||||
this.message('weighting_read_kg',{})
|
||||
.done(function(weight){
|
||||
if(self.weighting){
|
||||
if(self.use_debug_weight){
|
||||
self.weight = self.debug_weight;
|
||||
}else{
|
||||
self.weight = weight;
|
||||
}
|
||||
}
|
||||
.then(function(weight){
|
||||
ret.resolve(self.use_debug_weight ? self.debug_weight : weight);
|
||||
}, function(){ //failed to read weight
|
||||
ret.resolve(self.use_debug_weight ? self.debug_weight : 0.0);
|
||||
});
|
||||
return this.weight;
|
||||
return ret;
|
||||
},
|
||||
|
||||
// sets a custom weight, ignoring the proxy returned value.
|
||||
|
@ -125,17 +204,6 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
|
|||
this.debug_weight = 0;
|
||||
},
|
||||
|
||||
// the client has finished weighting products
|
||||
weighting_end: function(){
|
||||
if(this.weighting){
|
||||
this.weight = 0;
|
||||
this.weighting = false;
|
||||
this.message('weighting_end');
|
||||
}else{
|
||||
console.error('Weighting already ended !!!');
|
||||
this.weight = 0;
|
||||
}
|
||||
},
|
||||
|
||||
// the pos asks the client to pay 'price' units
|
||||
payment_request: function(price){
|
||||
|
|
|
@ -24,6 +24,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
|
||||
this.barcode_reader = new module.BarcodeReader({'pos': this}); // used to read barcodes
|
||||
this.proxy = new module.ProxyDevice(); // used to communicate to the hardware devices via a local proxy
|
||||
this.proxy_queue = new module.JobQueue(); // used to prevent parallels communications to the proxy
|
||||
this.db = new module.PosLS(); // a database used to store the products and categories
|
||||
this.db.clear('products','categories');
|
||||
this.debug = jQuery.deparam(jQuery.param.querystring()).debug !== undefined; //debug mode
|
||||
|
|
|
@ -441,7 +441,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
module.ErrorInvoiceTransferPopupWidget = module.ErrorPopupWidget.extend({
|
||||
template: 'ErrorInvoiceTransferPopupWidget',
|
||||
});
|
||||
|
||||
|
||||
module.ScaleInviteScreenWidget = module.ScreenWidget.extend({
|
||||
template:'ScaleInviteScreenWidget',
|
||||
|
||||
|
@ -451,30 +451,35 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
show: function(){
|
||||
this._super();
|
||||
var self = this;
|
||||
var queue = this.pos.proxy_queue;
|
||||
|
||||
self.pos.proxy.weighting_start();
|
||||
|
||||
this.intervalID = setInterval(function(){
|
||||
var weight = self.pos.proxy.weighting_read_kg();
|
||||
if(weight > 0.001){
|
||||
clearInterval(this.intervalID);
|
||||
self.pos_widget.screen_selector.set_current_screen(self.next_screen);
|
||||
}
|
||||
},50);
|
||||
queue.schedule(function(){
|
||||
return self.pos.proxy.weighting_start();
|
||||
},{ unclearable: true });
|
||||
|
||||
queue.schedule(function(){
|
||||
return self.pos.proxy.weighting_read_kg().then(function(weight){
|
||||
if(weight > 0.001){
|
||||
self.pos_widget.screen_selector.set_current_screen(self.next_screen);
|
||||
}
|
||||
});
|
||||
},{duration: 100, repeat: true});
|
||||
|
||||
this.add_action_button({
|
||||
label: _t('Back'),
|
||||
icon: '/point_of_sale/static/src/img/icons/png48/go-previous.png',
|
||||
click: function(){
|
||||
clearInterval(this.intervalID);
|
||||
self.pos_widget.screen_selector.set_current_screen(self.previous_screen);
|
||||
}
|
||||
});
|
||||
},
|
||||
close: function(){
|
||||
this._super();
|
||||
clearInterval(this.intervalID);
|
||||
this.pos.proxy.weighting_end();
|
||||
var self = this;
|
||||
this.pos.proxy_queue.clear();
|
||||
this.pos.proxy_queue.schedule(function(){
|
||||
return self.pos.proxy.weighting_end();
|
||||
},{ unclearable: true });
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -486,9 +491,11 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
|
||||
show: function(){
|
||||
this._super();
|
||||
this.renderElement();
|
||||
var self = this;
|
||||
var queue = this.pos.proxy_queue;
|
||||
|
||||
this.set_weight(0);
|
||||
this.renderElement();
|
||||
|
||||
this.add_action_button({
|
||||
label: _t('Back'),
|
||||
|
@ -507,14 +514,16 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
},
|
||||
});
|
||||
|
||||
this.pos.proxy.weighting_start();
|
||||
this.intervalID = setInterval(function(){
|
||||
var weight = self.pos.proxy.weighting_read_kg();
|
||||
if(weight != self.weight){
|
||||
self.weight = weight;
|
||||
self.$('.js-weight').text(self.get_product_weight_string());
|
||||
}
|
||||
},50);
|
||||
queue.schedule(function(){
|
||||
return self.pos.proxy.weighting_start()
|
||||
},{ unclearable: true });
|
||||
|
||||
queue.schedule(function(){
|
||||
return self.pos.proxy.weighting_read_kg().then(function(weight){
|
||||
self.set_weight(weight);
|
||||
});
|
||||
},{duration:50, repeat: true});
|
||||
|
||||
},
|
||||
renderElement: function(){
|
||||
var self = this;
|
||||
|
@ -544,54 +553,24 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
var product = this.get_product();
|
||||
return (product ? product.get('price') : 0) || 0;
|
||||
},
|
||||
set_weight: function(weight){
|
||||
this.weight = weight;
|
||||
this.$('.js-weight').text(this.get_product_weight_string());
|
||||
},
|
||||
get_product_weight_string: function(){
|
||||
return (this.weight || 0).toFixed(3) + ' Kg';
|
||||
},
|
||||
close: function(){
|
||||
var self = this;
|
||||
this._super();
|
||||
clearInterval(this.intervalID);
|
||||
this.pos.proxy.weighting_end();
|
||||
|
||||
this.pos.proxy_queue.clear();
|
||||
this.pos.proxy_queue.schedule(function(){
|
||||
self.pos.proxy.weighting_end();
|
||||
},{ unclearable: true });
|
||||
},
|
||||
});
|
||||
|
||||
// the JobQueue schedules a sequence of 'jobs'. each job is
|
||||
// a function returning a deferred. the queue waits for each job to finish
|
||||
// before launching the next. Each job can also be scheduled with a delay.
|
||||
// the queue jobqueue is used to prevent parallel requests to the payment terminal.
|
||||
|
||||
module.JobQueue = function(){
|
||||
var queue = [];
|
||||
var running = false;
|
||||
var run = function(){
|
||||
if(queue.length > 0){
|
||||
running = true;
|
||||
var job = queue.shift();
|
||||
setTimeout(function(){
|
||||
var def = job.fun();
|
||||
if(def){
|
||||
def.done(run);
|
||||
}else{
|
||||
run();
|
||||
}
|
||||
},job.delay || 0);
|
||||
}else{
|
||||
running = false;
|
||||
}
|
||||
};
|
||||
|
||||
// adds a job to the schedule.
|
||||
this.schedule = function(fun, delay){
|
||||
queue.push({fun:fun, delay:delay});
|
||||
if(!running){
|
||||
run();
|
||||
}
|
||||
}
|
||||
|
||||
// remove all jobs from the schedule
|
||||
this.clear = function(){
|
||||
queue = [];
|
||||
};
|
||||
};
|
||||
|
||||
module.ClientPaymentScreenWidget = module.ScreenWidget.extend({
|
||||
template:'ClientPaymentScreenWidget',
|
||||
|
|
Loading…
Reference in New Issue