[IMP] point_of_sale: ImageCache and RegExp search

bzr revid: fva@openerp.com-20120816150213-mdctwsjxiyjh4lxi
This commit is contained in:
Frédéric van der Essen 2012-08-16 17:02:13 +02:00
parent 0e31e74b40
commit daba4e4fc2
4 changed files with 95 additions and 57 deletions

View File

@ -20,8 +20,11 @@ function openerp_pos_db(instance, module){
this.category_ancestors = {};
this.category_childs = {};
this.category_parent = {};
this.category_search_string = {};
},
/* returns the category object from its id */
/* returns the category object from its id. If you pass a list of id as parameters, you get
* a list of category objects.
*/
get_category_by_id: function(categ_id){
if(categ_id instanceof Array){
var list = [];
@ -108,6 +111,13 @@ function openerp_pos_db(instance, module){
localStorage[this.name + '_' + store] = JSON.stringify(data);
this.cache[store] = data;
},
_product_search_string: function(product){
var str = '' + product.id + ':' + product.name;
if(product.ean13){
str += '|' + product.ean13;
}
return str + '\n';
},
add_products: function(products){
var stored_products = this.load('products',{});
var stored_categories = this.load('categories',{});
@ -117,21 +127,35 @@ function openerp_pos_db(instance, module){
}
for(var i = 0, len = products.length; i < len; i++){
var product = products[i];
var search_string = this._product_search_string(product);
var categ_id = product.pos_categ_id[0];
if(!stored_categories[categ_id]){
stored_categories[categ_id] = [];
}
stored_categories[categ_id].push(product.id);
if(this.category_search_string[categ_id] === undefined){
this.category_search_string[categ_id] = '';
}
this.category_search_string[categ_id] += search_string;
var ancestors = this.get_category_ancestors_ids(categ_id) || [];
for(var j = 0; j < ancestors.length; j++){
if(! stored_categories[ancestors[j]]){
stored_categories[ancestors[j]] = [];
var ancestor = ancestors[j];
if(! stored_categories[ancestor]){
stored_categories[ancestor] = [];
}
stored_categories[ancestors[j]].push(product.id);
stored_categories[ancestor].push(product.id);
if( this.category_search_string[ancestor] === undefined){
this.category_search_string[ancestor] = '';
}
this.category_search_string[ancestor] += search_string;
}
stored_products[product.id] = product;
}
console.log(this.category_search_string);
this.save('products',stored_products);
this.save('categories',stored_categories);
},
@ -173,41 +197,23 @@ function openerp_pos_db(instance, module){
}
return list;
},
/* returns as a parameter of the result_callback function a list of products with :
/* returns a list of products with :
* - a category that is or is a child of category_id,
* - a field in fields that contains a value that contains the query
* If a search is started before the previous has returned, the previous search may be cancelled
* (and the corresponding result_callback never called)
* - a name, package or ean13 containing the query (case insensitive)
*/
search_product_in_category: function(category_id, fields, query){
var self = this;
var stored_categories = this.load('categories',{});
var stored_products = this.load('products',{});
var product_ids = stored_categories[category_id];
var list = [];
var count = 0;
query = query.toString().toLowerCase();
if(!(fields instanceof Array)){
fields = [fields];
}
for(var i = 0, len = product_ids.length; i < len && count < this.limit; i++){
var product = stored_products[product_ids[i]];
for(var j = 0, jlen = fields.length; j < jlen; j++){
var field = product[fields[j]];
if(field === null || field === undefined){
continue;
}
field = field.toString().toLowerCase();
if(field.indexOf(query) != -1){
list.push(product);
count++;
break;
}
search_product_in_category: function(category_id, query){
var re = RegExp("([0-9]+):.*?"+query,"gi");
var results = [];
for(var i = 0; i < this.limit; i++){
r = re.exec(this.category_search_string[category_id]);
if(r){
var id = Number(r[1]);
results.push(this.get_product_by_id(id));
}else{
break;
}
}
return list;
return results;
},
add_order: function(order){
var last_id = this.load('last_order_id',0);

View File

@ -298,7 +298,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
//try to push an order to the server
(new instance.web.Model('pos.order')).get_func('create_from_ui')([order])
.fail(function(unused, event){
//don't show error popup if it fails (I guess, copy pasted from niv without understanding it completely)
//don't show error popup if it fails
event.preventDefault();
console.error('Failed to send order:',order);
self._flush(index+1);

View File

@ -1,6 +1,51 @@
function openerp_pos_widgets(instance, module){ //module is instance.point_of_sale
var QWeb = instance.web.qweb;
// The ImageCache is used to hide the latency of the application cache on-disk access
// that causes annoying flickering on product pictures. Why the hell a simple access to
// the application cache involves such latency is beyond me, hopefully one day this can be
// removed.
module.ImageCache = instance.web.Class.extend({
init: function(options){
options = options || {};
this.max_size = options.max_size || 100;
this.cache = {};
this.access_time = {};
this.size = 0;
},
// returns a DOM Image object from an url, and cache the last 100 (by default) results
get_image: function(url){
var cached = this.cache[url];
if(cached){
this.access_time[url] = (new Date()).getTime();
return cached;
}else{
var img = new Image();
img.src = url;
while(this.size >= this.max_size){
var oldestUrl = null;
var oldestTime = (new Date()).getTime();
for(var url in this.cache){
var time = this.access_time[url];
if(time <= oldestTime){
oldestTime = time;
oldestUrl = url;
}
}
if(oldestUrl){
delete this.cache[oldestUrl];
delete this.access_time[oldestUrl];
}
this.size--;
}
this.cache[url] = img;
this.access_time[url] = (new Date()).getTime();
return img;
}
},
});
module.NumpadWidget = module.PosBaseWidget.extend({
template:'NumpadWidget',
init: function(parent, options) {
@ -229,25 +274,16 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
this._super(parent,options);
this.model = options.model;
this.model.attributes.weight = options.weight;
this.next_screen = options.next_screen;
this.click_product_action = options.click_product_action;
},
add_to_order: function(event) {
/* Preserve the category URL */
event.preventDefault();
return (this.pos.get('selectedOrder')).addProduct(this.model);
},
set_weight: function(weight){
this.model.attributes.weight = weight;
this.renderElement();
this.next_screen = options.next_screen; //when a product is clicked, this screen is set
this.click_product_action = options.click_product_action;
},
// returns the url of the product thumbnail
get_image_url: function() {
var url = '/web/binary/image?session_id='+instance.connection.session_id+'&model=product.product&field=image&id='+this.model.get('id');
console.log('Requesting url:'+ url);
return url;
return '/web/binary/image?session_id='+instance.connection.session_id+'&model=product.product&field=image&id='+this.model.get('id');
},
renderElement: function() {
this._super();
this.$('img').replaceWith(this.pos_widget.image_cache.get_image(this.get_image_url()));
var self = this;
$("a", this.$element).click(function(e){
if(self.click_product_action){
@ -480,7 +516,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
this.$('.searchbox input').keyup(function(){
query = $(this).val().toLowerCase();
if(query){
var products = self.pos.db.search_product_in_category(self.category.id, ['name','ean13'], query);
var products = self.pos.db.search_product_in_category(self.category.id, query);
self.pos.get('products').reset(products);
self.$('.search-clear').fadeIn();
}else{
@ -518,11 +554,6 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
self.renderElement();
});
},
set_weight: function(weight){
for(var i = 0; i < this.product_list.length; i++){
this.product_list[i].set_weight(weight);
}
},
renderElement: function() {
var self = this;
this._super();
@ -656,6 +687,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
this.leftpane_visible = true;
this.leftpane_width = '440px';
this.cashier_controls_visible = true;
this.image_cache = new module.ImageCache(); // for faster products image display
/*
//Epileptic mode

View File

@ -357,7 +357,7 @@
<li class='product'>
<a href="#">
<div class="product-img">
<img t-att-src="widget.get_image_url()" />
<img src='' /> <!-- the product thumbnail -->
<t t-if="!widget.model.get('to_weight')">
<span class="price-tag">
<t t-esc="widget.format_currency(widget.model.get('list_price'))"/>