[IMP] point_of_sale: support for non ean13 barcodes using the Internal Reference field

bzr revid: fva@openerp.com-20130923145139-iu3ds9tcfzy1ffcf
This commit is contained in:
Frédéric van der Essen 2013-09-23 16:51:39 +02:00
parent 13f6d59043
commit e03f3aa288
7 changed files with 101 additions and 72 deletions

View File

@ -82,7 +82,7 @@ class PointOfSaleController(http.Controller):
"""
print 'scan_item_success: ' + str(ean)
@http.route('/pos/scan_item_error_unrecognized')
@http.route('/pos/scan_item_error_unrecognized', type='json', auth='admin')
def scan_item_error_unrecognized(self, ean):
"""
A product has been scanned without success

View File

@ -43,6 +43,7 @@ function openerp_pos_db(instance, module){
this.product_by_id = {};
this.product_by_ean13 = {};
this.product_by_category_id = {};
this.product_by_reference = {};
this.category_by_id = {};
this.root_category_id = 0;
@ -197,6 +198,9 @@ function openerp_pos_db(instance, module){
if(product.ean13){
this.product_by_ean13[product.ean13] = product;
}
if(product.default_code){
this.product_by_reference[product.default_code] = product;
}
}
},
add_packagings: function(packagings){
@ -241,6 +245,9 @@ function openerp_pos_db(instance, module){
}
return undefined;
},
get_product_by_reference: function(ref){
return this.product_by_reference[ref];
},
get_product_by_category: function(category_id){
var product_ids = this.product_by_category_id[category_id];
var list = [];

View File

@ -450,7 +450,7 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
// it will check its validity then return an object containing various
// information about the ean.
// most importantly :
// - ean : the ean
// - code : the ean
// - type : the type of the ean:
// 'price' | 'weight' | 'unit' | 'cashier' | 'client' | 'discount' | 'error'
//
@ -460,13 +460,16 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
// - unit : if the encoded value has a unit, it will be put there.
// not to be confused with the 'unit' type, which represent an unit of a
// unique product
// - base_code : the ean code with all the encoding parts set to zero; the one put on
// the product in the backend
parse_ean: function(ean){
var parse_result = {
type:'unknown', //
encoding: 'ean13',
type:'unknown',
prefix:'',
ean:ean,
base_ean: ean,
code:ean,
base_code: ean,
id:'',
value: 0,
unit: 'none',
@ -487,13 +490,13 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
parse_result.type = 'error';
} else if( match_prefix(this.price_prefix_set,'price')){
parse_result.id = ean.substring(0,7);
parse_result.base_ean = this.sanitize_ean(ean.substring(0,7));
parse_result.base_code = this.sanitize_ean(ean.substring(0,7));
parse_result.value = Number(ean.substring(7,12))/100.0;
parse_result.unit = 'euro';
} else if( match_prefix(this.weight_prefix_set,'weight')){
parse_result.id = ean.substring(0,7);
parse_result.value = Number(ean.substring(7,12))/1000.0;
parse_result.base_ean = this.sanitize_ean(ean.substring(0,7));
parse_result.base_code = this.sanitize_ean(ean.substring(0,7));
parse_result.unit = 'Kg';
} else if( match_prefix(this.client_prefix_set,'client')){
parse_result.id = ean.substring(0,7);
@ -502,7 +505,7 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
parse_result.id = ean.substring(0,7);
} else if( match_prefix(this.discount_prefix_set,'discount')){
parse_result.id = ean.substring(0,7);
parse_result.base_ean = this.sanitize_ean(ean.substring(0,7));
parse_result.base_code = this.sanitize_ean(ean.substring(0,7));
parse_result.value = Number(ean.substring(7,12))/100.0;
parse_result.unit = '%';
} else {
@ -512,9 +515,19 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
}
return parse_result;
},
on_ean: function(ean){
var parse_result = this.parse_ean(ean);
scan: function(type,code){
console.log('scan',type,code);
if (type === 'ean13'){
var parse_result = this.parse_ean(code);
}else if(type === 'reference'){
var parse_result = {
encoding: 'reference',
type: 'unit',
code: code,
prefix: '',
};
}
if (parse_result.type === 'error') { //most likely a checksum error, raise warning
console.warn('WARNING: barcode checksum error:',parse_result);
@ -522,7 +535,6 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
if(this.action_callback['product']){
this.action_callback['product'](parse_result);
}
//this.trigger("codebar",parse_result );
}else{
if(this.action_callback[parse_result.type]){
this.action_callback[parse_result.type](parse_result);
@ -530,41 +542,43 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
}
},
on_reference: function(code){
if(this.action_callback['reference']){
this.action_callback['reference'](code);
}
},
// starts catching keyboard events and tries to interpret codebar
// calling the callbacks when needed.
connect: function(){
var self = this;
var codeNumbers = [];
var timeStamp = 0;
var lastTimeStamp = 0;
var code = "";
var timeStamp = 0;
var onlynumbers = true;
// The barcode readers acts as a keyboard, we catch all keyup events and try to find a
// barcode sequence in the typed keys, then act accordingly.
this.handler = function(e){
//We only care about numbers
if (e.which >= 48 && e.which < 58){
if(timeStamp + 50 < new Date().getTime()){
code = "";
onlynumbers = true;
}
// The barcode reader sends keystrokes with a specific interval.
// We look if the typed keys fit in the interval.
if (codeNumbers.length === 0) {
timeStamp = new Date().getTime();
} else {
if (lastTimeStamp + 30 < new Date().getTime()) {
// not a barcode reader
codeNumbers = [];
timeStamp = new Date().getTime();
}
}
codeNumbers.push(e.which - 48);
lastTimeStamp = new Date().getTime();
if (codeNumbers.length === 13) {
//We have found what seems to be a valid codebar
self.on_ean(codeNumbers.join(''));
codeNumbers = [];
}
} else {
// NaN
codeNumbers = [];
timeStamp = new Date().getTime();
if( e.which < 48 || e.which >= 58 ){ // not a number
onlynumbers = false;
}
code += String.fromCharCode(e.which);
if(code.length >= 2 && self.pos.db.get_product_by_reference(code)){
self.scan('reference',code);
code = "";
onlynumbers = true;
}else if(code.length === 13 && onlynumbers){
self.scan('ean13',code);
code = "";
onlynumbers = true;
}
};
$('body').on('keypress', this.handler);

View File

@ -428,19 +428,23 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
return tried_all;
},
scan_product: function(parsed_ean){
scan_product: function(parsed_code){
var self = this;
var product = this.db.get_product_by_ean13(parsed_ean.base_ean);
var selectedOrder = this.get('selectedOrder');
if(parsed_code.encoding === 'ean13'){
var product = this.db.get_product_by_ean13(parsed_code.base_code);
}else if(parsed_code.encoding === 'reference'){
var product = this.db.get_product_by_reference(parsed_code.code);
}
if(!product){
return false;
}
if(parsed_ean.type === 'price'){
selectedOrder.addProduct(new module.Product(product), {price:parsed_ean.value});
}else if(parsed_ean.type === 'weight'){
selectedOrder.addProduct(new module.Product(product), {quantity:parsed_ean.value, merge:false});
if(parsed_code.type === 'price'){
selectedOrder.addProduct(new module.Product(product), {price:parsed_code.value});
}else if(parsed_code.type === 'weight'){
selectedOrder.addProduct(new module.Product(product), {quantity:parsed_code.value, merge:false});
}else{
selectedOrder.addProduct(new module.Product(product));
}

View File

@ -160,29 +160,29 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
// what happens when a product is scanned :
// it will add the product to the order and go to barcode_product_screen. Or show barcode_product_error_popup if
// there's an error.
barcode_product_action: function(ean){
barcode_product_action: function(code){
var self = this;
if(self.pos.scan_product(ean)){
self.pos.proxy.scan_item_success(ean);
if(self.pos.scan_product(code)){
self.pos.proxy.scan_item_success(code);
if(self.barcode_product_screen){
self.pos_widget.screen_selector.set_current_screen(self.barcode_product_screen);
}
}else{
self.pos.proxy.scan_item_error_unrecognized(ean);
self.pos.proxy.scan_item_error_unrecognized(code);
if(self.barcode_product_error_popup && self.pos_widget.screen_selector.get_user_mode() !== 'cashier'){
self.pos_widget.screen_selector.show_popup(self.barcode_product_error_popup);
}
}
},
// what happens when a cashier id barcode is scanned.
// the default behavior is the following :
// - if there's a user with a matching ean, put it as the active 'cashier', go to cashier mode, and return true
// - else : do nothing and return false. You probably want to extend this to show and appropriate error popup...
barcode_cashier_action: function(ean){
barcode_cashier_action: function(code){
var users = this.pos.get('user_list');
for(var i = 0, len = users.length; i < len; i++){
if(users[i].ean13 === ean.ean){
if(users[i].ean13 === code.code){
this.pos.set('cashier',users[i]);
this.pos_widget.username.refresh();
this.pos.proxy.cashier_mode_activated();
@ -190,7 +190,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
return true;
}
}
this.pos.proxy.scan_item_error_unrecognized(ean);
this.pos.proxy.scan_item_error_unrecognized(code);
return false;
},
@ -198,28 +198,28 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
// the default behavior is the following :
// - if there's a user with a matching ean, put it as the active 'client' and return true
// - else : return false.
barcode_client_action: function(ean){
barcode_client_action: function(code){
var partners = this.pos.get('partner_list');
for(var i = 0, len = partners.length; i < len; i++){
if(partners[i].ean13 === ean.ean){
if(partners[i].ean13 === code.code){
this.pos.get('selectedOrder').set_client(partners[i]);
this.pos_widget.username.refresh();
this.pos.proxy.scan_item_success(ean);
this.pos.proxy.scan_item_success(code);
return true;
}
}
this.pos.proxy.scan_item_error_unrecognized(ean);
this.pos.proxy.scan_item_error_unrecognized(code);
return false;
//TODO start the transaction
},
// what happens when a discount barcode is scanned : the default behavior
// is to set the discount on the last order.
barcode_discount_action: function(ean){
this.pos.proxy.scan_item_success(ean);
barcode_discount_action: function(code){
this.pos.proxy.scan_item_success(code);
var last_orderline = this.pos.get('selectedOrder').getLastOrderline();
if(last_orderline){
last_orderline.set_discount(ean.value)
last_orderline.set_discount(code.value)
}
},
@ -292,10 +292,10 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
this.pos_widget.username.set_user_mode(this.pos_widget.screen_selector.get_user_mode());
this.pos.barcode_reader.set_action_callback({
'cashier': self.barcode_cashier_action ? function(ean){ self.barcode_cashier_action(ean); } : undefined ,
'product': self.barcode_product_action ? function(ean){ self.barcode_product_action(ean); } : undefined ,
'client' : self.barcode_client_action ? function(ean){ self.barcode_client_action(ean); } : undefined ,
'discount': self.barcode_discount_action ? function(ean){ self.barcode_discount_action(ean); } : undefined,
'cashier': self.barcode_cashier_action ? function(code){ self.barcode_cashier_action(code); } : undefined ,
'product': self.barcode_product_action ? function(code){ self.barcode_product_action(code); } : undefined ,
'client' : self.barcode_client_action ? function(code){ self.barcode_client_action(code); } : undefined ,
'discount': self.barcode_discount_action ? function(code){ self.barcode_discount_action(code); } : undefined,
});
},
@ -405,7 +405,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
this.pos.barcode_reader.save_callbacks();
this.pos.barcode_reader.reset_action_callbacks();
this.pos.barcode_reader.set_action_callback({
'cashier': function(ean){
'cashier': function(code){
clearInterval(this.intervalID);
self.pos.proxy.cashier_mode_activated();
self.pos_widget.screen_selector.set_user_mode('cashier');
@ -683,14 +683,14 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
show_numpad: false,
show_leftpane: false,
barcode_product_action: function(ean){
barcode_product_action: function(code){
this.pos.proxy.transaction_start();
this._super(ean);
this._super(code);
},
barcode_client_action: function(ean){
barcode_client_action: function(code){
this.pos.proxy.transaction_start();
this._super(ean);
this._super(code);
$('.goodbye-message').addClass('oe_hidden');
this.pos_widget.screen_selector.show_popup('choose-receipt');
},

View File

@ -753,12 +753,15 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
this.$('.button.custom_ean').click(function(){
var ean = self.pos.barcode_reader.sanitize_ean(self.$('input.ean').val() || '0');
self.$('input.ean').val(ean);
self.pos.barcode_reader.on_ean(ean);
self.pos.barcode_reader.scan('ean13',ean);
});
this.$('.button.reference').click(function(){
self.pos.barcode_reader.scan('reference',self.$('input.ean').val());
});
_.each(this.eans, function(ean, name){
self.$('.button.'+name).click(function(){
self.$('input.ean').val(ean);
self.pos.barcode_reader.on_ean(ean);
self.pos.barcode_reader.scan('ean13',ean);
});
});
_.each(this.events, function(name){

View File

@ -494,6 +494,7 @@
<li class="button lemon_price">1.54€ Lemon</li>
<li class="button unknown_product">Unknown Product</li>
<li class="button invalid_ean">Invalid Ean</li>
<li class="button reference">Reference</li>
</ul>
<p class="category">Hardware Status</p>