diff --git a/bin/addons/base/ir/ir_model.py b/bin/addons/base/ir/ir_model.py index de1b2f0c53f..7fc27f6cc78 100644 --- a/bin/addons/base/ir/ir_model.py +++ b/bin/addons/base/ir/ir_model.py @@ -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/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/osv/orm.py b/bin/osv/orm.py index 2fcf91f1616..ca5dbf471eb 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -434,32 +434,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 @@ -467,56 +480,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]: @@ -526,8 +572,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], @@ -540,8 +585,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_id = ir_model_data_obj.read(cr, uid, [id], ['res_id'])[0]['res_id'] @@ -554,6 +598,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': @@ -584,7 +685,7 @@ class orm_template(object): 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] + \ @@ -598,7 +699,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: ' + \ @@ -618,19 +719,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/misc.py b/bin/tools/misc.py index a2712ee006e..9d4ea4d66cd 100644 --- a/bin/tools/misc.py +++ b/bin/tools/misc.py @@ -659,9 +659,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]