From 48062d4cf1a509afb0c364027ca5f99dc8c85bbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20van=20der=20Essen?= Date: Mon, 13 Aug 2012 18:00:26 +0200 Subject: [PATCH] [IMP] point_of_sale: removed IndexeDB and asynchronous backend bzr revid: fva@openerp.com-20120813160026-04w28p3pojzvdlkj --- addons/point_of_sale/static/src/js/pos_db.js | 349 ++---------------- .../point_of_sale/static/src/js/pos_models.js | 34 +- .../static/src/js/pos_screens.js | 24 +- .../static/src/js/pos_widgets.js | 32 +- 4 files changed, 66 insertions(+), 373 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 0be3d058da4..5c790b45d9e 100644 --- a/addons/point_of_sale/static/src/js/pos_db.js +++ b/addons/point_of_sale/static/src/js/pos_db.js @@ -1,284 +1,5 @@ -/** - * 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){ - function importIndexedDB(){ - if('indexedDB' in window){ - return true; - }else if('webkitIndexedDB' in window){ - window.indexedDB = window.webkitIndexedDB; - window.IDBCursor = window.webkitIDBCursor; - window.IDBDatabase = window.webkitIDBDatabase; - window.IDBDatabaseError = window.webkitIDBDatabaseError; - window.IDBDatabaseException = window.webkitIDBDatabaseException; - window.IDBFactory = window.webkitIDBFactory; - window.IDBIndex = window.webkitIDBIndex; - window.IDBKeyRange = window.webkitIDBKeyRange; - window.IDBObjectSrore = window.webkitIDBOjbectStore; - window.IDBRequest = window.webkitIDBRequest; - window.IDBTransaction = window.webkitIDBTransaction; - }else if('mozIndexedDB' in window){ - window.indexedDB = window.mozIndexedDB; - }else{ - throw new Error("DATABASE ERROR: IndexedDB not implemented. Please upgrade your web browser"); - } - } - importIndexedDB(); - - module.PosDB = instance.web.Class.extend({ - - version: 1, - name: 'openerp_pos_db', - limit: 50, - - init: function(options){ - var self = this; - options = options || {}; - - this.version = options.version || this.version; - this.name = options.name || this.name; - - var open_request = indexedDB.open(this.name, this.version); - - open_request.onblocked = function(event){ - throw new Error("DATABASE ERROR: request blocked."); - }; - - // new API (firefox) - open_request.onupgradeneeded = function(event){ - console.log('using new API'); - var transaction = open_request.transaction; - self._upgrade_db(event.oldVersion,transaction); - }; - - open_request.onsuccess = function(event){ - console.log('db',self.db); - self.db = open_request.result; - var oldVersion = Number(self.db.version); - - if(oldVersion !== self.version){ - // if we get to this point, it means that onupgradeneeded hasn't been called. - // so we try the old api (webkit) - if(!self.db.setVersion){ - throw new Error("DATABASE ERROR: database API is broken. Your web browser is probably out of date"); - } - console.log('using old API'); - var version_request = self.db.setVersion(self.version); - version_request.onsuccess = function(event){ - var transaction = version_request.result; - self._upgrade_db(oldVersion, transaction); - }; - } - }; - }, - _upgrade_db: function(oldversion, transaction){ - console.log('upgrade_db:',oldversion); - - this.db = transaction.db; - var productStore = this.db.createObjectStore('products', {keyPath: 'id'}); - - productStore.createIndex('ean13', 'ean13', {unique:true}); - - productStore.createIndex('name', 'name', {unique:false}); - - productStore.createIndex('category','category', {unique:false}); - - var imageStore = this.db.createObjectStore('images', {keyPath: 'id'}); - - var categoryStore = this.db.createObjectStore('categories', {keypath:'name'}); - }, - - _add_data: function(store, data){ - var transaction = this.db.transaction([store], 'readwrite'); - var objectStore = transaction.objectStore(store); - var request = objectStore.put(data); - }, - /* adds a product to the database, replacing the original product if it is already present. - * the product must be provided as a json as returned by the openerp backend - */ - add_product: function(product){ - if(product instanceof Array){ - for(var i = 0, len = product.length; i < len; i++){ - this.add_product(product[i]); - } - }else{ - if(product.product_image_small){ - var image = product.product_image_small; - var product = _.clone(product); - delete product['product_image_small']; - this._add_data('images', { id: product.id, image:image}); - } - this._add_data('products',product); - } - }, - - /* removes all the data in the database ! */ - clear: function(done_callback){ - var transaction = this.db.transaction(['products','images'],'readwrite'); - transaction.objectStore('products').clear(); - transaction.objectStore('images').clear(); - if(done_callback){ - transaction.oncomplete = function(){ done_callback(); }; - } - }, - - get_product_count: function(result_callback){ - this.db.transaction('products').objectStore('products').count().onsuccess = function(event){ - result_callback(event.target.result); - }; - }, - - get_image_count: function(result_callback){ - this.db.transaction('images').objectStore('images').count().onsuccess = function(event){ - result_callback(event.target.result); - }; - }, - - /* fetches a product with an id of 'id', returns the product as the first parameter - * of the result_callback function - */ - get_product_by_id: function(id, result_callback){ - var transaction = this.db.transaction('products'); - var objectStore = transaction.objectStore('products'); - var request = objectStore.get(id); - request.onsuccess = function(event){ - if(result_callback){ - result_callback(event.target.result); - } - }; - }, - get_product_by_name: function(name, result_callback){ - var transaction = this.db.transaction('products'); - var objectStore = transaction.objectStore('products'); - var index = objectStore.index('name'); - index.get(name).onsuccess = function(event){ - result_callback(event.target.result); - }; - }, - /* fetches the product with the ean13 matching the one provided. returns the product - * as the first parameter of the result_callback function - */ - get_product_by_ean13: function(ean13, result_callback){ - var transaction = this.db.transaction('products'); - var objectStore = transaction.objectStore('products'); - var index = objectStore.index('ean13'); - index.get(ean13).onsuccess = function(event){ - result_callback(event.target.result); - }; - }, - /* fetches all products belonging to a category, and returns the list of products - * as the first paramter of the result_callback function - */ - get_product_by_category: function(category, result_callback){ - var transaction = this.db.transaction('products'); - var objectStore = transaction.objectStore('products'); - var index = objectStore.index('category'); - var list = []; - index.openCursor(IDBKeyRange.only(category)).onsuccess = function(event){ - var cursor = event.target.result; - if(cursor){ - list.push(cursor.value); - cursor.continue(); - }else{ - result_callback(list); - } - }; - }, - /* Fetches a picture associated with a product. - * product: This is a product json object as returned by the openerp backend. - * result_callback: a callback that gets the image data as parameter. - */ - get_product_image: function(product, result_callback){ - var transaction = this.db.transaction('images'); - var objectStore = transaction.objectStore('images'); - var request = objectStore.get(product.id); - request.onsuccess = function(event){ - result_callback(event.target.result.image); - } - }, - /* fields: a string or a list of string representing the list of the fields that - * will be searched. the values of those field must be a string. - * query: a string that will be matched in the content of one of the searched fields. - * result_callback: a function that will be called with a list of all the products with - * a field that match the query. - */ - search_product: function(fields,query,result_callback){ - var transaction = this.db.transaction('products'); - var objectStore = transaction.objectStore('products'); - var list = []; - if(!(fields instanceof Array)){ - fields = [ fields ]; - } - query = query.toLowerCase(); - objectStore.openCursor().onsuccess = function(event){ - var cursor = event.target.result; - if(cursor){ - var obj = cursor.value; - for(var i = 0, len = fields.length; i < len; i++){ - if(obj[fields[i]].toLowerCase().indexOf(query) != -1){ - list.push(obj); - break; - } - } - cursor.continue(); - }else{ - result_callback(list); - } - } - }, - /* the callback function will be called with all products as parameter, by increasing id. - * if the callback returns 'break' the iteration will stop - */ - for_all_products: function(callback){ - var transaction = this.db.transaction('products'); - var objectStore = transaction.objectStore('products'); - objectStore.openCursor().onsuccess = function(event){ - var cursor = event.target.result; - if(cursor){ - var ret = callback(cursor.value); - if(ret !== 'break'){ - cursor.continue(); - } - } - }; - }, - /* the callback function will be called with all products as parameter by increasing id. - * if the callback returns 'break', the iteration will stop - * if the callback returns a product object, it will be inserted in the db, possibly - * overwriting an existing product. The intended usage is for the callback to return a - * modified version version of the product with the same id. Anything else and you're on your own. - */ - modify_all_products: function(callback){ - var transaction = this.db.transaction('products','readwrite'); - var objectStore = transaction.objectStore('products'); - objectStore.openCursor().onsuccess = function(event){ - var cursor = event.target.result; - if(cursor){ - var ret = callback(cursor.value); - if(ret === undefined || ret === null){ - cursor.continue(); - }else if(ret === 'break'){ - return; - }else{ - objectStore.put(ret); - } - } - }; - }, - }); - 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. */ @@ -372,7 +93,7 @@ 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(){ + _load_products: function(){ if(this.products_cache){ return this.products_cache; } @@ -384,12 +105,12 @@ function openerp_pos_db(instance, module){ } }, /* this internal method saves a dictionary associating ids to product to the disc */ - _set_products: function(products){ + _save_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(){ + _load_categories: function(){ if(this.categories_cache){ return this.categories_cache; } @@ -401,13 +122,13 @@ function openerp_pos_db(instance, module){ } }, /* this internal method saves to disc an array associating ids to the categories */ - _set_categories: function(categories){ + _save_categories: function(categories){ localStorage[this.categories] = JSON.stringify(categories); this.categories_cache = categories; }, add_products: function(products){ - var stored_products = this._get_products(); - var stored_categories = this._get_categories(); + var stored_products = this._load_products(); + var stored_categories = this._load_categories(); if(!products instanceof Array){ products = [products]; @@ -429,16 +150,13 @@ function openerp_pos_db(instance, module){ } stored_products[product.id] = product; } - this._set_products(stored_products); - this._set_categories(stored_categories); + this._save_products(stored_products); + this._save_categories(stored_categories); }, /* removes all the data from the database. TODO : being able to selectively remove data */ - clear: function(done_callback){ + clear: function(){ localStorage.removeItem(this.products); localStorage.removeItem(this.categories); - if(done_callback){ - done_callback(); - } }, /* this internal methods returns the count of properties in an object. */ _count_props : function(obj){ @@ -450,42 +168,27 @@ function openerp_pos_db(instance, module){ } return count; }, - get_product_count: function(result_callback){ - result_callback(this._count_props(this._get_products())); + get_product_by_id: function(id){ + return this._load_products()[id]; }, - get_product_by_id: function(id, result_callback){ - var products = this._get_products(); - result_callback( products[id] ); - }, - get_product_by_name: function(name, result_callback){ - var products = this._get_products(); - for(var i in products){ - if(products[i] && products[i].name === name){ - result_callback(products[i]); - return; - } - } - result_callback(undefined); - }, - get_product_by_ean13: function(ean13, result_callback){ - var products = this._get_products(); + get_product_by_ean13: function(ean13){ + var products = this._load_products(); for(var i in products){ if( products[i] && products[i].ean13 === ean13){ - result_callback(products[i]); - return; + return products[i]; } } - result_callback(undefined); + return undefined; }, - get_product_by_category: function(category_id, result_callback){ - var stored_categories = this._get_categories(); - var stored_products = this._get_products(); + get_product_by_category: function(category_id){ + var stored_categories = this._load_categories(); + var stored_products = this._load_products(); var product_ids = stored_categories[category_id]; var list = []; 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); + return 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, @@ -493,10 +196,10 @@ function openerp_pos_db(instance, module){ * 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){ + search_product_in_category: function(category_id, fields, query){ var self = this; - var stored_categories = this._get_categories(); - var stored_products = this._get_products(); + var stored_categories = this._load_categories(); + var stored_products = this._load_products(); var product_ids = stored_categories[category_id]; var list = []; var count = 0; @@ -521,14 +224,14 @@ function openerp_pos_db(instance, module){ } } } - result_callback(list); + return list; }, // TODO move the order storage from the crappy DAO in pos_models.js - add_order: function(order,done_callback){ + add_order: function(order){ }, - remove_order: function(order_id, done_callback){ + remove_order: function(order_id){ }, - get_orders: function(result_callback){ + get_orders: function(){ }, }); diff --git a/addons/point_of_sale/static/src/js/pos_models.js b/addons/point_of_sale/static/src/js/pos_models.js index 1fb8a0174fa..0f4d1b8aa64 100644 --- a/addons/point_of_sale/static/src/js/pos_models.js +++ b/addons/point_of_sale/static/src/js/pos_models.js @@ -216,7 +216,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal self.db.add_categories(categories); return fetch( 'product.product', - ['name', 'list_price','price','pos_categ_id', 'taxes_id','image', 'ean13', 'to_weight', 'uom_id', 'uos_id', 'uos_coeff', 'mes_type'], + ['name', 'list_price','price','pos_categ_id', 'taxes_id', 'ean13', 'to_weight', 'uom_id', 'uos_id', 'uos_coeff', 'mes_type'], [['pos_categ_id','!=', false]], {pricelist: self.get('shop').pricelist_id[0]} // context for price ); @@ -367,23 +367,21 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal scan_product: function(parsed_ean){ var self = this; - var def = new $.Deferred(); - this.db.get_product_by_ean13(parsed_ean.base_ean, function(product){ - var selectedOrder = this.get('selectedOrder'); - if(!product){ - def.reject('product-not-found: '+parsed_ean.base_ean); - return; - } - 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}); - }else{ - selectedOrder.addProduct(new module.Product(product)); - } - def.resolve(); - }); - return def; + var product = this.db.get_product_by_ean13(parsed_ean.base_ean); + var selectedOrder = this.get('selectedOrder'); + + 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}); + }else{ + selectedOrder.addProduct(new module.Product(product)); + } + return true; }, }); diff --git a/addons/point_of_sale/static/src/js/pos_screens.js b/addons/point_of_sale/static/src/js/pos_screens.js index 92665c5c381..659ee09c232 100644 --- a/addons/point_of_sale/static/src/js/pos_screens.js +++ b/addons/point_of_sale/static/src/js/pos_screens.js @@ -160,19 +160,17 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa // there's an error. barcode_product_action: function(ean){ var self = this; - this.pos_widget.scan_product(ean) - .done(function(){ - self.pos.proxy.scan_item_success(ean); - if(self.barcode_product_screen){ - self.pos_widget.screen_selector.set_current_screen(self.barcode_product_screen); - } - }) - .fail(function(){ - self.pos.proxy.scan_item_error_unrecognized(ean); - 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); - } - }); + if(pos_widget.scan_product(ean)){ + self.pos.proxy.scan_item_success(ean); + 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); + 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. diff --git a/addons/point_of_sale/static/src/js/pos_widgets.js b/addons/point_of_sale/static/src/js/pos_widgets.js index 106a7ca7c4b..329bb05aca8 100644 --- a/addons/point_of_sale/static/src/js/pos_widgets.js +++ b/addons/point_of_sale/static/src/js/pos_widgets.js @@ -242,7 +242,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa this.renderElement(); }, get_image_url: function() { - return 'data:image/gif;base64,'+this.model.get('image'); + return 'web/binary/image?session_id='+instance.connection.session_id+'&model=product.product&field=image&id='+this.model.get('id')+'&cache=1800'; }, renderElement: function() { this._super(); @@ -471,25 +471,20 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa var self = this; // find all products belonging to the current category - this.pos.db.get_product_by_category(this.category.id, function(products){ - // product lists watch for reset events on 'products' to re-render. - // FIXME that means all productlist widget re-render... even the hidden ones ! - self.pos.get('products').reset(products); - }); + var products = this.pos.db.get_product_by_category(this.category.id); + self.pos.get('products').reset(products); // filter the products according to the search string this.$('.searchbox input').keyup(function(){ query = $(this).val().toLowerCase(); if(query){ - self.pos.db.search_product_in_category(self.category.id, ['name','ean13'], query, function(products){ - self.pos.get('products').reset(products); - self.$('.search-clear').fadeIn(); - }); + var products = self.pos.db.search_product_in_category(self.category.id, ['name','ean13'], query); + self.pos.get('products').reset(products); + self.$('.search-clear').fadeIn(); }else{ - self.pos.db.get_product_by_category(self.category.id, function(products){ - self.pos.get('products').reset(products); - self.$('.search-clear').fadeOut(); - }); + var products = self.pos.db.get_product_by_category(self.category.id); + self.pos.get('products').reset(products); + self.$('.search-clear').fadeOut(); } }); @@ -497,11 +492,10 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa //reset the search when clicking on reset this.$('.search-clear').click(function(){ - self.pos.db.get_product_by_category(self.category.id, function(products){ - self.pos.get('products').reset(products); - self.$('.searchbox input').val('').focus(); - self.$('.search-clear').fadeOut(); - }); + var products = self.pos.db.get_product_by_category(self.category.id); + self.pos.get('products').reset(products); + self.$('.searchbox input').val('').focus(); + self.$('.search-clear').fadeOut(); }); }, });