[WIP] point_of_sale: moving DAO to db
[odoo/odoo.git] / addons / point_of_sale / static / src / js / pos_db.js
1 function openerp_pos_db(instance, module){ 
2
3     /* PosLS is a LocalStorage based implementation of the point of sale database,
4        it performs better for few products, but does not scale beyond 500 products. 
5        */
6     module.PosLS = instance.web.Class.extend({
7         name: 'openerp_pos_ls', //the prefix of the localstorage data
8         limit: 100,  // the maximum number of results returned by a search
9         init: function(options){
10             options = options || {};
11             this.name = options.name || this.name;
12             this.limit = options.limit || this.limit;
13
14             //cache the data in memory to avoid roundtrips to the localstorage
15             this.cache = {};
16
17             this.category_by_id = {};
18             this.root_category_id  = 0;
19             this.category_products = {};
20             this.category_ancestors = {};
21             this.category_childs = {};
22             this.category_parent    = {};
23         },
24         /* returns the category object from its id */
25         get_category_by_id: function(categ_id){
26             if(categ_id instanceof Array){
27                 var list = [];
28                 for(var i = 0, len = categ_id.length; i < len; i++){
29                     var cat = this.category_by_id[categ_id[i]];
30                     if(cat){
31                         list.push(cat);
32                     }else{
33                         console.error("get_category_by_id: no category has id:",categ_id[i]);
34                     }
35                 }
36                 return list;
37             }else{
38                 return this.category_by_id[categ_id];
39             }
40         },
41         /* returns a list of the category's child categories ids, or an empty list 
42          * if a category has no childs */
43         get_category_childs_ids: function(categ_id){
44             return this.category_childs[categ_id] || [];
45         },
46         /* returns a list of all ancestors (parent, grand-parent, etc) categories ids
47          * starting from the root category to the direct parent */
48         get_category_ancestors_ids: function(categ_id){
49             return this.category_ancestors[categ_id] || [];
50         },
51         /* returns the parent category's id of a category, or the root_category_id if no parent.
52          * the root category is parent of itself. */
53         get_category_parent_id: function(categ_id){
54             return this.category_parent[categ_id] || this.root_category_id;
55         },
56         /* adds categories definitions to the database. categories is a list of categories objects as
57          * returned by the openerp server. Categories must be inserted before the products or the 
58          * product/ categories association may (will) not work properly */
59         add_categories: function(categories){
60             var self = this;
61             if(!this.category_by_id[this.root_category_id]){
62                 this.category_by_id[this.root_category_id] = {
63                     id : this.root_category_id,
64                     name : 'Root',
65                 };
66             }
67             for(var i=0, len = categories.length; i < len; i++){
68                 this.category_by_id[categories[i].id] = categories[i];
69             }
70             for(var i=0, len = categories.length; i < len; i++){
71                 var cat = categories[i];
72                 var parent_id = cat.parent_id[0] || this.root_category_id;
73                 this.category_parent[cat.id] = cat.parent_id[0];
74                 if(!this.category_childs[parent_id]){
75                     this.category_childs[parent_id] = [];
76                 }
77                 this.category_childs[parent_id].push(cat.id);
78             }
79             function make_ancestors(cat_id, ancestors){
80                 self.category_ancestors[cat_id] = ancestors;
81
82                 ancestors = ancestors.slice(0);
83                 ancestors.push(cat_id);
84
85                 var childs = self.category_childs[cat_id] || [];
86                 for(var i=0, len = childs.length; i < len; i++){
87                     make_ancestors(childs[i], ancestors);
88                 }
89             }
90             make_ancestors(this.root_category_id, []);
91         },
92         /* loads a record store from the database. returns default if nothing is found */
93         load: function(store,deft){
94             if(this.cache[store] !== undefined){
95                 return this.cache[store];
96             }
97             var data = localStorage[this.name + '_' + store];
98             if(data !== undefined){
99                 data = JSON.parse(data);
100                 this.cache[store] = data;
101                 return data;
102             }else{
103                 return deft;
104             }
105         },
106         /* saves a record store to the database */
107         save: function(store,data){
108             localStorage[this.name + '_' + store] = JSON.stringify(data);
109             this.cache[store] = data;
110         },
111         add_products: function(products){
112             var stored_products = this.load('products',{}); 
113             var stored_categories = this.load('categories',{});
114
115             if(!products instanceof Array){
116                 products = [products];
117             }
118             for(var i = 0, len = products.length; i < len; i++){
119                 var product = products[i];
120                 var categ_id = product.pos_categ_id[0];
121                 if(!stored_categories[categ_id]){
122                     stored_categories[categ_id] = [];
123                 }
124                 stored_categories[categ_id].push(product.id);
125                 var ancestors = this.get_category_ancestors_ids(categ_id) || [];
126
127                 for(var j = 0; j < ancestors.length; j++){
128                     if(! stored_categories[ancestors[j]]){
129                         stored_categories[ancestors[j]] = [];
130                     }
131                     stored_categories[ancestors[j]].push(product.id);
132                 }
133                 stored_products[product.id] = product;
134             }
135             this.save('products',stored_products);
136             this.save('categories',stored_categories);
137         },
138         /* removes all the data from the database. TODO : being able to selectively remove data */
139         clear: function(){
140             localStorage.removeItem(this.name + '_products');
141             localStorage.removeItem(this.name + '_categories');
142         },
143         /* this internal methods returns the count of properties in an object. */
144         _count_props : function(obj){
145             var count = 0;
146             for(var prop in obj){
147                 if(obj.hasOwnProperty(prop)){
148                     count++;
149                 }
150             }
151             return count;
152         },
153         get_product_by_id: function(id){
154             return this.load('products',{})[id];
155         },
156         get_product_by_ean13: function(ean13){
157             var products = this.load('products',{});
158             for(var i in products){
159                 if( products[i] && products[i].ean13 === ean13){
160                     return products[i];
161                 }
162             }
163             return undefined;
164         },
165         get_product_by_category: function(category_id){
166             var stored_categories = this.load('categories',{});
167             var stored_products   = this.load('products',{});
168             var product_ids  = stored_categories[category_id];
169             var list = [];
170             for(var i = 0, len = Math.min(product_ids.length,this.limit); i < len; i++){
171                 list.push(stored_products[product_ids[i]]);
172             }
173             return list;
174         },
175         /* returns as a parameter of the result_callback function a list of products with :
176          * - a category that is or is a child of category_id,
177          * - a field in fields that contains a value that contains the query
178          * If a search is started before the previous has returned, the previous search may be cancelled
179          * (and the corresponding result_callback never called) 
180          */
181         search_product_in_category: function(category_id, fields, query){
182             var self = this;
183             var stored_categories = this.load('categories',{});
184             var stored_products   = this.load('products',{});
185             var product_ids       = stored_categories[category_id];
186             var list = [];
187             var count = 0;
188             
189             query = query.toString().toLowerCase();
190
191             if(!(fields instanceof Array)){
192                 fields = [fields];
193             }
194             for(var i = 0, len = product_ids.length; i < len && count < this.limit; i++){
195                 var product = stored_products[product_ids[i]];
196                 for(var j = 0, jlen = fields.length; j < jlen; j++){
197                     var field = product[fields[j]];
198                     if(field === null || field === undefined){
199                         continue;
200                     }
201                     field = field.toString().toLowerCase();
202                     if(field.indexOf(query) != -1){
203                         list.push(product);
204                         count++;
205                         break;
206                     }
207                 }
208             }
209             return list;
210         },
211         add_order: function(order){
212             var last_id = this.load('last_order_id',0);
213             var orders  = this.load('orders',[]);
214             orders.push({id: last_id + 1, data: order});
215             this.save('last_order_id',last_id+1);
216             this.save('orders',orders);
217         },
218         remove_order: function(order_id){
219             var orders = this.load('orders',[]);
220             orders = _.filter(orders, function(order){
221                 return order.id !== order_id;
222             });
223             this.save('orders',orders);
224         },
225         get_orders: function(){
226             return this.load('orders',[]);
227         },
228     });
229     /*
230     module.LocalStorageDAO = instance.web.Class.extend({
231         add_operation: function(operation) {
232             var self = this;
233             return $.async_when().pipe(function() {
234                 var tmp = self._get('oe_pos_operations', []);
235                 var last_id = self._get('oe_pos_operations_sequence', 1);
236                 tmp.push({'id': last_id, 'data': operation});
237                 self._set('oe_pos_operations', tmp);
238                 self._set('oe_pos_operations_sequence', last_id + 1);
239             });
240         },
241         remove_operation: function(id) {
242             var self = this;
243             return $.async_when().pipe(function() {
244                 var tmp = self._get('oe_pos_operations', []);
245                 tmp = _.filter(tmp, function(el) {
246                     return el.id !== id;
247                 });
248                 self._set('oe_pos_operations', tmp);
249             });
250         },
251         get_operations: function() {
252             var self = this;
253             return $.async_when().pipe(function() {
254                 return self._get('oe_pos_operations', []);
255             });
256         },
257         _get: function(key, default_) {
258             var txt = localStorage['oe_pos_dao_'+key];
259             if (! txt)
260                 return default_;
261             return JSON.parse(txt);
262         },
263         _set: function(key, value) {
264             localStorage['oe_pos_dao_'+key] = JSON.stringify(value);
265         },
266         reset_stored_data: function(){
267             for(key in localStorage){
268                 if(key.indexOf('oe_pos_dao_') === 0){
269                     delete localStorage[key];
270                 }
271             }
272             0497 53 82 88
273         },
274     });
275     */
276
277     window.PosLS = module.PosLS;
278 }