From 760939d83f4d51f56e8d4da21501116ac1bceef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20van=20der=20Essen?= Date: Fri, 10 Aug 2012 15:58:32 +0200 Subject: [PATCH] [IMP] point_of_sale: IndexedDB: the LocalStorage DB is working now bzr revid: fva@openerp.com-20120810135832-7xb3yq0r1p829nv1 --- addons/point_of_sale/static/src/js/pos_db.js | 124 ++++++++++++------- 1 file changed, 80 insertions(+), 44 deletions(-) diff --git a/addons/point_of_sale/static/src/js/pos_db.js b/addons/point_of_sale/static/src/js/pos_db.js index d660b130dd2..7b252bb8c41 100644 --- a/addons/point_of_sale/static/src/js/pos_db.js +++ b/addons/point_of_sale/static/src/js/pos_db.js @@ -1,15 +1,20 @@ /** + * WIP : AS OF THIS COMMIT, THE INDEXEDB BACKEND IS IN A NON WORKING STATE + * * This file contains an IndexedDB (html5 database) backend for the Point Of Sale. * The IDB is used to store the list of products and especially their thumbnails, which may * not fit in the localStorage. * The IDB offers a big performance boost for products lookup, but not so much for search as * searching is not yet implemented in the IndexedDB API and must be performed manually in JS. + * + * this file also contains a localstorage implementation of the database to be used by browsers + * that don't support the indexeddb api. * */ function openerp_pos_db(instance, module){ // this is used for testing - window.gen_products = function(options){ + var gen_products = function(options){ options = options || {}; var count = options.count || 100; var imageSize = options.imageSize || 1800; @@ -60,10 +65,13 @@ function openerp_pos_db(instance, module){ }; //this is used for testing - window.log = function(x){ + var log = function(x){ console.log(x); }; + // window.gen_products = gen_products; + // window.log = log; + function importIndexedDB(){ if('indexedDB' in window){ return true; @@ -330,9 +338,12 @@ function openerp_pos_db(instance, module){ }); window.PosDB = module.PosDB; + /* PosLS is a LocalStorage based implementation of the point of sale database, + it performs better for few products, but does not scale beyond 500 products. + */ module.PosLS = instance.web.Class.extend({ - name: 'openerp_pos_ls', - limit: 50, + name: 'openerp_pos_ls', //the prefix of the localstorage data + limit: 100, // the maximum number of results returned by a search init: function(options){ options = options || {}; this.name = options.name || this.name; @@ -340,6 +351,10 @@ function openerp_pos_db(instance, module){ this.products = this.name + '_products'; this.categories = this.name + '_categories'; + //products cache put the data in memory to avoid roundtrips to the localstorage + this.products_cache = null; + this.categories_cache = null; + this.category_by_id = {}; this.root_category_id = 0; this.category_products = {}; @@ -347,6 +362,7 @@ function openerp_pos_db(instance, module){ this.category_childs = {}; this.category_parent = {}; }, + /* returns the category object from its id */ get_category_by_id: function(categ_id){ if(categ_id instanceof Array){ var list = []; @@ -363,15 +379,24 @@ function openerp_pos_db(instance, module){ return this.category_by_id[categ_id]; } }, + /* returns a list of the category's child categories ids, or an empty list + * if a category has no childs */ get_category_childs_ids: function(categ_id){ return this.category_childs[categ_id] || []; }, + /* returns a list of all ancestors (parent, grand-parent, etc) categories ids + * starting from the root category to the direct parent */ get_category_ancestors_ids: function(categ_id){ return this.category_ancestors[categ_id] || []; }, + /* returns the parent category's id of a category, or the root_category_id if no parent. + * the root category is parent of itself. */ get_category_parent_id: function(categ_id){ return this.category_parent[categ_id] || this.root_category_id; }, + /* adds categories definitions to the database. categories is a list of categories objects as + * returned by the openerp server. Categories must be inserted before the products or the + * product/ categories association may (will) not work properly */ add_categories: function(categories){ var self = this; if(!this.category_by_id[this.root_category_id]){ @@ -381,13 +406,11 @@ function openerp_pos_db(instance, module){ }; } for(var i=0, len = categories.length; i < len; i++){ - console.log('putting category : ',categories[i].id, categories[i].name); this.category_by_id[categories[i].id] = categories[i]; } for(var i=0, len = categories.length; i < len; i++){ var cat = categories[i]; var parent_id = cat.parent_id[0] || this.root_category_id; - console.log('category parent',cat.id, parent_id); this.category_parent[cat.id] = cat.parent_id[0]; if(!this.category_childs[parent_id]){ this.category_childs[parent_id] = []; @@ -407,7 +430,11 @@ function openerp_pos_db(instance, module){ } make_ancestors(this.root_category_id, []); }, + /* this internal method returns from disc a dictionary associating ids to the products */ _get_products: function(){ + if(this.products_cache){ + return this.products_cache; + } var products = localStorage[this.products]; if(products){ return JSON.parse(products) || {}; @@ -415,10 +442,16 @@ function openerp_pos_db(instance, module){ return {}; } }, + /* this internal method saves a dictionary associating ids to product to the disc */ _set_products: function(products){ localStorage[this.products] = JSON.stringify(products); + this.products_cache = products; }, + /* this internal method returns from disc a dictionary associating ids to the categories */ _get_categories: function(){ + if(this.categories_cache){ + return this.categories_cache; + } var categories = localStorage[this.categories]; if(categories){ return JSON.parse(categories) || {}; @@ -426,8 +459,10 @@ function openerp_pos_db(instance, module){ return {}; } }, + /* this internal method saves to disc an array associating ids to the categories */ _set_categories: function(categories){ localStorage[this.categories] = JSON.stringify(categories); + this.categories_cache = categories; }, add_products: function(products){ var stored_products = this._get_products(); @@ -444,7 +479,6 @@ function openerp_pos_db(instance, module){ } stored_categories[categ_id].push(product.id); var ancestors = this.get_category_ancestors_ids(categ_id) || []; - console.log('ancestors:',ancestors); for(var j = 0; j < ancestors.length; j++){ if(! stored_categories[ancestors[j]]){ @@ -457,6 +491,7 @@ function openerp_pos_db(instance, module){ this._set_products(stored_products); this._set_categories(stored_categories); }, + /* removes all the data from the database. TODO : being able to selectively remove data */ clear: function(done_callback){ localStorage.removeItem(this.products); localStorage.removeItem(this.categories); @@ -464,18 +499,15 @@ function openerp_pos_db(instance, module){ done_callback(); } }, + /* this internal methods returns the count of properties in an object. */ _count_props : function(obj){ - if(obj.__count__){ - return obj.__count__; - }else{ - var count = 0; - for(var prop in obj){ - if(obj.hasOwnProperty(prop)){ - count++; - } + var count = 0; + for(var prop in obj){ + if(obj.hasOwnProperty(prop)){ + count++; } - return count; } + return count; }, get_product_count: function(result_callback){ result_callback(this._count_props(this._get_products())); @@ -509,50 +541,54 @@ function openerp_pos_db(instance, module){ var stored_products = this._get_products(); var product_ids = stored_categories[category_id]; var list = []; - for(var i = 0, len = product_ids.length; i < len; i++){ + for(var i = 0, len = Math.min(product_ids.length,this.limit); i < len; i++){ list.push(stored_products[product_ids[i]]); } result_callback(list); }, + /* returns as a parameter of the result_callback function 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) + */ search_product_in_category: function(category_id, fields, query, result_callback){ var self = this; - this.get_product_by_category(category_id, function(products){ - var list = []; + var stored_categories = this._get_categories(); + var stored_products = this._get_products(); + var product_ids = stored_categories[category_id]; + var list = []; + var count = 0; + + query = query.toString().toLowerCase(); - query = query.toString().toLowerCase(); - - if(!(fields instanceof Array)){ - fields = [fields]; - } - for(var i in products){ - for(var j = 0, jlen = fields.length; j < jlen; j++){ - var field = products[i][fields[j]]; - if(field === null || field === undefined){ - continue; - } - if(typeof field !== 'string'){ - if(field.toString){ - field = field.toString(); - }else{ - continue; - } - } - if(field.toLowerCase().indexOf(query) != -1){ - list.push(products[i]); - break; - } + 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; } } - result_callback(list); - }); + } + result_callback(list); }, + // TODO move the order storage from the crappy DAO in pos_models.js add_order: function(order,done_callback){ }, remove_order: function(order_id, done_callback){ }, get_orders: function(result_callback){ }, - }); window.PosLS = module.PosLS;