diff --git a/bin/addons/base/i18n/fr_FR.po b/bin/addons/base/i18n/fr_FR.po index fcfe08ad585..b214f1f2b25 100644 --- a/bin/addons/base/i18n/fr_FR.po +++ b/bin/addons/base/i18n/fr_FR.po @@ -680,7 +680,7 @@ msgstr "Facteur" #. module: base #: view:res.lang:0 msgid "%B - Full month name." -msgstr "%B - Nomd u mois complet." +msgstr "%B - Nom du mois complet." #. module: base #: field:ir.actions.report.xml,report_type:0 diff --git a/bin/addons/base/ir/ir_attachment.py b/bin/addons/base/ir/ir_attachment.py index b1a1eef9e4c..c2c99e52ccf 100644 --- a/bin/addons/base/ir/ir_attachment.py +++ b/bin/addons/base/ir/ir_attachment.py @@ -94,9 +94,10 @@ class ir_attachment(osv.osv): context['bin_size'] = False for i in self.browse(cr, uid, ids, context=context): result[i.id] = False - for format in ('png','PNG','jpg','JPG'): - if (i.datas_fname or '').endswith(format): + for format in ('png','jpg','jpeg','gif','bmp'): + if (i.datas_fname and i.datas_fname.lower() or '').endswith(format): result[i.id]= i.datas + break return result _name = 'ir.attachment' diff --git a/bin/addons/base/ir/ir_model.py b/bin/addons/base/ir/ir_model.py index 6ee219378fa..aa89e0f71dd 100644 --- a/bin/addons/base/ir/ir_model.py +++ b/bin/addons/base/ir/ir_model.py @@ -517,7 +517,6 @@ class ir_model_data(osv.osv): return res_id def _unlink(self, cr, uid, model, ids, direct=False): - #self.pool.get(model).unlink(cr, uid, ids) for id in ids: self.unlink_mark[(model, id)]=False cr.execute('delete from ir_model_data where res_id=%s and model=%s', (id, model)) @@ -582,8 +581,9 @@ class ir_model_data(osv.osv): self.unlink(cr, uid, [id]) cr.execute('DELETE FROM ir_values WHERE value=%s', ('%s,%s' % (model, res_id),)) cr.commit() - except: + except Exception, e: cr.rollback() + logger.notifyChannel('init', netsvc.LOG_ERROR, e) logger.notifyChannel('init', netsvc.LOG_ERROR, 'Could not delete id: %d of model %s\nThere should be some relation that points to this resource\nYou should manually fix this and restart --update=module' % (res_id, model)) return True ir_model_data() diff --git a/bin/addons/base/ir/ir_rule.py b/bin/addons/base/ir/ir_rule.py index fdfa82ec002..597ccf705e0 100644 --- a/bin/addons/base/ir/ir_rule.py +++ b/bin/addons/base/ir/ir_rule.py @@ -120,9 +120,9 @@ class ir_rule(osv.osv): return res _columns = { - 'field_id': fields.many2one('ir.model.fields', 'Field',domain= "[('model_id','=', parent.model_id)]", select=1, required=True), - 'operator':fields.selection((('=', '='), ('<>', '<>'), ('<=', '<='), ('>=', '>='), ('in', 'in'), ('child_of', 'child_of')), 'Operator', required=True), - 'operand':fields.selection(_operand,'Operand', size=64, required=True), + 'field_id': fields.many2one('ir.model.fields', 'Field',domain= "[('model_id','=', parent.model_id)]", select=1), + 'operator':fields.selection((('=', '='), ('<>', '<>'), ('<=', '<='), ('>=', '>='), ('in', 'in'), ('child_of', 'child_of')), 'Operator'), + 'operand':fields.selection(_operand,'Operand', size=64), 'rule_group': fields.many2one('ir.rule.group', 'Group', select=2, required=True, ondelete="cascade"), 'domain_force': fields.char('Force Domain', size=250), 'domain': fields.function(_domain_force_get, method=True, string='Domain', type='char', size=250) diff --git a/bin/addons/base/ir/ir_ui_menu.py b/bin/addons/base/ir/ir_ui_menu.py index 5715fc9ac78..75a3550250e 100644 --- a/bin/addons/base/ir/ir_ui_menu.py +++ b/bin/addons/base/ir/ir_ui_menu.py @@ -233,7 +233,7 @@ class ir_ui_menu(osv.osv): 'complete_name': fields.function(_get_full_name, method=True, string='Complete Name', type='char', size=128), 'icon': fields.selection(tools.icons, 'Icon', size=64), - 'icon_pict': fields.function(_get_icon_pict, method=True, type='picture'), + 'icon_pict': fields.function(_get_icon_pict, method=True, type='char', size=32), 'action': fields.function(_action, fnct_inv=_action_inv, method=True, type='reference', string='Action', selection=[ diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py index 9042ee9e711..2da10afc509 100644 --- a/bin/addons/base/module/module.py +++ b/bin/addons/base/module/module.py @@ -493,10 +493,11 @@ class module(osv.osv): id = super(module, self).create(cr, uid, data, context) if data.get('name'): self.pool.get('ir.model.data').create(cr, uid, { - 'name': 'module_name_translation', + 'name': 'module_meta_information', 'model': 'ir.module.module', 'res_id': id, - 'module': data['name'] + 'module': data['name'], + 'noupdate': True, }) return id module() diff --git a/bin/openerp-server.py b/bin/openerp-server.py index a3d14ddfae1..a518f8a99c0 100755 --- a/bin/openerp-server.py +++ b/bin/openerp-server.py @@ -42,9 +42,12 @@ import signal # the path needs to be updated before any `import xml` # TODO: remove PyXML dependencies, use lxml instead. #---------------------------------------------------------- -_oldxml = '/usr/lib/python%s/site-packages/oldxml' % sys.version[:3] -if os.path.exists(_oldxml): - sys.path.append(_oldxml) +_oldxml1 = '/usr/lib/python%s/site-packages/oldxml' % sys.version[:3] +_oldxml2 = '/usr/lib/python%s/dist-packages/oldxml' % sys.version[:3] +if os.path.exists(_oldxml1): + sys.path.insert(0,_oldxml1) +elif os.path.exists(_oldxml2): + sys.path.insert(0,_oldxml2) import release diff --git a/bin/osv/fields.py b/bin/osv/fields.py index 2a4ab8837c4..7d34f686010 100644 --- a/bin/osv/fields.py +++ b/bin/osv/fields.py @@ -686,8 +686,9 @@ class related(function): t_data = False break if field_detail['type'] in ('one2many', 'many2many'): - t_id=t_data.id - t_data = t_data[self.arg[i]][0] + if self._type != "many2one": + t_id=t_data.id + t_data = t_data[self.arg[i]][0] else: t_id=t_data['id'] t_data = t_data[self.arg[i]] diff --git a/bin/osv/orm.py b/bin/osv/orm.py index fa4559ff491..cedacb728b3 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -52,12 +52,14 @@ import fields import tools import sys + try: from xml import dom, xpath except ImportError: sys.stderr.write("ERROR: Import xpath module\n") sys.stderr.write("ERROR: Try to install the old python-xml package\n") - sys.exit(2) + sys.stderr.write('On Ubuntu Jaunty, try this: sudo cp /usr/lib/python2.6/dist-packages/oldxml/_xmlplus/utils/boolean.so /usr/lib/python2.5/site-packages/oldxml/_xmlplus/utils\n') + raise from tools.config import config @@ -80,6 +82,8 @@ class except_orm(Exception): self.value = value self.args = (name, value) +class BrowseRecordError(Exception): + pass # Readonly python database object browser class browse_null(object): @@ -126,7 +130,6 @@ class browse_record(object): ''' if not context: context = {} - assert id and isinstance(id, (int, long,)), _('Wrong ID for the browse record, got %r, expected an integer.') % (id,) self._list_class = list_class or browse_record_list self._cr = cr self._uid = uid @@ -139,6 +142,11 @@ class browse_record(object): cache.setdefault(table._name, {}) self._data = cache[table._name] + if not (id and isinstance(id, (int, long,))): + raise BrowseRecordError(_('Wrong ID for the browse record, got %r, expected an integer.') % (id,)) +# if not table.exists(cr, uid, id, context): +# raise BrowseRecordError(_('Object %s does not exists') % (self,)) + if id not in self._data: self._data[id] = {'id': id} @@ -1163,6 +1171,9 @@ class orm_template(object): def copy(self, cr, uid, id, default=None, context=None): raise _('The copy method is not implemented on this object !') + def exists(self, cr, uid, id, context=None): + raise _('The exists method is not implemented on this object !') + def read_string(self, cr, uid, id, langs, fields=None, context=None): res = {} res2 = {} @@ -1204,7 +1215,7 @@ class orm_template(object): raise NotImplementedError() class orm_memory(orm_template): - _protected = ['read', 'write', 'create', 'default_get', 'perm_read', 'unlink', 'fields_get', 'fields_view_get', 'search', 'name_get', 'distinct_field_get', 'name_search', 'copy', 'import_data', 'search_count'] + _protected = ['read', 'write', 'create', 'default_get', 'perm_read', 'unlink', 'fields_get', 'fields_view_get', 'search', 'name_get', 'distinct_field_get', 'name_search', 'copy', 'import_data', 'search_count', 'exists'] _inherit_fields = {} _max_count = 200 _max_hours = 1 @@ -1389,11 +1400,14 @@ class orm_memory(orm_template): def _check_removed_columns(self, cr, log=False): # nothing to check in memory... pass + + def exists(self, cr, uid, id, context=None): + return id in self.datas class orm(orm_template): _sql_constraints = [] _table = None - _protected = ['read','write','create','default_get','perm_read','unlink','fields_get','fields_view_get','search','name_get','distinct_field_get','name_search','copy','import_data','search_count'] + _protected = ['read','write','create','default_get','perm_read','unlink','fields_get','fields_view_get','search','name_get','distinct_field_get','name_search','copy','import_data','search_count', 'exists'] def _parent_store_compute(self, cr): logger = netsvc.Logger() @@ -2271,9 +2285,16 @@ class orm(orm_template): # call the 'set' method of fields which are not classic_write upd_todo.sort(lambda x, y: self._columns[x].priority-self._columns[y].priority) + + # default element in context must be remove when call a one2many or many2many + rel_context = context.copy() + for c in context.items(): + if c[0].startswith('default_'): + del rel_context[c[0]] + for field in upd_todo: for id in ids: - self._columns[field].set(cr, self, id, field, vals[field], user, context=context) + self._columns[field].set(cr, self, id, field, vals[field], user, context=rel_context) for table in self._inherits: col = self._inherits[table] @@ -2472,8 +2493,15 @@ class orm(orm_template): cr.execute('update '+self._table+' set parent_left=parent_left+2 where parent_left>%s', (pleft,)) cr.execute('update '+self._table+' set parent_right=parent_right+2 where parent_right>%s', (pleft,)) cr.execute('update '+self._table+' set parent_left=%s,parent_right=%s where id=%s', (pleft+1,pleft+2,id_new)) + + # default element in context must be remove when call a one2many or many2many + rel_context = context.copy() + for c in context.items(): + if c[0].startswith('default_'): + del rel_context[c[0]] + for field in upd_todo: - self._columns[field].set(cr, self, id_new, field, vals[field], user, context) + self._columns[field].set(cr, self, id_new, field, vals[field], user, rel_context) self._validate(cr, user, [id_new], context) result = self._store_get_values(cr, user, [id_new], vals.keys(), context) @@ -2736,6 +2764,10 @@ class orm(orm_template): trans_obj.create(cr,uid,record) return new_id + def exists(self, cr, uid, id, context=None): + cr.execute('SELECT count(1) FROM "%s" where id=%%s' % (self._table,), (id,)) + return bool(cr.fetchone()[0]) + def check_recursion(self, cr, uid, ids, parent=None): if not parent: parent = self._parent_name diff --git a/bin/report/render/html2html/html2html.py b/bin/report/render/html2html/html2html.py index db6a1ea511c..fa07e9b4726 100644 --- a/bin/report/render/html2html/html2html.py +++ b/bin/report/render/html2html/html2html.py @@ -30,7 +30,7 @@ import re from reportlab.lib.utils import ImageReader _regex = re.compile('\[\[(.+?)\]\]') - +utils._regex = re.compile('\[\[\s*(.+?)\s*\]\]',re.DOTALL) class html2html(object): def __init__(self, html, localcontext): self.localcontext = localcontext @@ -48,6 +48,7 @@ class html2html(object): if len(child): for n in new_child: new_child.text = utils._process_text(self, child.text) + new_child.tail = utils._process_text(self, child.tail) new_child.remove(n) process_text(child, new_child) else: @@ -66,6 +67,7 @@ class html2html(object): else : new_child.getparent().remove(new_child) new_child.text = utils._process_text(self, child.text) + new_child.tail = utils._process_text(self, child.tail) self._node = copy.deepcopy(self.etree) for n in self._node: self._node.remove(n) diff --git a/bin/report/render/rml2pdf/trml2pdf.py b/bin/report/render/rml2pdf/trml2pdf.py index b281b34636b..7efda11382b 100644 --- a/bin/report/render/rml2pdf/trml2pdf.py +++ b/bin/report/render/rml2pdf/trml2pdf.py @@ -450,11 +450,11 @@ class _rml_flowable(object): for key in txt_n.attrib.keys(): if key in ('rml_except', 'rml_loop', 'rml_tag'): del txt_n.attrib[key] - if not self._textual(n).isspace(): + if True or not self._textual(n).isspace(): txt_n.text = self._textual(n) txt_n.tail = '' rc1 += etree.tostring(txt_n) - rc1 += utils._process_text(self, node.tail or '') + #rc1 += utils._process_text(self, node.tail or '') return rc1 def _table(self, node): @@ -759,8 +759,13 @@ class _rml_template(object): def render(self, node_stories): fis = [] r = _rml_flowable(self.doc,self.localcontext, images=self.images, path=self.path, title=self.title) + story_cnt = 0 for node_story in node_stories: fis += r.render(node_story) + if self.localcontext: + story_cnt += 1 + if story_cnt == len(self.localcontext['objects']): + fis.append(PageCount()) fis.append(platypus.PageBreak()) self.doc_tmpl.build(fis) diff --git a/bin/report/render/rml2pdf/utils.py b/bin/report/render/rml2pdf/utils.py index 9aed08e3c9c..65fb2366c9a 100644 --- a/bin/report/render/rml2pdf/utils.py +++ b/bin/report/render/rml2pdf/utils.py @@ -103,13 +103,14 @@ def _process_text(self, txt): result += self.localcontext.get('translate', lambda x:x)(sps.pop(0)) if sps: try: - txt2 = str2xml(eval(sps.pop(0),self.localcontext)) + txt = eval(sps.pop(0),self.localcontext) except: - txt2 = '' - if type(txt2)==type('') or type(txt2)==type(u''): + pass + if type(txt)==type('') or type(txt)==type(u''): + txt2 = str2xml(txt) result += txt2 - elif (txt2 is not None) and (txt2 is not False): - result += str(txt2) + elif (txt is not None) and (txt is not False): + result += str(txt) return result def text_get(node): diff --git a/bin/service/security.py b/bin/service/security.py index 040d71be6e1..b8db107302a 100644 --- a/bin/service/security.py +++ b/bin/service/security.py @@ -27,7 +27,10 @@ _uid_cache = {} def login(db, login, password): cr = pooler.get_db(db).cursor() - cr.execute('select id from res_users where login=%s and password=%s and active', (login.encode('utf-8'), password.encode('utf-8'))) + if password: + cr.execute('select id from res_users where login=%s and password=%s and active', (login.encode('utf-8'), password.encode('utf-8'))) + else: + cr.execute('select id from res_users where login=%s and password is null and active', (login.encode('utf-8'),)) res = cr.fetchone() cr.close() if res: @@ -45,7 +48,10 @@ def check(db, uid, passwd): if _uid_cache.get(db, {}).get(uid) == passwd: return True cr = pooler.get_db(db).cursor() - cr.execute('select count(*) from res_users where id=%s and password=%s', (int(uid), passwd)) + if passwd: + cr.execute('select count(*) from res_users where id=%s and password=%s', (int(uid), passwd)) + else: + cr.execute('select count(*) from res_users where id=%s and password is null', (int(uid),)) res = cr.fetchone()[0] cr.close() if not bool(res): @@ -60,7 +66,10 @@ def check(db, uid, passwd): def access(db, uid, passwd, sec_level, ids): cr = pooler.get_db(db).cursor() - cr.execute('select id from res_users where id=%s and password=%s', (uid, passwd)) + if passwd: + cr.execute('select id from res_users where id=%s and password=%s', (uid, passwd)) + else: + cr.execute('select id from res_users where id=%s and password is null', (uid,)) res = cr.fetchone() cr.close() if not res: diff --git a/bin/service/web_services.py b/bin/service/web_services.py index 3b01ee78132..f5ad5e402e1 100644 --- a/bin/service/web_services.py +++ b/bin/service/web_services.py @@ -352,7 +352,7 @@ class common(netsvc.Service): self.exportMethod(self.timezone_get) self.exportMethod(self.get_available_updates) self.exportMethod(self.get_migration_scripts) - self.exportMethod(self.get_environment) + self.exportMethod(self.get_server_environment) def ir_set(self, db, uid, password, keys, args, name, value, replace=True, isobject=False): security.check(db, uid, password) @@ -505,7 +505,7 @@ GNU Public Licence. l.notifyChannel('migration', netsvc.LOG_ERROR, tb_s) raise - def get_environment(self,lang=False): + def get_server_environment(self,lang=False): try: if '.bzr' in os.listdir((os.getcwd()[0:-3])): fp = open(os.path.join(os.getcwd()[0:-3],'.bzr/branch/last-revision')) @@ -522,9 +522,10 @@ GNU Public Licence. 'PlatForm : %s\n' \ 'Operating System Version : %s\n' \ 'Python Version : %s\n'\ + 'Locale : %s\n' \ 'OpenERP-Server Version : %s\n'\ - 'OpenERP-Server Last Revision ID : %s'\ - 'Locale : %s'%(os.name,sys.platform,str(sys.version.split('\n')[1]),str(sys.version[0:5]),release.version,rev_no,lang) + 'OpenERP-Server Last Revision ID : %s' \ + %(os.name,sys.platform,str(sys.version.split('\n')[1]),str(sys.version[0:5]), lang, release.version,rev_no) return environment common() @@ -659,7 +660,7 @@ class report_spool(netsvc.Service): tb = sys.exc_info() tb_s = "".join(traceback.format_exception(*tb)) logger = netsvc.Logger() - logger.notifyChannel('web-services', netsvc.LOG_ERROR,common().get_environment(context.get('lang',False))) + logger.notifyChannel('web-services', netsvc.LOG_ERROR,common().get_server_environment(context.get('lang',False))) logger.notifyChannel('web-services', netsvc.LOG_ERROR, 'Exception: %s\n%s' % (str(exception), tb_s)) self._reports[id]['exception'] = ExceptionWithTraceback(tools.exception_to_unicode(exception), tb) diff --git a/bin/tools/convert.py b/bin/tools/convert.py index 71bbb800cf5..fb85c4b88f2 100644 --- a/bin/tools/convert.py +++ b/bin/tools/convert.py @@ -259,7 +259,7 @@ form: module.record_id""" % (xml_id,) ids.append(self.id_get(cr, d_model, d_id)) if len(ids): self.pool.get(d_model).unlink(cr, self.uid, ids) - #self.pool.get('ir.model.data')._unlink(cr, self.uid, d_model, ids, direct=True) + self.pool.get('ir.model.data')._unlink(cr, self.uid, d_model, ids, direct=True) return False def _tag_report(self, cr, rec, data_node=None): diff --git a/bin/tools/misc.py b/bin/tools/misc.py index d8ad910f5fc..a2712ee006e 100644 --- a/bin/tools/misc.py +++ b/bin/tools/misc.py @@ -100,8 +100,8 @@ def init_db(cr): info.get('website', ''), i, info.get('name', False), info.get('description', ''), p_id, state, info.get('certificate'))) cr.execute('insert into ir_model_data \ - (name,model,module, res_id) values (%s,%s,%s,%s)', ( - 'module_meta_information', 'ir.module.module', i, id)) + (name,model,module, res_id, noupdate) values (%s,%s,%s,%s,%s)', ( + 'module_meta_information', 'ir.module.module', i, id, True)) dependencies = info.get('depends', []) for d in dependencies: cr.execute('insert into ir_module_module_dependency \ diff --git a/bin/tools/translate.py b/bin/tools/translate.py index 59d6630516f..0fb0bd8589c 100644 --- a/bin/tools/translate.py +++ b/bin/tools/translate.py @@ -24,7 +24,8 @@ import os from os.path import join import fnmatch import csv, xml.dom, re -import osv, tools, pooler +import tools, pooler +from osv.orm import BrowseRecordError import ir import netsvc from tools.misc import UpdateableStr @@ -420,7 +421,13 @@ def trans_generate(lang, modules, dbname=None): if not pool.get(model): logger.notifyChannel("db", netsvc.LOG_ERROR, "unable to find object %r" % (model,)) continue - obj = pool.get(model).browse(cr, uid, res_id) + + try: + obj = pool.get(model).browse(cr, uid, res_id) + except BrowseRecordError: + logger.notifyChannel("db", netsvc.LOG_ERROR, "unable to find object %r with id %d" % (model, res_id)) + continue + if model=='ir.ui.view': d = xml.dom.minidom.parseString(encode(obj.arch)) for t in trans_parse_view(d.documentElement): @@ -524,11 +531,8 @@ def trans_generate(lang, modules, dbname=None): for field_name,field_def in pool.get(model)._columns.items(): if field_def.translate: name = model + "," + field_name - try: - trad = getattr(obj, field_name) or '' - push_translation(module, 'model', name, xml_name, encode(trad)) - except: - pass + trad = getattr(obj, field_name) or '' + push_translation(module, 'model', name, xml_name, encode(trad)) # parse source code for _() calls def get_module_from_path(path): diff --git a/bin/workflow/workitem.py b/bin/workflow/workitem.py index fe098bdefb9..f9cf812c16c 100644 --- a/bin/workflow/workitem.py +++ b/bin/workflow/workitem.py @@ -88,10 +88,11 @@ def _execute(cr, workitem, activity, ident, stack): # # send a signal to parent workflow (signal: subflow.signal_name) # + signal_todo = [] if (workitem['state']=='active') and activity['signal_send']: cr.execute("select i.id,w.osv,i.res_id from wkf_instance i left join wkf w on (i.wkf_id=w.id) where i.id in (select inst_id from wkf_workitem where subflow_id=%s)", (workitem['inst_id'],)) for i in cr.fetchall(): - instance.validate(cr, i[0], (ident[0],i[1],i[2]), activity['signal_send'], force_running=True) + signal_todo.append((i[0], (ident[0],i[1],i[2]), activity['signal_send'])) if activity['kind']=='dummy': if workitem['state']=='active': @@ -139,6 +140,9 @@ def _execute(cr, workitem, activity, ident, stack): state= cr.fetchone()[0] if state=='complete': _state_set(cr, workitem, activity, 'complete', ident) + for t in signal_todo: + instance.validate(cr, t[0], t[1], t[2], force_running=True) + return result def _split_test(cr, workitem, split_mode, ident, signal=None, stack=None):