[IMP] point_of_sale: conver the wizard_scan_product into osv_memory wizard and set...
[odoo/odoo.git] / bin / osv / osv.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details.
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20 ##############################################################################
21
22 #
23 # OSV: Objects Services
24 #
25
26 import orm
27 import netsvc
28 import pooler
29 import copy
30 import sys
31 import traceback
32
33 from psycopg2 import IntegrityError
34 from tools.func import wraps
35
36
37 module_list = []
38 module_class_list = {}
39 class_pool = {}
40
41 class except_osv(Exception):
42     def __init__(self, name, value, exc_type='warning'):
43         self.name = name
44         self.exc_type = exc_type
45         self.value = value
46         self.args = (exc_type, name)
47
48
49 class osv_pool(netsvc.Service):
50
51     def check(f):
52         @wraps(f)
53         def wrapper(self, dbname, *args, **kwargs):
54             try:
55                 if not pooler.get_pool(dbname)._ready:
56                     raise except_osv('Database not ready', 'Currently, this database is not fully loaded and can not be used.')
57                 return f(self, dbname, *args, **kwargs)
58             except orm.except_orm, inst:
59                 if inst.name == 'AccessError':
60                     tb_s = "AccessError\n" + "".join(traceback.format_exception(*sys.exc_info()))
61                     self.logger.notifyChannel('web-services', netsvc.LOG_DEBUG, tb_s)
62                 self.abortResponse(1, inst.name, 'warning', inst.value)
63             except except_osv, inst:
64                 self.abortResponse(1, inst.name, inst.exc_type, inst.value)
65             except IntegrityError, inst:
66                 for key in self._sql_error.keys():
67                     if key in inst[0]:
68                         self.abortResponse(1, 'Constraint Error', 'warning', self._sql_error[key])
69                 self.abortResponse(1, 'Integrity Error', 'warning', inst[0])
70             except Exception, e:
71                 tb_s = "".join(traceback.format_exception(*sys.exc_info()))
72                 self.logger.notifyChannel('web-services', netsvc.LOG_ERROR, tb_s)
73                 raise
74
75         return wrapper
76
77
78     def __init__(self):
79         self._ready = False
80         self.obj_pool = {}
81         self.module_object_list = {}
82         self.created = []
83         self._sql_error = {}
84         self._store_function = {}
85         self._init = True
86         self._init_parent = {}
87         self.logger = netsvc.Logger()
88         netsvc.Service.__init__(self, 'object_proxy', audience='')
89         self.exportMethod(self.obj_list)
90         self.exportMethod(self.exec_workflow)
91         self.exportMethod(self.execute)
92
93     def init_set(self, cr, mode):
94         different = mode != self._init
95         if different:
96             if mode:
97                 self._init_parent = {}
98             if not mode:
99                 for o in self._init_parent:
100                     self.get(o)._parent_store_compute(cr)
101             self._init = mode
102
103         self._ready = True
104         return different
105
106     def execute_cr(self, cr, uid, obj, method, *args, **kw):
107         object = pooler.get_pool(cr.dbname).get(obj)
108         if not object:
109             raise except_osv('Object Error', 'Object %s doesn\'t exist' % str(obj))
110         return getattr(object, method)(cr, uid, *args, **kw)
111
112     @check
113     def execute(self, db, uid, obj, method, *args, **kw):
114         db, pool = pooler.get_db_and_pool(db)
115         cr = db.cursor()
116         try:
117             try:
118                 if method.startswith('_'):
119                     raise except_osv('Method Error', 'Private method %s can not be calleble.' % (method,))
120                 res = pool.execute_cr(cr, uid, obj, method, *args, **kw)
121                 if res is None:
122                     self.logger.notifyChannel("web-services", netsvc.LOG_WARNING,
123                     'Method can not return a None value (crash in XML-RPC)')
124                 cr.commit()
125             except Exception:
126                 cr.rollback()
127                 raise
128         finally:
129             cr.close()
130         return res
131
132     def exec_workflow_cr(self, cr, uid, obj, method, *args):
133         wf_service = netsvc.LocalService("workflow")
134         return wf_service.trg_validate(uid, obj, args[0], method, cr)
135
136     @check
137     def exec_workflow(self, db, uid, obj, method, *args):
138         cr = pooler.get_db(db).cursor()
139         try:
140             try:
141                 res = self.exec_workflow_cr(cr, uid, obj, method, *args)
142                 cr.commit()
143             except Exception:
144                 cr.rollback()
145                 raise
146         finally:
147             cr.close()
148         return res
149
150     def obj_list(self):
151         return self.obj_pool.keys()
152
153     # adds a new object instance to the object pool.
154     # if it already existed, the instance is replaced
155     def add(self, name, obj_inst):
156         if name in self.obj_pool:
157             del self.obj_pool[name]
158         self.obj_pool[name] = obj_inst
159
160         module = str(obj_inst.__class__)[6:]
161         module = module[:len(module)-1]
162         module = module.split('.')[0][2:]
163         self.module_object_list.setdefault(module, []).append(obj_inst)
164
165     # Return None if object does not exist
166     def get(self, name):
167         obj = self.obj_pool.get(name, None)
168         return obj
169
170     #TODO: pass a list of modules to load
171     def instanciate(self, module, cr):
172         res = []
173         class_list = module_class_list.get(module, [])
174         for klass in class_list:
175             res.append(klass.createInstance(self, module, cr))
176         return res
177
178 class osv_base(object):
179     def __init__(self, pool, cr):
180         pool.add(self._name, self)
181         self.pool = pool
182         super(osv_base, self).__init__(cr)
183
184     def __new__(cls):
185         module = str(cls)[6:]
186         module = module[:len(module)-1]
187         module = module.split('.')[0][2:]
188         if not hasattr(cls, '_module'):
189             cls._module = module
190         module_class_list.setdefault(cls._module, []).append(cls)
191         class_pool[cls._name] = cls
192         if module not in module_list:
193             module_list.append(cls._module)
194         return None
195
196 class osv_memory(osv_base, orm.orm_memory):
197     #
198     # Goal: try to apply inheritancy at the instanciation level and
199     #       put objects in the pool var
200     #
201     def createInstance(cls, pool, module, cr):
202         parent_names = getattr(cls, '_inherit', None)
203         if parent_names:
204             if isinstance(parent_names, (str, unicode)):
205                 name = cls._name or parent_names
206                 parent_names = [parent_names]
207             else:
208                 name = cls._name
209             if not name:
210                 raise TypeError('_name is mandatory in case of multiple inheritance')
211
212             for parent_name in ((type(parent_names)==list) and parent_names or [parent_names]):
213                 parent_class = pool.get(parent_name).__class__
214                 assert pool.get(parent_name), "parent class %s does not exist in module %s !" % (parent_name, module)
215                 nattr = {}
216                 for s in ('_columns', '_defaults'):
217                     new = copy.copy(getattr(pool.get(parent_name), s))
218                     if hasattr(new, 'update'):
219                         new.update(cls.__dict__.get(s, {}))
220                     else:
221                         new.extend(cls.__dict__.get(s, []))
222                     nattr[s] = new
223                 cls = type(name, (cls, parent_class), nattr)
224
225         obj = object.__new__(cls)
226         obj.__init__(pool, cr)
227         return obj
228     createInstance = classmethod(createInstance)
229
230 class osv(osv_base, orm.orm):
231     #
232     # Goal: try to apply inheritancy at the instanciation level and
233     #       put objects in the pool var
234     #
235     def createInstance(cls, pool, module, cr):
236         parent_names = getattr(cls, '_inherit', None)
237         if parent_names:
238             if isinstance(parent_names, (str, unicode)):
239                 name = cls._name or parent_names
240                 parent_names = [parent_names]
241             else:
242                 name = cls._name
243             if not name:
244                 raise TypeError('_name is mandatory in case of multiple inheritance')
245
246             for parent_name in ((type(parent_names)==list) and parent_names or [parent_names]):
247                 parent_class = pool.get(parent_name).__class__
248                 assert pool.get(parent_name), "parent class %s does not exist in module %s !" % (parent_name, module)
249                 nattr = {}
250                 for s in ('_columns', '_defaults', '_inherits', '_constraints', '_sql_constraints'):
251                     new = copy.copy(getattr(pool.get(parent_name), s))
252                     if hasattr(new, 'update'):
253                         new.update(cls.__dict__.get(s, {}))
254                     else:
255                         if s=='_constraints':
256                             for c in cls.__dict__.get(s, []):
257                                 exist = False
258                                 for c2 in range(len(new)):
259                                     if new[c2][2]==c[2]:
260                                         new[c2] = c
261                                         exist = True
262                                         break
263                                 if not exist:
264                                     new.append(c)
265                         else:
266                             new.extend(cls.__dict__.get(s, []))
267                     nattr[s] = new
268                 cls = type(name, (cls, parent_class), nattr)
269         obj = object.__new__(cls)
270         obj.__init__(pool, cr)
271         return obj
272     createInstance = classmethod(createInstance)
273
274 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
275