diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py index 1d4b76e3ed9..a64d6288881 100644 --- a/bin/addons/__init__.py +++ b/bin/addons/__init__.py @@ -675,6 +675,17 @@ def load_modules(db, force_demo=False, status=None, update_module=False): status = {} cr = db.cursor() + if cr: + cr.execute("SELECT relname FROM pg_class WHERE relkind='r' AND relname='ir_module_module'") + if len(cr.fetchall())==0: + logger.notifyChannel("init", netsvc.LOG_INFO, "init db") + tools.init_db(cr) +# cr.execute("update res_users set password=%s where id=%s",('admin',1)) + # in that case, force --init=all + tools.config["init"]["all"] = 1 + tools.config['update']['all'] = 1 + if not tools.config['without_demo']: + tools.config["demo"]['all'] = 1 force = [] if force_demo: force.append('demo') diff --git a/bin/addons/base/i18n/fr_FR.po b/bin/addons/base/i18n/fr_FR.po index b214f1f2b25..f7f24c35cac 100644 --- a/bin/addons/base/i18n/fr_FR.po +++ b/bin/addons/base/i18n/fr_FR.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.0\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-05-19 14:36+0000\n" -"PO-Revision-Date: 2009-06-08 09:44+0000\n" -"Last-Translator: Olivier (OpenERP) \n" +"PO-Revision-Date: 2009-07-07 13:42+0000\n" +"Last-Translator: Olivier (Open ERP) \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2009-06-08 09:48+0000\n" +"X-Launchpad-Export-Date: 2009-07-07 14:08+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base @@ -3424,7 +3424,6 @@ msgstr "Configuration de l'action client" #. module: base #: model:ir.actions.act_window,name:base.action_partner_address_form #: model:ir.model,name:base.model_res_partner_address -#: model:ir.ui.menu,name:base.menu_partner_address_form #: view:res.partner.address:0 msgid "Partner Addresses" msgstr "Adresses des Partenaires" @@ -4024,7 +4023,7 @@ msgstr "Etat d'Esprit Partenaire" #. module: base #: selection:ir.ui.view,type:0 msgid "mdx" -msgstr "" +msgstr "mdx" #. module: base #: model:res.country,name:base.bi @@ -6348,7 +6347,7 @@ msgstr "Voir la Réf." #. module: base #: selection:module.lang.install,init,lang:0 msgid "Dutch (Belgium) / Nederlands (Belgïe)" -msgstr "" +msgstr "Néerlandais (Belgique) / Nederlands (Belgïe)" #. module: base #: model:ir.actions.act_window,name:base.open_repository_tree diff --git a/bin/addons/base/ir/ir_model.py b/bin/addons/base/ir/ir_model.py index de1b2f0c53f..1e718144187 100644 --- a/bin/addons/base/ir/ir_model.py +++ b/bin/addons/base/ir/ir_model.py @@ -73,7 +73,7 @@ class ir_model(osv.osv): def write(self, cr, user, ids, vals, context=None): if context: - del context['__last_update'] + context.pop('__last_update', None) return super(ir_model,self).write(cr, user, ids, vals, context) def create(self, cr, user, vals, context=None): @@ -229,6 +229,9 @@ class ir_model_fields(osv.osv): 'field_description': lambda *a: '', } _order = "id" + _sql_constraints = [ + ('size_gt_zero', 'CHECK (size>0)', 'Size of the field can never be less than 1 !'), + ] def unlink(self, cr, user, ids, context=None): for field in self.browse(cr, user, ids, context): if field.state <> 'manual': @@ -244,17 +247,18 @@ class ir_model_fields(osv.osv): vals['model'] = model_data.model if context and context.get('manual',False): vals['state'] = 'manual' - res = super(ir_model_fields,self).create(cr, user, vals, context) + res = super(ir_model_fields,self).create(cr, user, vals, context) if vals.get('state','base') == 'manual': if not vals['name'].startswith('x_'): raise except_orm(_('Error'), _("Custom fields must have a name that starts with 'x_' !")) if 'relation' in vals and not self.pool.get('ir.model').search(cr, user, [('model','=',vals['relation'])]): raise except_orm(_('Error'), _("Model %s Does not Exist !" % vals['relation'])) - + if self.pool.get(vals['model']): self.pool.get(vals['model']).__init__(self.pool, cr) self.pool.get(vals['model'])._auto_init(cr, {}) + return res ir_model_fields() diff --git a/bin/addons/base/ir/ir_ui_view.py b/bin/addons/base/ir/ir_ui_view.py index b1e15b34cf4..5c4c50fae47 100644 --- a/bin/addons/base/ir/ir_ui_view.py +++ b/bin/addons/base/ir/ir_ui_view.py @@ -35,7 +35,7 @@ def _check_xml(self, cr, uid, ids, context={}): if not relaxng.validate(eview): logger = netsvc.Logger() logger.notifyChannel('init', netsvc.LOG_ERROR, 'The view does not fit the required schema !') - logger.notifyChannel('init', netsvc.LOG_ERROR, relaxng.error_log.last_error) + logger.notifyChannel('init', netsvc.LOG_ERROR, tools.ustr(relaxng.error_log.last_error)) return False return True diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py index 2da10afc509..6f818a69041 100644 --- a/bin/addons/base/module/module.py +++ b/bin/addons/base/module/module.py @@ -480,7 +480,7 @@ class module(osv.osv): if not mod.description: logger.notifyChannel("init", netsvc.LOG_WARNING, 'module %s: description is empty !' % (mod.name,)) - if not mod.certificate: + if not mod.certificate or not mod.certificate.isdigit(): logger.notifyChannel('init', netsvc.LOG_WARNING, 'module %s: no quality certificate' % (mod.name,)) else: val = long(mod.certificate[2:]) % 97 == 29 diff --git a/bin/addons/base/report/custom_default.xsl b/bin/addons/base/report/custom_default.xsl index f08078fcde4..2074bd2f7fb 100644 --- a/bin/addons/base/report/custom_default.xsl +++ b/bin/addons/base/report/custom_default.xsl @@ -7,8 +7,10 @@ 1cm 1cm 1cm - 29.7cm,21cm - + + + + a4_letter diff --git a/bin/netsvc.py b/bin/netsvc.py index 3ff6416f2b0..a96aa06db75 100644 --- a/bin/netsvc.py +++ b/bin/netsvc.py @@ -24,7 +24,6 @@ # ############################################################################## - import SimpleXMLRPCServer import SocketServer import logging @@ -121,7 +120,7 @@ def init_logger(): handler = logging.handlers.FileHandler(logf) except Exception, ex: sys.stderr.write("ERROR: couldn't create the logfile directory. Logging to the standard output.\n") - handler = logging.StreamHandler(sys.stdout) + handler = logging.StreamHandler(sys.stdout) else: # Normal Handler on standard output handler = logging.StreamHandler(sys.stdout) @@ -158,7 +157,10 @@ def init_logger(): class Logger(object): + def notifyChannel(self, name, level, msg): + from service.web_services import common + log = logging.getLogger(tools.ustr(name)) if level == LOG_DEBUG_RPC and not hasattr(log, level): @@ -171,6 +173,9 @@ class Logger(object): msg = tools.exception_to_unicode(msg) try: + if level in (LOG_ERROR,LOG_CRITICAL): + msg = common().get_server_environment() + msg + result = tools.ustr(msg).strip().split('\n') except UnicodeDecodeError: result = msg.strip().split('\n') @@ -210,7 +215,7 @@ class Agent(object): for timer in self._timers[db]: if not timer.isAlive(): self._timers[db].remove(timer) - + @classmethod def cancel(cls, db_name): """Cancel all timers for a given database. If None passed, all timers are cancelled""" @@ -218,7 +223,7 @@ class Agent(object): if db_name is None or db == db_name: for timer in cls._timers[db]: timer.cancel() - + @classmethod def quit(cls): cls.cancel(None) diff --git a/bin/osv/expression.py b/bin/osv/expression.py index 7e7f0f4c54c..3b36d4f95d3 100644 --- a/bin/osv/expression.py +++ b/bin/osv/expression.py @@ -198,10 +198,22 @@ class expression(object): self.__exp[i] = (left, 'in', right) else: # other field type + # add the time part to datetime field when it's not there: + if field._type == 'datetime' and self.__exp[i][2] and len(self.__exp[i][2]) == 10: + + self.__exp[i] = list(self.__exp[i]) + + if operator in ('>', '>='): + self.__exp[i][2] += ' 00:00:00' + elif operator in ('<', '<='): + self.__exp[i][2] += ' 23:59:59' + + self.__exp[i] = tuple(self.__exp[i]) + if field.translate: if operator in ('like', 'ilike', 'not like', 'not ilike'): right = '%%%s%%' % right - + operator = operator == '=like' and 'like' or operator query1 = '( SELECT res_id' \ @@ -224,7 +236,7 @@ class expression(object): ' SELECT id' \ ' FROM "' + working_table._table + '"' \ ' WHERE "' + left + '" ' + operator + instr + ")" - + query2 = [working_table._name + ',' + left, context.get('lang', False) or 'en_US', 'model', diff --git a/bin/osv/orm.py b/bin/osv/orm.py index c337e697f53..a522466823f 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -390,8 +390,12 @@ class orm_template(object): vals['select_level'] )) if 'module' in context: + name1 = 'field_' + self._table + '_' + k + cr.execute("select name from ir_model_data where name='%s'"%(name1)) + if cr.fetchone(): + name1 = name1 + "_" + str(id) cr.execute("INSERT INTO ir_model_data (name,date_init,date_update,module,model,res_id) VALUES (%s, now(), now(), %s, %s, %s)", \ - (('field_'+self._table+'_'+k)[:64], context['module'], 'ir.model.fields', id) + (name1[:64], context['module'], 'ir.model.fields', id) ) else: for key, val in vals.items(): @@ -443,32 +447,45 @@ class orm_template(object): def __export_row(self, cr, uid, row, fields, context=None): - def check_type(type,r): - if type == 'float': + def check_type(field_type): + if field_type == 'float': return 0.0 - elif type == 'integer': + elif field_type == 'integer': return 0 - elif type == 'char': - return '' - return r + elif field_type == 'boolean': + return False + return '' lines = [] data = map(lambda x: '', range(len(fields))) done = [] for fpos in range(len(fields)): - f = fields[fpos] + f = fields[fpos] if f: r = row i = 0 while i < len(f): - r = r[f[i]] + if f[i] == 'db_id': + r = r['id'] + elif f[i] == 'id': + model_data = self.pool.get('ir.model.data') + data_ids = model_data.search(cr, uid, [('model','=',r._table_name),('res_id','=',r['id'])]) + if len(data_ids): + d = model_data.read(cr, uid, data_ids, ['name','module'])[0] + if d['module']: + r = '%s.%s'%(d['module'],d['name']) + else: + r = d['name'] + else: + break + else: + r = r[f[i]] if not r: if f[i] in self._columns: - r = check_type(self._columns[f[i]]._type,r) + r = check_type(self._columns[f[i]]._type) elif f[i] in self._inherit_fields: - r = check_type(self._inherit_fields[f[i]][2]._type,r) - - data[fpos] = tools.ustr(r) + r = check_type(self._inherit_fields[f[i]][2]._type) + data[fpos] = r break if isinstance(r, (browse_record_list, list)): first = True @@ -476,56 +493,89 @@ class orm_template(object): or [], fields) if fields2 in done: break - done.append(fields2) + done.append(fields2) for row2 in r: lines2 = self.__export_row(cr, uid, row2, fields2, - context) + context) if first: for fpos2 in range(len(fields)): if lines2 and lines2[0][fpos2]: data[fpos2] = lines2[0][fpos2] + if not data[fpos]: + dt = '' + for rr in r : + if isinstance(rr.name, browse_record): + rr = rr.name + dt+=rr.name+',' + data[fpos] = dt[:-1] + break lines += lines2[1:] first = False else: - lines += lines2 + lines += lines2 break i += 1 if i == len(f): + if isinstance(r, browse_record): + r = r.name data[fpos] = tools.ustr(r or '') return [data] + lines - def export_data(self, cr, uid, ids, fields, context=None): + def export_data(self, cr, uid, ids, fields_to_export, context=None): if not context: context = {} - fields = map(lambda x: x.split('/'), fields) + imp_comp = context.get('import_comp',False) + cols = self._columns.copy() + for f in self._inherit_fields: + cols.update({f: self._inherit_fields[f][2]}) + fields_to_export = map(lambda x: x.split('/'), fields_to_export) + fields_export = fields_to_export+[] + warning = '' + warning_fields = [] + for field in fields_export: + if imp_comp and len(field)>1: + warning_fields.append('/'.join(map(lambda x:x in cols and cols[x].string or x,field))) + elif len (field) <=1: + if imp_comp and cols.get(field and field[0],False): + if ((isinstance(cols[field[0]], fields.function) and not cols[field[0]].store) \ + or isinstance(cols[field[0]], fields.related)\ + or isinstance(cols[field[0]], fields.one2many)): + warning_fields.append('/'.join(map(lambda x:x in cols and cols[x].string or x,field))) datas = [] + if imp_comp and len(warning_fields): + warning = 'Following columns cannot be exported since you select to be import compatible.\n%s' %('\n'.join(warning_fields)) + cr.rollback() + return {'warning' : warning} for row in self.browse(cr, uid, ids, context): - datas += self.__export_row(cr, uid, row, fields, context) - return datas + datas += self.__export_row(cr, uid, row, fields_to_export, context) + return {'datas':datas} def import_data(self, cr, uid, fields, datas, mode='init', current_module='', noupdate=False, context=None, filename=None): if not context: context = {} fields = map(lambda x: x.split('/'), fields) logger = netsvc.Logger() - - def process_liness(self, datas, prefix, fields_def, position=0): + ir_model_data_obj = self.pool.get('ir.model.data') + def process_liness(self, datas, prefix, current_module, model_name, fields_def, position=0): line = datas[position] row = {} translate = {} todo = [] warning = '' data_id = False + data_res_id = False + is_xml_id = False + is_db_id = False + ir_model_data_obj = self.pool.get('ir.model.data') # # Import normal fields # for i in range(len(fields)): if i >= len(line): raise Exception(_('Please check that all your lines have %d columns.') % (len(fields),)) - field = fields[i] - if field == ["id"]: - data_id = line[i] + if not line[i]: continue + field = fields[i] if (len(field)==len(prefix)+1) and field[len(prefix)].endswith(':id'): res_id = False if line[i]: @@ -535,8 +585,7 @@ class orm_template(object): if '.' in word: module, xml_id = word.rsplit('.', 1) else: - module, xml_id = current_module, word - ir_model_data_obj = self.pool.get('ir.model.data') + module, xml_id = current_module, word id = ir_model_data_obj._get_id(cr, uid, module, xml_id) res_id2 = ir_model_data_obj.read(cr, uid, [id], @@ -549,8 +598,7 @@ class orm_template(object): if '.' in line[i]: module, xml_id = line[i].rsplit('.', 1) else: - module, xml_id = current_module, line[i] - ir_model_data_obj = self.pool.get('ir.model.data') + module, xml_id = current_module, line[i] id = ir_model_data_obj._get_id(cr, uid, module, xml_id) res_res_id = ir_model_data_obj.read(cr, uid, [id], ['res_id']) @@ -565,6 +613,63 @@ class orm_template(object): continue if (len(field) == len(prefix)+1) and \ (prefix == field[0:len(prefix)]): + if field[len(prefix)] == "id": + # XML ID + db_id = False + is_xml_id = data_id = line[i] + d = data_id.split('.') + module = len(d)>1 and d[0] or '' + name = len(d)>1 and d[1] or d[0] + data_ids = ir_model_data_obj.search(cr, uid, [('module','=',module),('model','=',model_name),('name','=',name)]) + if len(data_ids): + d = ir_model_data_obj.read(cr, uid, data_ids, ['res_id'])[0] + db_id = d['res_id'] + if is_db_id and not db_id: + data_ids = ir_model_data_obj.search(cr, uid, [('module','=',module),('model','=',model_name),('res_id','=',is_db_id)]) + if not len(data_ids): + ir_model_data_obj.create(cr, uid, {'module':module, 'model':model_name, 'name':name, 'res_id':is_db_id}) + db_id = is_db_id + if is_db_id and int(db_id) != int(is_db_id): + warning += ("Id is not the same than existing one: " + str(is_db_id) + " !\n") + logger.notifyChannel("import", netsvc.LOG_ERROR, + "Id is not the same than existing one: " + str(is_db_id) + ' !\n') + continue + + if field[len(prefix)] == "db_id": + # Database ID + try: + line[i]= int(line[i]) + except Exception, e: + warning += (str(e) + "!\n") + logger.notifyChannel("import", netsvc.LOG_ERROR, + str(e) + '!\n') + continue + is_db_id = line[i] + obj_model = self.pool.get(model_name) + ids = obj_model.search(cr, uid, [('id','=',line[i])]) + if not len(ids): + warning += ("Database ID doesn't exist: " + model_name + ": " + str(line[i]) + " !\n") + logger.notifyChannel("import", netsvc.LOG_ERROR, + "Database ID doesn't exist: " + model_name + ": " + str(line[i]) + ' !\n') + continue + else: + data_res_id = ids[0] + data_ids = ir_model_data_obj.search(cr, uid, [('model','=',model_name),('res_id','=',line[i])]) + if len(data_ids): + d = ir_model_data_obj.read(cr, uid, data_ids, ['name','module'])[0] + data_id = d['name'] + if d['module']: + data_id = '%s.%s'%(d['module'],d['name']) + else: + data_id = d['name'] + if is_xml_id and not data_id: + data_id = is_xml_id + if is_xml_id and is_xml_id!=data_id: + warning += ("Id is not the same than existing one: " + str(line[i]) + " !\n") + logger.notifyChannel("import", netsvc.LOG_ERROR, + "Id is not the same than existing one: " + str(line[i]) + ' !\n') + + continue if fields_def[field[len(prefix)]]['type'] == 'integer': res = line[i] and int(line[i]) elif fields_def[field[len(prefix)]]['type'] == 'boolean': @@ -580,18 +685,22 @@ class orm_template(object): sel = fields_def[field[len(prefix)]]['selection'](self, cr, uid, context) for key, val in sel: - if str(key) == line[i]: + if line[i] in [tools.ustr(key),tools.ustr(val)]: #Acepting key or value for selection field res = key + break if line[i] and not res: logger.notifyChannel("import", netsvc.LOG_WARNING, "key '%s' not found in selection field '%s'" % \ (line[i], field[len(prefix)])) + + warning += "Key/value '"+ str(line[i]) +"' not found in selection field '"+str(field[len(prefix)])+"'" + elif fields_def[field[len(prefix)]]['type']=='many2one': res = False if line[i]: relation = fields_def[field[len(prefix)]]['relation'] res2 = self.pool.get(relation).name_search(cr, uid, - line[i], [], operator='=') + line[i], [], operator='=', context=context) res = (res2 and res2[0][0]) or False if not res: warning += ('Relation not found: ' + line[i] + \ @@ -605,7 +714,7 @@ class orm_template(object): relation = fields_def[field[len(prefix)]]['relation'] for word in line[i].split(config.get('csv_internal_sep')): res2 = self.pool.get(relation).name_search(cr, - uid, word, [], operator='=') + uid, word, [], operator='=', context=context) res3 = (res2 and res2[0][0]) or False if not res3: warning += ('Relation not found: ' + \ @@ -625,19 +734,20 @@ class orm_template(object): if field[0] not in todo: todo.append(field[len(prefix)]) # - # Import one2many fields + # Import one2many, many2many fields # nbrmax = 1 for field in todo: - newfd = self.pool.get(fields_def[field]['relation']).fields_get( + relation_obj = self.pool.get(fields_def[field]['relation']) + newfd = relation_obj.fields_get( cr, uid, context=context) - res = process_liness(self, datas, prefix + [field], newfd, position) - (newrow, max2, w2, translate2, data_id2) = res + res = process_liness(self, datas, prefix + [field], current_module, relation_obj._name, newfd, position) + (newrow, max2, w2, translate2, data_id2, data_res_id2) = res nbrmax = max(nbrmax, max2) - warning = warning + w2 - reduce(lambda x, y: x and y, newrow) + warning = warning + w2 + reduce(lambda x, y: x and y, newrow) row[field] = (reduce(lambda x, y: x or y, newrow.values()) and \ - [(0, 0, newrow)]) or [] + [(0, 0, newrow)]) or [] i = max2 while (position+i) 1) and 'cents' or 'cent' cents = _100_to_text(cents_number) - cents = cents_number and '%s %s' % (cents, cents_name) or '' + cents = cents_number and '%s %s' % (cents.lower(), cents_name) or '' + if cents: + lacs += ' and %s' % (cents, ) return lacs diff --git a/bin/tools/convert.py b/bin/tools/convert.py index a57a3ee306f..a691f7c5e21 100644 --- a/bin/tools/convert.py +++ b/bin/tools/convert.py @@ -883,7 +883,7 @@ def convert_xml_import(cr, module, xmlfile, idref=None, mode='init', noupdate=Fa except Exception, e: logger = netsvc.Logger() logger.notifyChannel('init', netsvc.LOG_ERROR, 'The XML file does not fit the required schema !') - logger.notifyChannel('init', netsvc.LOG_ERROR, relaxng.error_log.last_error) + logger.notifyChannel('init', netsvc.LOG_ERROR, tools.ustr(relaxng.error_log.last_error)) raise if idref is None: diff --git a/bin/tools/misc.py b/bin/tools/misc.py index 08ad464d3d3..2be922edb5d 100644 --- a/bin/tools/misc.py +++ b/bin/tools/misc.py @@ -672,9 +672,9 @@ class cache(object): if time.time()-self.timeout > self.lasttime: self.lasttime = time.time() t = time.time()-self.timeout - for key in self.cache.keys(): - if self.cache[key][1] '..\\Lib' + disk_basedir = os.path.dirname(os.path.dirname(pytz.__file__)) + zipfile_path = os.path.join(options['py2exe']['dist_dir'], 'library.zip') + z = zipfile.ZipFile(zipfile_path, 'a') + for absdir, directories, filenames in os.walk(zoneinfo_dir): + assert absdir.startswith(disk_basedir), (absdir, disk_basedir) + zip_dir = absdir[len(disk_basedir):] + for f in filenames: + z.write(os.path.join(absdir, f), os.path.join(zip_dir, f)) + z.close()