From 07881a0c50b00635f5becbb7c0c3b416f34e1263 Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Fri, 2 Sep 2011 17:18:53 +0530 Subject: [PATCH 001/106] [REF]:execute method in audittrail_objects_proxy bzr revid: nch@tinyerp.com-20110902114853-z7f1uofjgh8poq0z --- addons/audittrail/audittrail.py | 39 +++++++++++++-------------------- 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index bfa6bca8f34..ffb44502ba4 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -292,7 +292,7 @@ class audittrail_objects_proxy(object_proxy): def log_fct(self, db, uid, model, method, fct_src, *args): """ - Logging function: This function is performs logging oprations according to method + Logging function: This function is performs logging operations according to method @param db: the current database @param uid: the current user’s ID for security checks, @param object: Object who's values are being changed @@ -482,41 +482,32 @@ class audittrail_objects_proxy(object_proxy): cr = pooler.get_db(db).cursor() cr.autocommit(True) logged_uids = [] + rule = False + ignore_methods = ['default_get','read','fields_view_get','fields_get','search', + 'search_count','name_search','name_get','get','request_get', + 'get_sc', 'unlink', 'write', 'create'] fct_src = super(audittrail_objects_proxy, self).execute - - def my_fct(db, uid, model, method, *args): - rule = False + try: model_ids = model_pool.search(cr, uid, [('model', '=', model)]) model_id = model_ids and model_ids[0] or False - - for model_name in pool.obj_list(): - if model_name == 'audittrail.rule': - rule = True - if not rule: - return fct_src(db, uid_orig, model, method, *args) - if not model_id: - return fct_src(db, uid_orig, model, method, *args) - + if 'audittrail.rule' in pool.obj_list(): + rule = True + if not rule or not model_id: + return fct_src(db, uid_orig, model, method, *args) rule_ids = rule_pool.search(cr, uid, [('object_id', '=', model_id), ('state', '=', 'subscribed')]) if not rule_ids: return fct_src(db, uid_orig, model, method, *args) - for thisrule in rule_pool.browse(cr, uid, rule_ids): - for user in thisrule.user_id: - logged_uids.append(user.id) + for model_rule in rule_pool.browse(cr, uid, rule_ids): + logged_uids += map(lambda x:x.id, model_rule.user_id) if not logged_uids or uid in logged_uids: if method in ('read', 'write', 'create', 'unlink'): - if getattr(thisrule, 'log_' + method): + if getattr(model_rule, 'log_' + method): return self.log_fct(db, uid_orig, model, method, fct_src, *args) - - elif method not in ('default_get','read','fields_view_get','fields_get','search','search_count','name_search','name_get','get','request_get', 'get_sc', 'unlink', 'write', 'create'): - if thisrule.log_action: + elif method not in ignore_methods: + if model_rule.log_action: return self.log_fct(db, uid_orig, model, method, fct_src, *args) - return fct_src(db, uid_orig, model, method, *args) - try: - res = my_fct(db, uid, model, method, *args) - return res finally: cr.close() From 2fef7cd890150c20b4cb9835d601263de1ba5632 Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Mon, 5 Sep 2011 14:39:26 +0530 Subject: [PATCH 002/106] [IMP]:refactored with speed improvement:get_value_text method bzr revid: nch@tinyerp.com-20110905090926-jjklwr3p12sbjzl2 --- addons/audittrail/audittrail.py | 50 +++++++++++---------------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index ffb44502ba4..0780679f49c 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -203,37 +203,22 @@ class audittrail_objects_proxy(object_proxy): if field_name in('__last_update','id'): return values pool = pooler.get_pool(cr.dbname) - field_pool = pool.get('ir.model.fields') - model_pool = pool.get('ir.model') obj_pool = pool.get(model.model) - if obj_pool._inherits: - inherits_ids = model_pool.search(cr, uid, [('model', '=', obj_pool._inherits.keys()[0])]) - field_ids = field_pool.search(cr, uid, [('name', '=', field_name), ('model_id', 'in', (model.id, inherits_ids[0]))]) - else: - field_ids = field_pool.search(cr, uid, [('name', '=', field_name), ('model_id', '=', model.id)]) - field_id = field_ids and field_ids[0] or False - assert field_id, _("'%s' field does not exist in '%s' model" %(field_name, model.model)) - - field = field_pool.read(cr, uid, field_id) - relation_model = field['relation'] - relation_model_pool = relation_model and pool.get(relation_model) or False - - if field['ttype'] == 'many2one': - res = False - relation_id = False - if values and type(values) == tuple: - relation_id = values[0] - if relation_id and relation_model_pool: - relation_model_object = relation_model_pool.read(cr, uid, relation_id, [relation_model_pool._rec_name]) - res = relation_model_object[relation_model_pool._rec_name] - return res - - elif field['ttype'] in ('many2many','one2many'): - res = [] - for relation_model_object in relation_model_pool.read(cr, uid, values, [relation_model_pool._rec_name]): - res.append(relation_model_object[relation_model_pool._rec_name]) - return res - + field_obj = obj_pool._all_columns.get(field_name, False) + assert field_obj, _("'%s' field does not exist in '%s' model" %(field_name, model.model)) + field_obj = field_obj.column + if field_obj._obj: + relation_model_pool = pool.get(field_obj._obj) + relational_rec_name = relation_model_pool._rec_name + if field_obj._type == 'many2one': + if values and isinstance(values, tuple): + if values[0]: + relation_model_object = relation_model_pool.read(cr, uid, values[0], [relational_rec_name]) + return relation_model_object.get(relational_rec_name) + return False + elif field_obj._type in ('many2many','one2many'): + data = relation_model_pool.read(cr, uid, values, [relational_rec_name]) + return map(lambda x:x.get(relational_rec_name, False), data) return values def create_log_line(self, cr, uid, log_id, model, lines=[]): @@ -482,7 +467,6 @@ class audittrail_objects_proxy(object_proxy): cr = pooler.get_db(db).cursor() cr.autocommit(True) logged_uids = [] - rule = False ignore_methods = ['default_get','read','fields_view_get','fields_get','search', 'search_count','name_search','name_get','get','request_get', 'get_sc', 'unlink', 'write', 'create'] @@ -490,9 +474,7 @@ class audittrail_objects_proxy(object_proxy): try: model_ids = model_pool.search(cr, uid, [('model', '=', model)]) model_id = model_ids and model_ids[0] or False - if 'audittrail.rule' in pool.obj_list(): - rule = True - if not rule or not model_id: + if not ('audittrail.rule' in pool.obj_list()) or not model_id: return fct_src(db, uid_orig, model, method, *args) rule_ids = rule_pool.search(cr, uid, [('object_id', '=', model_id), ('state', '=', 'subscribed')]) if not rule_ids: From 9ebdf040f574d1da0697435fdc4acae864085aec Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Mon, 5 Sep 2011 15:08:41 +0530 Subject: [PATCH 003/106] [IMP]:refactored create_log_line method bzr revid: nch@tinyerp.com-20110905093841-uk7nke7e36gsf4ig --- addons/audittrail/audittrail.py | 39 ++++++++++++++------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 0780679f49c..99382797d72 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -235,43 +235,36 @@ class audittrail_objects_proxy(object_proxy): model_pool = pool.get('ir.model') field_pool = pool.get('ir.model.fields') log_line_pool = pool.get('audittrail.log.line') - #start Loop for line in lines: - if line['name'] in('__last_update','id'): + if line['name'] in ('__last_update','id'): continue + field_obj = obj_pool._all_columns.get(line['name'], False) + assert field_obj, _("'%s' field does not exist in '%s' model" %(line['name'], model.model)) + field_obj = field_obj.column + old_value = line.get('old_value', '') + new_value = line.get('new_value', '') + old_value_text = line.get('old_value_text', '') + new_value_text = line.get('new_value_text', '') + search_models = [ model.id ] if obj_pool._inherits: - inherits_ids = model_pool.search(cr, uid, [('model', '=', obj_pool._inherits.keys()[0])]) - field_ids = field_pool.search(cr, uid, [('name', '=', line['name']), ('model_id', 'in', (model.id, inherits_ids[0]))]) - else: - field_ids = field_pool.search(cr, uid, [('name', '=', line['name']), ('model_id', '=', model.id)]) - field_id = field_ids and field_ids[0] or False - assert field_id, _("'%s' field does not exist in '%s' model" %(line['name'], model.model)) - - field = field_pool.read(cr, uid, field_id) - old_value = 'old_value' in line and line['old_value'] or '' - new_value = 'new_value' in line and line['new_value'] or '' - old_value_text = 'old_value_text' in line and line['old_value_text'] or '' - new_value_text = 'new_value_text' in line and line['new_value_text'] or '' - + search_models += model_pool.search(cr, uid, [('model', 'in', obj_pool._inherits.keys())]) + field_id = field_pool.search(cr, uid, [('name', '=', line['name']), ('model_id', 'in', search_models)]) if old_value_text == new_value_text: continue - if field['ttype'] == 'many2one': - if type(old_value) == tuple: - old_value = old_value[0] - if type(new_value) == tuple: - new_value = new_value[0] + if field_obj._type == 'many2one': + old_value = isinstance(old_value, tuple) and old_value[0] or old_value + new_value = isinstance(new_value, tuple) and new_value[0] or new_value vals = { "log_id": log_id, - "field_id": field_id, + "field_id": field_id and field_id[0] or False, "old_value": old_value, "new_value": new_value, "old_value_text": old_value_text, "new_value_text": new_value_text, - "field_description": field['field_description'] + "field_description": field_obj.string } line_id = log_line_pool.create(cr, uid, vals) cr.commit() - #End Loop return True From 2a828b8f5e86ce16bce6a114a34a8f893bed7c6e Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Mon, 5 Sep 2011 17:38:46 +0530 Subject: [PATCH 004/106] [IMP]:refactored log_fct to include create for o2m, m2m method bzr revid: nch@tinyerp.com-20110905120846-sletd1fvcfloqdxy --- addons/audittrail/audittrail.py | 55 +++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 99382797d72..841eda00d29 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -292,31 +292,38 @@ class audittrail_objects_proxy(object_proxy): model_id = model_ids and model_ids[0] or False assert model_id, _("'%s' Model does not exist..." %(model)) model = model_pool.browse(cr, uid, model_id) - + relational_table_log = args and args[-1] == 'child_relation_log' or False if method in ('create'): - res_id = fct_src(db, uid_orig, model.model, method, *args) - cr.commit() - resource = resource_pool.read(cr, uid, res_id, args[0].keys()) - vals = { - "method": method, - "object_id": model.id, - "user_id": uid_orig, - "res_id": resource['id'], - } - if 'id' in resource: - del resource['id'] - log_id = log_pool.create(cr, uid, vals) - lines = [] - for field in resource: - line = { - 'name': field, - 'new_value': resource[field], - 'new_value_text': self.get_value_text(cr, uid, field, resource[field], model) - } - lines.append(line) - self.create_log_line(cr, uid, log_id, model, lines) - - cr.commit() + fields_to_read = [] + if relational_table_log: + res_id = args[0] + else: + res_id = fct_src(db, uid_orig, model.model, method, *args) + cr.commit() + fields_to_read = args[0].keys() + resource = resource_pool.read(cr, uid, res_id, fields_to_read) + if not isinstance(resource, list): + resource = [resource] + vals = { 'method': method, 'object_id': model.id,'user_id': uid_orig} + for resource_data in resource: + vals.update({'res_id': resource_data['id']}) + if 'id' in resource_data: + del resource_data['id'] + log_id = log_pool.create(cr, uid, vals) + lines = [] + for field in resource_data: + field_obj = resource_pool._all_columns.get(field, False) + field_obj = field_obj.column + if field_obj._type in ('one2many','many2many'): + self.log_fct(db, uid, field_obj._obj, method, None, resource_data[field], 'child_relation_log') + line = { + 'name': field, + 'new_value': resource_data[field], + 'new_value_text': self.get_value_text(cr, uid, field, resource_data[field], model) + } + lines.append(line) + self.create_log_line(cr, uid, log_id, model, lines) + cr.commit() cr.close() return res_id From 43ff15c84d7f6f674e0201a2674b2a5a4e3c7082 Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Tue, 6 Sep 2011 11:01:24 +0530 Subject: [PATCH 005/106] [IMP]:get_value_text to use name_get for x2m and simply return [1] arg for m2o tuple bzr revid: nch@tinyerp.com-20110906053124-a3kw3j2g3weln60q --- addons/audittrail/audittrail.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 841eda00d29..1d42000488d 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -204,21 +204,19 @@ class audittrail_objects_proxy(object_proxy): return values pool = pooler.get_pool(cr.dbname) obj_pool = pool.get(model.model) - field_obj = obj_pool._all_columns.get(field_name, False) + field_obj = obj_pool._all_columns.get(field_name) assert field_obj, _("'%s' field does not exist in '%s' model" %(field_name, model.model)) field_obj = field_obj.column if field_obj._obj: relation_model_pool = pool.get(field_obj._obj) relational_rec_name = relation_model_pool._rec_name if field_obj._type == 'many2one': - if values and isinstance(values, tuple): - if values[0]: - relation_model_object = relation_model_pool.read(cr, uid, values[0], [relational_rec_name]) - return relation_model_object.get(relational_rec_name) - return False + if values: + return values[1] + return values elif field_obj._type in ('many2many','one2many'): - data = relation_model_pool.read(cr, uid, values, [relational_rec_name]) - return map(lambda x:x.get(relational_rec_name, False), data) + data = relation_model_pool.name_get(cr, uid, values) + return map(lambda x:x[1], data) return values def create_log_line(self, cr, uid, log_id, model, lines=[]): @@ -312,7 +310,7 @@ class audittrail_objects_proxy(object_proxy): log_id = log_pool.create(cr, uid, vals) lines = [] for field in resource_data: - field_obj = resource_pool._all_columns.get(field, False) + field_obj = resource_pool._all_columns.get(field) field_obj = field_obj.column if field_obj._type in ('one2many','many2many'): self.log_fct(db, uid, field_obj._obj, method, None, resource_data[field], 'child_relation_log') From 1947eed2df667bfd59b7c42306e19ab390170e96 Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Tue, 6 Sep 2011 11:24:31 +0530 Subject: [PATCH 006/106] [IMP]:support for x2m log unlink bzr revid: nch@tinyerp.com-20110906055431-a87bvbm0o7p1hts5 --- addons/audittrail/audittrail.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 1d42000488d..3f4417a15bb 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -359,33 +359,31 @@ class audittrail_objects_proxy(object_proxy): elif method in ('unlink'): res_ids = args[0] + res = False old_values = {} for res_id in res_ids: old_values[res_id] = resource_pool.read(cr, uid, res_id) - + vals = {'method': method,'object_id': model.id,'user_id': uid_orig} for res_id in res_ids: - vals = { - "method": method, - "object_id": model.id, - "user_id": uid_orig, - "res_id": res_id, - - } + vals.update({'res_id': res_id}) log_id = log_pool.create(cr, uid, vals) lines = [] for field in old_values[res_id]: - if field in ('id'): - continue + if field == 'id': continue + field_obj = resource_pool._all_columns.get(field) + field_obj = field_obj.column + if field_obj._type in ('one2many','many2many'): + self.log_fct(db, uid, field_obj._obj, method, None, old_values[res_id][field], 'child_relation_log') line = { 'name': field, 'old_value': old_values[res_id][field], 'old_value_text': self.get_value_text(cr, uid, field, old_values[res_id][field], model) } lines.append(line) - self.create_log_line(cr, uid, log_id, model, lines) - res = fct_src(db, uid_orig, model.model, method, *args) - cr.commit() + if not relational_table_log: + res = fct_src(db, uid_orig, model.model, method, *args) + cr.commit() cr.close() return res else: From d213821ea0dc2b000f95df025be8f45cefa63330 Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Tue, 6 Sep 2011 11:52:41 +0530 Subject: [PATCH 007/106] [IMP]:x2m logging when there is any action execute like on_change,copy etc bzr revid: nch@tinyerp.com-20110906062241-373t8wqelc9jsyk9 --- addons/audittrail/audittrail.py | 46 +++++++++++++++------------------ 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 3f4417a15bb..ed4fc5a551d 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -236,7 +236,7 @@ class audittrail_objects_proxy(object_proxy): for line in lines: if line['name'] in ('__last_update','id'): continue - field_obj = obj_pool._all_columns.get(line['name'], False) + field_obj = obj_pool._all_columns.get(line['name']) assert field_obj, _("'%s' field does not exist in '%s' model" %(line['name'], model.model)) field_obj = field_obj.column old_value = line.get('old_value', '') @@ -250,8 +250,8 @@ class audittrail_objects_proxy(object_proxy): if old_value_text == new_value_text: continue if field_obj._type == 'many2one': - old_value = isinstance(old_value, tuple) and old_value[0] or old_value - new_value = isinstance(new_value, tuple) and new_value[0] or new_value + old_value = old_value[0] + new_value = new_value[0] vals = { "log_id": log_id, "field_id": field_id and field_id[0] or False, @@ -305,8 +305,7 @@ class audittrail_objects_proxy(object_proxy): vals = { 'method': method, 'object_id': model.id,'user_id': uid_orig} for resource_data in resource: vals.update({'res_id': resource_data['id']}) - if 'id' in resource_data: - del resource_data['id'] + del resource_data['id'] log_id = log_pool.create(cr, uid, vals) lines = [] for field in resource_data: @@ -393,38 +392,36 @@ class audittrail_objects_proxy(object_proxy): res_ids = args[0] old_values = {} fields = [] - if len(args)>1 and type(args[1]) == dict: + if len(args) > 1 and isinstance(args[1], dict): fields = args[1].keys() - if type(res_ids) in (long, int): + if isinstance(res_ids, (long, int)): res_ids = [res_ids] if res_ids: - for resource in resource_pool.read(cr, uid, res_ids): + resource_data = resource_pool.read(cr, uid, res_ids) + for resource in resource_data: resource_id = resource['id'] - if 'id' in resource: - del resource['id'] + del resource['id'] old_values_text = {} old_value = {} for field in resource.keys(): + field_obj = resource_pool._all_columns.get(field) + field_obj = field_obj.column + if field_obj._type in ('one2many','many2many'): + self.log_fct(db, uid, field_obj._obj, method, None, resource[field], 'child_relation_log') old_value[field] = resource[field] old_values_text[field] = self.get_value_text(cr, uid, field, resource[field], model) old_values[resource_id] = {'text':old_values_text, 'value': old_value} - - res = fct_src(db, uid_orig, model.model, method, *args) - cr.commit() + if not relational_table_log: + res = fct_src(db, uid_orig, model.model, method, *args) + cr.commit() if res_ids: - for resource in resource_pool.read(cr, uid, res_ids): + resource_data = resource_pool.read(cr, uid, res_ids) + vals = {'method': method,'object_id': model.id,'user_id': uid_orig } + for resource in resource_data: resource_id = resource['id'] - if 'id' in resource: - del resource['id'] - vals = { - "method": method, - "object_id": model.id, - "user_id": uid_orig, - "res_id": resource_id, - } - - + del resource['id'] + vals.update({'res_id': resource_id}) log_id = log_pool.create(cr, uid, vals) lines = [] for field in resource.keys(): @@ -436,7 +433,6 @@ class audittrail_objects_proxy(object_proxy): 'old_value_text': old_values[resource_id]['text'][field] } lines.append(line) - self.create_log_line(cr, uid, log_id, model, lines) cr.commit() cr.close() From c70d21b6227dac93a0765e80f80a80a3718c532e Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Tue, 6 Sep 2011 12:24:16 +0530 Subject: [PATCH 008/106] [IMP]:refactored: removed code duplication bzr revid: nch@tinyerp.com-20110906065416-33abo0zg1e6n55v5 --- addons/audittrail/audittrail.py | 85 +++++++++++---------------------- 1 file changed, 28 insertions(+), 57 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index ed4fc5a551d..4fd99d7bba3 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -250,8 +250,8 @@ class audittrail_objects_proxy(object_proxy): if old_value_text == new_value_text: continue if field_obj._type == 'many2one': - old_value = old_value[0] - new_value = new_value[0] + old_value = old_value and old_value[0] or old_value + new_value = new_value and new_value[0] or new_value vals = { "log_id": log_id, "field_id": field_id and field_id[0] or False, @@ -439,90 +439,61 @@ class audittrail_objects_proxy(object_proxy): return res return True - - - def execute(self, db, uid, model, method, *args, **kw): + def audit_log_call(self, db, uid, model, method, action_type, *args, **argv): """ Overrides Object Proxy execute method @param db: the current database @param uid: the current user's ID for security checks, @param object: Object who's values are being changed @param method: get any method and create log - + @param action_type: either 'execute' or 'workflow' @return: Returns result as per method of Object proxy """ uid_orig = uid uid = 1 pool = pooler.get_pool(db) + logged_uids = [] model_pool = pool.get('ir.model') rule_pool = pool.get('audittrail.rule') cr = pooler.get_db(db).cursor() cr.autocommit(True) - logged_uids = [] - ignore_methods = ['default_get','read','fields_view_get','fields_get','search', - 'search_count','name_search','name_get','get','request_get', - 'get_sc', 'unlink', 'write', 'create'] - fct_src = super(audittrail_objects_proxy, self).execute + if action_type == 'execute': + ignore_methods = ['default_get','read','fields_view_get','fields_get','search', + 'search_count','name_search','name_get','get','request_get', + 'get_sc', 'unlink', 'write', 'create'] + fct_src = super(audittrail_objects_proxy, self).execute + else: + fct_src = super(audittrail_objects_proxy, self).exec_workflow try: model_ids = model_pool.search(cr, uid, [('model', '=', model)]) model_id = model_ids and model_ids[0] or False if not ('audittrail.rule' in pool.obj_list()) or not model_id: - return fct_src(db, uid_orig, model, method, *args) + return fct_src(db, uid_orig, model, method, *args, **argv) rule_ids = rule_pool.search(cr, uid, [('object_id', '=', model_id), ('state', '=', 'subscribed')]) if not rule_ids: - return fct_src(db, uid_orig, model, method, *args) - + return fct_src(db, uid_orig, model, method, *args, **argv) for model_rule in rule_pool.browse(cr, uid, rule_ids): logged_uids += map(lambda x:x.id, model_rule.user_id) if not logged_uids or uid in logged_uids: - if method in ('read', 'write', 'create', 'unlink'): - if getattr(model_rule, 'log_' + method): + if action_type == 'execute': + if method in ('read', 'write', 'create', 'unlink'): + if getattr(model_rule, 'log_' + method): + return self.log_fct(db, uid_orig, model, method, fct_src, *args) + elif method not in ignore_methods: + if model_rule.log_action: + return self.log_fct(db, uid_orig, model, method, fct_src, *args) + else: + if model_rule.log_workflow: return self.log_fct(db, uid_orig, model, method, fct_src, *args) - elif method not in ignore_methods: - if model_rule.log_action: - return self.log_fct(db, uid_orig, model, method, fct_src, *args) - return fct_src(db, uid_orig, model, method, *args) + return fct_src(db, uid_orig, model, method, *args, **argv) finally: cr.close() + def execute(self, db, uid, model, method, *args, **argv): + return self.audit_log_call(db, uid, model, method, 'execute', *args, **argv) + def exec_workflow(self, db, uid, model, method, *args, **argv): - uid_orig = uid - uid = 1 - - pool = pooler.get_pool(db) - logged_uids = [] - fct_src = super(audittrail_objects_proxy, self).exec_workflow - field = method - rule = False - model_pool = pool.get('ir.model') - rule_pool = pool.get('audittrail.rule') - cr = pooler.get_db(db).cursor() - cr.autocommit(True) - try: - model_ids = model_pool.search(cr, uid, [('model', '=', model)]) - for obj_name in pool.obj_list(): - if obj_name == 'audittrail.rule': - rule = True - if not rule: - return super(audittrail_objects_proxy, self).exec_workflow(db, uid_orig, model, method, *args, **argv) - if not model_ids: - return super(audittrail_objects_proxy, self).exec_workflow(db, uid_orig, model, method, *args, **argv) - - rule_ids = rule_pool.search(cr, uid, [('object_id', 'in', model_ids), ('state', '=', 'subscribed')]) - if not rule_ids: - return super(audittrail_objects_proxy, self).exec_workflow(db, uid_orig, model, method, *args, **argv) - - for thisrule in rule_pool.browse(cr, uid, rule_ids): - for user in thisrule.user_id: - logged_uids.append(user.id) - if not logged_uids or uid in logged_uids: - if thisrule.log_workflow: - return self.log_fct(db, uid_orig, model, method, fct_src, *args) - return super(audittrail_objects_proxy, self).exec_workflow(db, uid_orig, model, method, *args, **argv) - - return True - finally: - cr.close() + return self.audit_log_call(db, uid, model, method, 'workflow', *args, **argv) audittrail_objects_proxy() From b8596288a8c793c7e1b176d570f291668ab22a1a Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Tue, 6 Sep 2011 15:04:53 +0530 Subject: [PATCH 009/106] [IMP]:removedget_value_text to refactore the code..more improvements coming bzr revid: nch@tinyerp.com-20110906093453-c6z7wj8178w6o75g --- addons/audittrail/audittrail.py | 112 +++++++++++++++----------------- 1 file changed, 53 insertions(+), 59 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 4fd99d7bba3..41205982101 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -187,38 +187,6 @@ audittrail_log_line() class audittrail_objects_proxy(object_proxy): """ Uses Object proxy for auditing changes on object of subscribed Rules""" - def get_value_text(self, cr, uid, field_name, values, model, context=None): - """ - Gets textual values for the fields - e.g.: For field of type many2one it gives its name value instead of id - - @param cr: the current row, from the database cursor, - @param uid: the current user’s ID for security checks, - @param field_name: List of fields for text values - @param values: Values for field to be converted into textual values - @return: values: List of textual values for given fields - """ - if not context: - context = {} - if field_name in('__last_update','id'): - return values - pool = pooler.get_pool(cr.dbname) - obj_pool = pool.get(model.model) - field_obj = obj_pool._all_columns.get(field_name) - assert field_obj, _("'%s' field does not exist in '%s' model" %(field_name, model.model)) - field_obj = field_obj.column - if field_obj._obj: - relation_model_pool = pool.get(field_obj._obj) - relational_rec_name = relation_model_pool._rec_name - if field_obj._type == 'many2one': - if values: - return values[1] - return values - elif field_obj._type in ('many2many','one2many'): - data = relation_model_pool.name_get(cr, uid, values) - return map(lambda x:x[1], data) - return values - def create_log_line(self, cr, uid, log_id, model, lines=[]): """ Creates lines for changed fields with its old and new values @@ -234,8 +202,6 @@ class audittrail_objects_proxy(object_proxy): field_pool = pool.get('ir.model.fields') log_line_pool = pool.get('audittrail.log.line') for line in lines: - if line['name'] in ('__last_update','id'): - continue field_obj = obj_pool._all_columns.get(line['name']) assert field_obj, _("'%s' field does not exist in '%s' model" %(line['name'], model.model)) field_obj = field_obj.column @@ -279,7 +245,6 @@ class audittrail_objects_proxy(object_proxy): """ uid_orig = uid uid = 1 - res2 = args pool = pooler.get_pool(db) cr = pooler.get_db(db).cursor() resource_pool = pool.get(model) @@ -303,6 +268,7 @@ class audittrail_objects_proxy(object_proxy): if not isinstance(resource, list): resource = [resource] vals = { 'method': method, 'object_id': model.id,'user_id': uid_orig} + new_value_text = '' for resource_data in resource: vals.update({'res_id': resource_data['id']}) del resource_data['id'] @@ -311,12 +277,18 @@ class audittrail_objects_proxy(object_proxy): for field in resource_data: field_obj = resource_pool._all_columns.get(field) field_obj = field_obj.column + new_value_text = resource_data[field] + if field in ('__last_update', 'id'):continue if field_obj._type in ('one2many','many2many'): self.log_fct(db, uid, field_obj._obj, method, None, resource_data[field], 'child_relation_log') + data = pool.get(field_obj._obj).name_get(cr, uid, resource_data[field]) + new_value_text = map(lambda x:x[1], data) + elif field_obj._type == 'many2one': + new_value_text = resource_data[field] and resource_data[field][1] or resource_data[field] line = { 'name': field, 'new_value': resource_data[field], - 'new_value_text': self.get_value_text(cr, uid, field, resource_data[field], model) + 'new_value_text': new_value_text } lines.append(line) self.create_log_line(cr, uid, log_id, model, lines) @@ -328,29 +300,29 @@ class audittrail_objects_proxy(object_proxy): res_ids = args[0] old_values = {} res = fct_src(db, uid_orig, model.model, method, *args) - if type(res) == list: - for v in res: - old_values[v['id']] = v - else: - old_values[res['id']] = res + map(lambda x:old_values.setdefault(x['id'], x), res) + vals = {'method': method,'object_id': model.id,'user_id': uid_orig} + old_value_text = '' for res_id in old_values: - vals = { - "method": method, - "object_id": model.id, - "user_id": uid_orig, - "res_id": res_id, - - } + vals.update({'res_id': res_id}) log_id = log_pool.create(cr, uid, vals) lines = [] for field in old_values[res_id]: + if field in ('__last_update', 'id'):continue + field_obj = resource_pool._all_columns.get(field) + field_obj = field_obj.column + old_value_text = old_values[res_id][field] + if field_obj._type in ('one2many','many2many'): + data = pool.get(field_obj._obj).name_get(cr, uid, old_values[res_id][field]) + old_value_text = map(lambda x:x[1], data) + elif field_obj._type == 'many2one': + old_value_text = old_values[res_id][field] and old_values[res_id][field][1] or old_values[res_id][field] line = { - 'name': field, - 'old_value': old_values[res_id][field], - 'old_value_text': self.get_value_text(cr, uid, field, old_values[res_id][field], model) - } + 'name': field, + 'old_value': old_values[res_id][field], + 'old_value_text': old_value_text + } lines.append(line) - self.create_log_line(cr, uid, log_id, model, lines) cr.commit() cr.close() @@ -363,20 +335,26 @@ class audittrail_objects_proxy(object_proxy): for res_id in res_ids: old_values[res_id] = resource_pool.read(cr, uid, res_id) vals = {'method': method,'object_id': model.id,'user_id': uid_orig} + old_value_text = '' for res_id in res_ids: vals.update({'res_id': res_id}) log_id = log_pool.create(cr, uid, vals) lines = [] for field in old_values[res_id]: - if field == 'id': continue + if field in ('__last_update', 'id'):continue field_obj = resource_pool._all_columns.get(field) field_obj = field_obj.column + old_value_text = old_values[res_id][field] if field_obj._type in ('one2many','many2many'): self.log_fct(db, uid, field_obj._obj, method, None, old_values[res_id][field], 'child_relation_log') + data = pool.get(field_obj._obj).name_get(cr, uid, old_values[res_id][field]) + old_value_text = map(lambda x:x[1], data) + elif field_obj._type == 'many2one': + old_value_text = old_values[res_id][field] and old_values[res_id][field][1] or old_values[res_id][field] line = { 'name': field, 'old_value': old_values[res_id][field], - 'old_value_text': self.get_value_text(cr, uid, field, old_values[res_id][field], model) + 'old_value_text': old_value_text } lines.append(line) self.create_log_line(cr, uid, log_id, model, lines) @@ -398,26 +376,33 @@ class audittrail_objects_proxy(object_proxy): res_ids = [res_ids] if res_ids: resource_data = resource_pool.read(cr, uid, res_ids) + old_text = '' for resource in resource_data: resource_id = resource['id'] del resource['id'] old_values_text = {} old_value = {} for field in resource.keys(): + if field in ('__last_update', 'id'):continue field_obj = resource_pool._all_columns.get(field) field_obj = field_obj.column + old_text = resource[field] if field_obj._type in ('one2many','many2many'): - self.log_fct(db, uid, field_obj._obj, method, None, resource[field], 'child_relation_log') + self.log_fct(db, uid, field_obj._obj, method, None, resource[field], 'child_relation_log') + data = pool.get(field_obj._obj).name_get(cr, uid, resource[field]) + old_text = map(lambda x:x[1], data) + elif field_obj._type == 'many2one': + old_text = resource[field] and resource[field][1] or resource[field] old_value[field] = resource[field] - old_values_text[field] = self.get_value_text(cr, uid, field, resource[field], model) + old_values_text[field] = old_text old_values[resource_id] = {'text':old_values_text, 'value': old_value} if not relational_table_log: res = fct_src(db, uid_orig, model.model, method, *args) cr.commit() - if res_ids: resource_data = resource_pool.read(cr, uid, res_ids) vals = {'method': method,'object_id': model.id,'user_id': uid_orig } + old_value_text = '' for resource in resource_data: resource_id = resource['id'] del resource['id'] @@ -425,11 +410,20 @@ class audittrail_objects_proxy(object_proxy): log_id = log_pool.create(cr, uid, vals) lines = [] for field in resource.keys(): + if field in ('__last_update', 'id'):continue + field_obj = resource_pool._all_columns.get(field) + field_obj = field_obj.column + old_value_text = resource[field] + if field_obj._type in ('one2many','many2many'): + data = pool.get(field_obj._obj).name_get(cr, uid, resource[field]) + old_value_text = map(lambda x:x[1], data) + elif field_obj._type == 'many2one': + old_value_text = resource[field] and resource[field][1] or resource[field] line = { 'name': field, 'new_value': resource[field], 'old_value': old_values[resource_id]['value'][field], - 'new_value_text': self.get_value_text(cr, uid, field, resource[field], model), + 'new_value_text': old_value_text, 'old_value_text': old_values[resource_id]['text'][field] } lines.append(line) From dbd40832d51837844fbf0a94e842c41defbc56dc Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Tue, 6 Sep 2011 16:19:49 +0530 Subject: [PATCH 010/106] [REF]:more refactoring bzr revid: nch@tinyerp.com-20110906104949-i6uxzcdden0pq71a --- addons/audittrail/audittrail.py | 75 +++++++++------------------------ 1 file changed, 21 insertions(+), 54 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 41205982101..625d4d46072 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -231,7 +231,17 @@ class audittrail_objects_proxy(object_proxy): cr.commit() return True - + def get_x2m_m2o_values(self, cr, db, uid, pool, resource_pool, method, field, value, recursive=True): + field_obj = (resource_pool._all_columns.get(field)).column + if field_obj._type in ('one2many','many2many'): + if recursive: + self.log_fct(db, uid, field_obj._obj, method, None, value, 'child_relation_log') + data = pool.get(field_obj._obj).name_get(cr, uid, value) + return map(lambda x:x[1], data) + elif field_obj._type == 'many2one': + return value and value[1] or value + return False + def log_fct(self, db, uid, model, method, fct_src, *args): """ Logging function: This function is performs logging operations according to method @@ -268,27 +278,18 @@ class audittrail_objects_proxy(object_proxy): if not isinstance(resource, list): resource = [resource] vals = { 'method': method, 'object_id': model.id,'user_id': uid_orig} - new_value_text = '' for resource_data in resource: vals.update({'res_id': resource_data['id']}) del resource_data['id'] log_id = log_pool.create(cr, uid, vals) lines = [] for field in resource_data: - field_obj = resource_pool._all_columns.get(field) - field_obj = field_obj.column - new_value_text = resource_data[field] if field in ('__last_update', 'id'):continue - if field_obj._type in ('one2many','many2many'): - self.log_fct(db, uid, field_obj._obj, method, None, resource_data[field], 'child_relation_log') - data = pool.get(field_obj._obj).name_get(cr, uid, resource_data[field]) - new_value_text = map(lambda x:x[1], data) - elif field_obj._type == 'many2one': - new_value_text = resource_data[field] and resource_data[field][1] or resource_data[field] + ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, resource_data[field]) line = { 'name': field, 'new_value': resource_data[field], - 'new_value_text': new_value_text + 'new_value_text': ret_val and ret_val or resource_data[field] } lines.append(line) self.create_log_line(cr, uid, log_id, model, lines) @@ -302,25 +303,17 @@ class audittrail_objects_proxy(object_proxy): res = fct_src(db, uid_orig, model.model, method, *args) map(lambda x:old_values.setdefault(x['id'], x), res) vals = {'method': method,'object_id': model.id,'user_id': uid_orig} - old_value_text = '' for res_id in old_values: vals.update({'res_id': res_id}) log_id = log_pool.create(cr, uid, vals) lines = [] for field in old_values[res_id]: if field in ('__last_update', 'id'):continue - field_obj = resource_pool._all_columns.get(field) - field_obj = field_obj.column - old_value_text = old_values[res_id][field] - if field_obj._type in ('one2many','many2many'): - data = pool.get(field_obj._obj).name_get(cr, uid, old_values[res_id][field]) - old_value_text = map(lambda x:x[1], data) - elif field_obj._type == 'many2one': - old_value_text = old_values[res_id][field] and old_values[res_id][field][1] or old_values[res_id][field] + ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, old_values[res_id][field], False) line = { 'name': field, 'old_value': old_values[res_id][field], - 'old_value_text': old_value_text + 'old_value_text': ret_val and ret_val or old_values[res_id][field] } lines.append(line) self.create_log_line(cr, uid, log_id, model, lines) @@ -335,26 +328,17 @@ class audittrail_objects_proxy(object_proxy): for res_id in res_ids: old_values[res_id] = resource_pool.read(cr, uid, res_id) vals = {'method': method,'object_id': model.id,'user_id': uid_orig} - old_value_text = '' for res_id in res_ids: vals.update({'res_id': res_id}) log_id = log_pool.create(cr, uid, vals) lines = [] for field in old_values[res_id]: if field in ('__last_update', 'id'):continue - field_obj = resource_pool._all_columns.get(field) - field_obj = field_obj.column - old_value_text = old_values[res_id][field] - if field_obj._type in ('one2many','many2many'): - self.log_fct(db, uid, field_obj._obj, method, None, old_values[res_id][field], 'child_relation_log') - data = pool.get(field_obj._obj).name_get(cr, uid, old_values[res_id][field]) - old_value_text = map(lambda x:x[1], data) - elif field_obj._type == 'many2one': - old_value_text = old_values[res_id][field] and old_values[res_id][field][1] or old_values[res_id][field] + ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, old_values[res_id][field]) line = { 'name': field, 'old_value': old_values[res_id][field], - 'old_value_text': old_value_text + 'old_value_text': ret_val and ret_val or old_values[res_id][field] } lines.append(line) self.create_log_line(cr, uid, log_id, model, lines) @@ -376,7 +360,6 @@ class audittrail_objects_proxy(object_proxy): res_ids = [res_ids] if res_ids: resource_data = resource_pool.read(cr, uid, res_ids) - old_text = '' for resource in resource_data: resource_id = resource['id'] del resource['id'] @@ -384,17 +367,9 @@ class audittrail_objects_proxy(object_proxy): old_value = {} for field in resource.keys(): if field in ('__last_update', 'id'):continue - field_obj = resource_pool._all_columns.get(field) - field_obj = field_obj.column - old_text = resource[field] - if field_obj._type in ('one2many','many2many'): - self.log_fct(db, uid, field_obj._obj, method, None, resource[field], 'child_relation_log') - data = pool.get(field_obj._obj).name_get(cr, uid, resource[field]) - old_text = map(lambda x:x[1], data) - elif field_obj._type == 'many2one': - old_text = resource[field] and resource[field][1] or resource[field] + ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, resource[field]) old_value[field] = resource[field] - old_values_text[field] = old_text + old_values_text[field] = ret_val and ret_val or resource[field] old_values[resource_id] = {'text':old_values_text, 'value': old_value} if not relational_table_log: res = fct_src(db, uid_orig, model.model, method, *args) @@ -402,7 +377,6 @@ class audittrail_objects_proxy(object_proxy): if res_ids: resource_data = resource_pool.read(cr, uid, res_ids) vals = {'method': method,'object_id': model.id,'user_id': uid_orig } - old_value_text = '' for resource in resource_data: resource_id = resource['id'] del resource['id'] @@ -411,19 +385,12 @@ class audittrail_objects_proxy(object_proxy): lines = [] for field in resource.keys(): if field in ('__last_update', 'id'):continue - field_obj = resource_pool._all_columns.get(field) - field_obj = field_obj.column - old_value_text = resource[field] - if field_obj._type in ('one2many','many2many'): - data = pool.get(field_obj._obj).name_get(cr, uid, resource[field]) - old_value_text = map(lambda x:x[1], data) - elif field_obj._type == 'many2one': - old_value_text = resource[field] and resource[field][1] or resource[field] + ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, resource[field], False) line = { 'name': field, 'new_value': resource[field], 'old_value': old_values[resource_id]['value'][field], - 'new_value_text': old_value_text, + 'new_value_text': ret_val and ret_val or resource[field], 'old_value_text': old_values[resource_id]['text'][field] } lines.append(line) From 1dce682a32d0d20092553933921056df42a8d145 Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Tue, 6 Sep 2011 17:57:35 +0530 Subject: [PATCH 011/106] [REF] bzr revid: nch@tinyerp.com-20110906122735-4ikr703mpzbiav5b --- addons/audittrail/audittrail.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 625d4d46072..244f26fba3f 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -266,7 +266,7 @@ class audittrail_objects_proxy(object_proxy): assert model_id, _("'%s' Model does not exist..." %(model)) model = model_pool.browse(cr, uid, model_id) relational_table_log = args and args[-1] == 'child_relation_log' or False - if method in ('create'): + if method == 'create': fields_to_read = [] if relational_table_log: res_id = args[0] @@ -297,7 +297,7 @@ class audittrail_objects_proxy(object_proxy): cr.close() return res_id - elif method in ('read'): + elif method == 'read': res_ids = args[0] old_values = {} res = fct_src(db, uid_orig, model.model, method, *args) @@ -321,7 +321,7 @@ class audittrail_objects_proxy(object_proxy): cr.close() return res - elif method in ('unlink'): + elif method == 'unlink': res_ids = args[0] res = False old_values = {} From 044e4f4c1a6c3be56d8efc581bb4520f6fedf251 Mon Sep 17 00:00:00 2001 From: "Naresh (OpenERP)" Date: Wed, 7 Sep 2011 18:08:13 +0530 Subject: [PATCH 012/106] [IMP/REF]:allowed entires to be logged when doing different actions/workflow/on_change/write etc...and removed and refactored the code bzr revid: nch@tinyerp.com-20110907123813-4thzx4y3e9vic7uq --- addons/audittrail/audittrail.py | 231 ++++++++++++++++---------------- 1 file changed, 114 insertions(+), 117 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 244f26fba3f..579ba005ba3 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -231,7 +231,7 @@ class audittrail_objects_proxy(object_proxy): cr.commit() return True - def get_x2m_m2o_values(self, cr, db, uid, pool, resource_pool, method, field, value, recursive=True): + def get_value_text(self, cr, db, uid, pool, resource_pool, method, field, value, recursive=True): field_obj = (resource_pool._all_columns.get(field)).column if field_obj._type in ('one2many','many2many'): if recursive: @@ -242,6 +242,27 @@ class audittrail_objects_proxy(object_proxy): return value and value[1] or value return False + def start_log_process(self, cr, db, user_id, model, method, resource_data, pool, resource_pool): + key1 = '%s_value'%(method == 'create' and 'new' or 'old') + key2 = '%s_value_text'%(method == 'create' and 'new' or 'old') + uid = 1 + vals = { 'method': method, 'object_id': model.id,'user_id': user_id} + for resource, fields in resource_data.iteritems(): + vals.update({'res_id': resource}) + log_id = pool.get('audittrail.log').create(cr, uid, vals) + lines = [] + for field_key, value in fields.iteritems(): + if field_key in ('__last_update', 'id'):continue + ret_val = self.get_value_text(cr, db, uid, pool, resource_pool, method, field_key, value, method != 'read') + line = { + 'name': field_key, + key1: value, + key2: ret_val and ret_val or value + } + lines.append(line) + self.create_log_line(cr, uid, log_id, model, lines) + return True + def log_fct(self, db, uid, model, method, fct_src, *args): """ Logging function: This function is performs logging operations according to method @@ -259,14 +280,12 @@ class audittrail_objects_proxy(object_proxy): cr = pooler.get_db(db).cursor() resource_pool = pool.get(model) log_pool = pool.get('audittrail.log') - model_pool = pool.get('ir.model') - - model_ids = model_pool.search(cr, uid, [('model', '=', model)]) - model_id = model_ids and model_ids[0] or False - assert model_id, _("'%s' Model does not exist..." %(model)) - model = model_pool.browse(cr, uid, model_id) + model = self.check_rule_subscription(cr, uid, pool, model, False) + assert model, _("'%s' Model does not exist..." %(model)) + relational_table_log = args and args[-1] == 'child_relation_log' or False if method == 'create': + resource_data = {} fields_to_read = [] if relational_table_log: res_id = args[0] @@ -274,77 +293,29 @@ class audittrail_objects_proxy(object_proxy): res_id = fct_src(db, uid_orig, model.model, method, *args) cr.commit() fields_to_read = args[0].keys() - resource = resource_pool.read(cr, uid, res_id, fields_to_read) - if not isinstance(resource, list): - resource = [resource] - vals = { 'method': method, 'object_id': model.id,'user_id': uid_orig} - for resource_data in resource: - vals.update({'res_id': resource_data['id']}) - del resource_data['id'] - log_id = log_pool.create(cr, uid, vals) - lines = [] - for field in resource_data: - if field in ('__last_update', 'id'):continue - ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, resource_data[field]) - line = { - 'name': field, - 'new_value': resource_data[field], - 'new_value_text': ret_val and ret_val or resource_data[field] - } - lines.append(line) - self.create_log_line(cr, uid, log_id, model, lines) - cr.commit() + if res_id: + resource = resource_pool.read(cr, uid, res_id, fields_to_read) + if not isinstance(resource,list): + resource = [resource] + map(lambda x: resource_data.setdefault(x['id'], x), resource) + self.start_log_process(cr, db, uid_orig, model, method, resource_data, pool, resource_pool) + cr.commit() cr.close() return res_id - elif method == 'read': + elif method in('read', 'unlink'): res_ids = args[0] old_values = {} - res = fct_src(db, uid_orig, model.model, method, *args) - map(lambda x:old_values.setdefault(x['id'], x), res) - vals = {'method': method,'object_id': model.id,'user_id': uid_orig} - for res_id in old_values: - vals.update({'res_id': res_id}) - log_id = log_pool.create(cr, uid, vals) - lines = [] - for field in old_values[res_id]: - if field in ('__last_update', 'id'):continue - ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, old_values[res_id][field], False) - line = { - 'name': field, - 'old_value': old_values[res_id][field], - 'old_value_text': ret_val and ret_val or old_values[res_id][field] - } - lines.append(line) - self.create_log_line(cr, uid, log_id, model, lines) - cr.commit() - cr.close() - return res - - elif method == 'unlink': - res_ids = args[0] - res = False - old_values = {} - for res_id in res_ids: - old_values[res_id] = resource_pool.read(cr, uid, res_id) - vals = {'method': method,'object_id': model.id,'user_id': uid_orig} - for res_id in res_ids: - vals.update({'res_id': res_id}) - log_id = log_pool.create(cr, uid, vals) - lines = [] - for field in old_values[res_id]: - if field in ('__last_update', 'id'):continue - ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, old_values[res_id][field]) - line = { - 'name': field, - 'old_value': old_values[res_id][field], - 'old_value_text': ret_val and ret_val or old_values[res_id][field] - } - lines.append(line) - self.create_log_line(cr, uid, log_id, model, lines) - if not relational_table_log: + if method == 'read': res = fct_src(db, uid_orig, model.model, method, *args) - cr.commit() + map(lambda x: old_values.setdefault(x['id'], x), res) + else: + res = resource_pool.read(cr, uid, res_ids) + map(lambda x:old_values.setdefault(x['id'], x), res) + self.start_log_process(cr, db, uid_orig, model, method, old_values, pool, resource_pool) + if not relational_table_log and method == 'unlink': + res = fct_src(db, uid_orig, model.model, method, *args) + cr.commit() cr.close() return res else: @@ -359,47 +330,79 @@ class audittrail_objects_proxy(object_proxy): if isinstance(res_ids, (long, int)): res_ids = [res_ids] if res_ids: - resource_data = resource_pool.read(cr, uid, res_ids) - for resource in resource_data: - resource_id = resource['id'] - del resource['id'] - old_values_text = {} - old_value = {} - for field in resource.keys(): - if field in ('__last_update', 'id'):continue - ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, resource[field]) - old_value[field] = resource[field] - old_values_text[field] = ret_val and ret_val or resource[field] - old_values[resource_id] = {'text':old_values_text, 'value': old_value} - if not relational_table_log: - res = fct_src(db, uid_orig, model.model, method, *args) - cr.commit() + x2m_old_values = {} + old_values = {} + def inline_process_old_data(res_ids, model, model_id=False): + resource_pool = pool.get(model) + resource_data = resource_pool.read(cr, uid, res_ids) + _old_values = {} + for resource in resource_data: + _old_values_text = {} + _old_value = {} + resource_id = resource['id'] + for field in resource.keys(): + if field in ('__last_update', 'id'):continue + field_obj = (resource_pool._all_columns.get(field)).column + if field_obj._type in ('one2many','many2many'): + x2m_rule_ids, x2m_model = self.check_rule_subscription(cr, uid, pool, field_obj._obj) + if x2m_rule_ids: + x2m_old_values.update(inline_process_old_data(resource[field], field_obj._obj, x2m_model)) + ret_val = self.get_value_text(cr, db, uid, pool, resource_pool, method, field, resource[field], False) + _old_value[field] = resource[field] + _old_values_text[field] = ret_val and ret_val or resource[field] + _old_values[resource_id] = {'text':_old_values_text, 'value': _old_value} + if model_id: + _old_values[resource_id].update({'model_id':model_id}) + return _old_values + old_values.update(inline_process_old_data(res_ids, model.model)) + res = fct_src(db, uid_orig, model.model, method, *args) + cr.commit() if res_ids: - resource_data = resource_pool.read(cr, uid, res_ids) - vals = {'method': method,'object_id': model.id,'user_id': uid_orig } - for resource in resource_data: - resource_id = resource['id'] - del resource['id'] - vals.update({'res_id': resource_id}) - log_id = log_pool.create(cr, uid, vals) - lines = [] - for field in resource.keys(): - if field in ('__last_update', 'id'):continue - ret_val = self.get_x2m_m2o_values(cr, db, uid, pool, resource_pool, method, field, resource[field], False) - line = { - 'name': field, - 'new_value': resource[field], - 'old_value': old_values[resource_id]['value'][field], - 'new_value_text': ret_val and ret_val or resource[field], - 'old_value_text': old_values[resource_id]['text'][field] - } - lines.append(line) - self.create_log_line(cr, uid, log_id, model, lines) + def inline_process_new_data(res_ids, model, dict_to_use={}): + resource_pool = pool.get(model.model) + resource_data = resource_pool.read(cr, uid, res_ids) + vals = {'method': method,'object_id': model.id,'user_id': uid_orig } + for resource in resource_data: + resource_id = resource['id'] + vals.update({'res_id': resource_id}) + log_id = log_pool.create(cr, uid, vals) + lines = [] + for field in resource.keys(): + if field in ('__last_update', 'id'):continue + field_obj = (resource_pool._all_columns.get(field)).column + if field_obj._type in ('one2many','many2many'): + x2m_rule_ids, x2m_model = self.check_rule_subscription(cr, uid, pool, field_obj._obj) + if x2m_rule_ids: + inline_process_new_data(resource[field], x2m_model, x2m_old_values) + ret_val = self.get_value_text(cr, db, uid, pool, resource_pool, method, field, resource[field], False) + line = { + 'name': field, + 'new_value': resource[field], + 'old_value': resource_id in dict_to_use and dict_to_use[resource_id]['value'].get(field), + 'new_value_text': ret_val and ret_val or resource[field], + 'old_value_text': resource_id in dict_to_use and dict_to_use[resource_id]['text'].get(field) + } + lines.append(line) + self.create_log_line(cr, uid, log_id, model, lines) + return True + inline_process_new_data(res_ids, model, old_values) cr.commit() cr.close() return res return True - + + def check_rule_subscription(self, cr, uid, pool, model, rule_check=True): + ''' + Test if the model has been subscribed to the audit rule + if yes then return the rule_ids also return the model browse_record object. + ''' + model_ids = pool.get('ir.model').search(cr, uid, [('model', '=', model)]) + model_obj = model_ids and model_ids[0] and pool.get('ir.model').browse(cr, uid, model_ids[0]) or False + if rule_check: + rule_ids = pool.get('audittrail.rule').search(cr, uid, [('object_id', '=', model_obj.id), ('state', '=', 'subscribed')]) + return rule_ids, model_obj + return model_obj + def audit_log_call(self, db, uid, model, method, action_type, *args, **argv): """ Overrides Object Proxy execute method @@ -414,8 +417,6 @@ class audittrail_objects_proxy(object_proxy): uid = 1 pool = pooler.get_pool(db) logged_uids = [] - model_pool = pool.get('ir.model') - rule_pool = pool.get('audittrail.rule') cr = pooler.get_db(db).cursor() cr.autocommit(True) if action_type == 'execute': @@ -426,14 +427,10 @@ class audittrail_objects_proxy(object_proxy): else: fct_src = super(audittrail_objects_proxy, self).exec_workflow try: - model_ids = model_pool.search(cr, uid, [('model', '=', model)]) - model_id = model_ids and model_ids[0] or False - if not ('audittrail.rule' in pool.obj_list()) or not model_id: + rule_ids, model_obj = self.check_rule_subscription(cr, uid, pool, model) + if not ('audittrail.rule' in pool.obj_list() and model_obj and rule_ids): return fct_src(db, uid_orig, model, method, *args, **argv) - rule_ids = rule_pool.search(cr, uid, [('object_id', '=', model_id), ('state', '=', 'subscribed')]) - if not rule_ids: - return fct_src(db, uid_orig, model, method, *args, **argv) - for model_rule in rule_pool.browse(cr, uid, rule_ids): + for model_rule in pool.get('audittrail.rule').browse(cr, uid, rule_ids): logged_uids += map(lambda x:x.id, model_rule.user_id) if not logged_uids or uid in logged_uids: if action_type == 'execute': From ad61a880bf166d953d38774c437ec8b69bde7b3e Mon Sep 17 00:00:00 2001 From: "ARA (OpenERP)" Date: Wed, 28 Sep 2011 17:43:31 +0530 Subject: [PATCH 013/106] [FIX] hr-expense : incmplete handling of canceld and reopened invoices lp bug: https://launchpad.net/bugs/808704 fixed bzr revid: ara@tinyerp.com-20110928121331-p3x76mmel6ity9fs --- addons/hr_expense/hr_expense.py | 5 +++++ addons/hr_expense/hr_expense_view.xml | 1 + addons/hr_expense/hr_expense_workflow.xml | 20 ++++++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/addons/hr_expense/hr_expense.py b/addons/hr_expense/hr_expense.py index 2dc6ad090ac..b671705d769 100644 --- a/addons/hr_expense/hr_expense.py +++ b/addons/hr_expense/hr_expense.py @@ -82,6 +82,7 @@ class hr_expense_expense(osv.osv): ('accepted', 'Approved'), ('invoiced', 'Invoiced'), ('paid', 'Reimbursed'), + ('invoice_except', 'Invoice Exception'), ('cancelled', 'Refused')], 'State', readonly=True, help='When the expense request is created the state is \'Draft\'.\n It is confirmed by the user and request is sent to admin, the state is \'Waiting Confirmation\'.\ \nIf the admin accepts it, the state is \'Accepted\'.\n If an invoice is made for the expense request, the state is \'Invoiced\'.\n If the expense is paid to user, the state is \'Reimbursed\'.'), @@ -224,6 +225,10 @@ class hr_expense_expense(osv.osv): res = inv_id return res + def action_invoice_cancel(self, cr, uid, ids, context=None): + self.write(cr, uid, ids, {'state': 'invoice_except'}, context=context) + return True + hr_expense_expense() class product_product(osv.osv): diff --git a/addons/hr_expense/hr_expense_view.xml b/addons/hr_expense/hr_expense_view.xml index 786dc6beee2..a832191bb90 100644 --- a/addons/hr_expense/hr_expense_view.xml +++ b/addons/hr_expense/hr_expense_view.xml @@ -106,6 +106,7 @@ - - + @@ -240,4 +219,28 @@ + + + \ No newline at end of file From f25889155b77348c92f7eb77f54ecccfa24ac677 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 21 Nov 2011 15:34:50 +0100 Subject: [PATCH 081/106] [REF] audittrail: refactoring of audittrail module. (Finished the write/actions, wkf actions) bzr revid: qdp-launchpad@openerp.com-20111121143450-yzkuk0rpomy2aync --- addons/audittrail/audittrail.py | 206 ++++++++++---------------------- 1 file changed, 65 insertions(+), 141 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 8007d348749..1baf767fcac 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -175,9 +175,9 @@ class audittrail_objects_proxy(object_proxy): def get_value_text(self, cr, uid, pool, resource_pool, method, field, value, recursive=True): """ - Gets textual values for the fields. - If the field is a many2one, it returns the name. - If it's a one2many or a many2many, it returns a list of name. + Gets textual values for the fields. + If the field is a many2one, it returns the name. + If it's a one2many or a many2many, it returns a list of name. In other cases, it just returns the value. :param cr: the current row, from the database cursor, :param uid: the current user’s ID for security checks, @@ -185,7 +185,7 @@ class audittrail_objects_proxy(object_proxy): :param resource_pool: pooler object of the model which values are being changed. :param field: for which the text value is to be returned. :param value: value of the field. - :param recursive: True or False, True will repeat the process recursively => when? + :param recursive: True or False, True will repeat the process recursively :return: string value or a list of values(for O2M/M2M) """ @@ -195,11 +195,13 @@ class audittrail_objects_proxy(object_proxy): self.log_fct(cr, uid, field_obj._obj, method, None, value, 'child_relation_log') data = pool.get(field_obj._obj).name_get(cr, uid, value) #return the modifications on x2many fields as a list of names - return map(lambda x:x[1], data) + res = map(lambda x:x[1], data) elif field_obj._type == 'many2one': #return the modifications on a many2one field as its value returned by name_get() - return value and value[1] or value - return value + res = value and value[1] or value + else: + res = value + return res def create_log_line(self, cr, uid, log_id, model, lines=[]): """ @@ -274,7 +276,7 @@ class audittrail_objects_proxy(object_proxy): self.create_log_line(cr, 1, log_id, model, lines) return True - def log_fct(self, cr, uid, model, method, fct_src, *args): + def log_fct(self, cr, uid_orig, model, method, fct_src, *args): """ Logging function: This function is performing the logging operation @param model: Object whose values are being changed @@ -283,15 +285,13 @@ class audittrail_objects_proxy(object_proxy): @return: Returns result as per method of Object proxy """ - uid_orig = uid - uid = 1 pool = pooler.get_pool(cr.dbname) resource_pool = pool.get(model) model_pool = pool.get('ir.model') model_ids = model_pool.search(cr, 1, [('model', '=', model)]) model_id = model_ids and model_ids[0] or False assert model_id, _("'%s' Model does not exist..." %(model)) - model = model_pool.browse(cr, uid, model_id) + model = model_pool.browse(cr, 1, model_id) relational_table_log = True if (args and args[-1] == 'child_relation_log') else False if method == 'create': @@ -303,61 +303,57 @@ class audittrail_objects_proxy(object_proxy): res = fct_src(cr, uid_orig, model.model, method, *args) fields_to_read = args[0].keys() if res: - resource = resource_pool.read(cr, uid, res, fields_to_read) + resource = resource_pool.read(cr, 1, res, fields_to_read) if not isinstance(resource,list): resource = [resource] map(lambda x: resource_data.setdefault(x['id'], x), resource) self.start_log_process(cr, uid_orig, model, method, resource_data, pool, resource_pool) - - elif method in('read', 'unlink'): + elif method == 'read': + old_values = {} + res = fct_src(cr, uid_orig, model.model, method, *args) + map(lambda x: old_values.setdefault(x['id'], x), res) + self.start_log_process(cr, uid_orig, model, method, old_values, pool, resource_pool) + elif method == 'unlink': res_ids = args[0] old_values = {} - if method == 'read': - res = fct_src(cr, uid_orig, model.model, method, *args) - map(lambda x: old_values.setdefault(x['id'], x), res) - else: - res = resource_pool.read(cr, uid, res_ids) - map(lambda x:old_values.setdefault(x['id'], x), res) + res = resource_pool.read(cr, 1, res_ids) + map(lambda x:old_values.setdefault(x['id'], x), res) self.start_log_process(cr, uid_orig, model, method, old_values, pool, resource_pool) - if not relational_table_log and method == 'unlink': + if not relational_table_log: res = fct_src(cr, uid_orig, model.model, method, *args) - else: #method is write or workflow action + else: #method is write, action or workflow action res_ids = [] - res = True if args: res_ids = args[0] - old_values = {} - fields = [] - if len(args) > 1 and isinstance(args[1], dict): - fields = args[1].keys() if isinstance(res_ids, (long, int)): res_ids = [res_ids] if res_ids: #store the old values into a dictionary old_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) - #process the original function or workflow trigger + #process the original function, workflow trigger... res = fct_src(cr, uid_orig, model.model, method, *args) if method == 'copy': res_ids = [res] if res_ids: - #check the new value and store them into a dictionary + #check the new values and store them into a dictionary new_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) + #compare the old and new values and create audittrail log if needed self.process_data(cr, uid_orig, pool, res_ids, model, method, old_values, new_values) return res - def get_data(self, cr, uid_orig, pool, res_ids, model, method): + def get_data(self, cr, uid, pool, res_ids, model, method): """ - This is specially created to log actions and workflow actions on an object recursively. - It processes and iterates recursively on old data (i.e before the method was executed ) - and stores it in a dict. Then this dict is used to compare with the new data - (i.e after the method execution) and log the changes. + This function simply read all the fields of the given res_ids, and also recurisvely on + all records of a x2m fields read that need to be logged. Then it returns the result in + convenient structure that will be used as comparison basis. :param cr: the current row, from the database cursor, - :param uid_orig: the current user’s ID, + :param uid: the current user’s ID. This parameter is currently not used as every + operation to get data is made as super admin. Though, it could be usefull later. :param pool: current db's pooler object. :param res_ids: Id's of resource to be logged/compared. :param model: Object whose values are being changed - :param method: method to log: create, read, unlink,write,actions,workflow actions + :param method: method to log: create, read, unlink, write, actions, workflow actions :return: dict mapping a tuple (model_id, resource_id) with its value and textual value { (model_id, resource_id): { 'value': ... 'textual_value': ... @@ -365,42 +361,46 @@ class audittrail_objects_proxy(object_proxy): } """ data = {} - # read all the fields of the given resource in super admin mode resource_pool = pool.get(model.model) + # read all the fields of the given resources in super admin mode for resource in resource_pool.read(cr, 1, res_ids): - values_text = {} values = {} + values_text = {} resource_id = resource['id'] + # loop on each field on the res_ids we just have read for field in resource: if field in ('__last_update', 'id'): continue values[field] = resource[field] - ret_val = self.get_value_text(cr, 1, pool, resource_pool, method, field, resource[field], False) - values_text[field] = ret_val and ret_val or resource[field] - data[(model.id, resource_id)] = {'text':values_text, 'value': values} + # get the textual value of that field for this record + values_text[field] = self.get_value_text(cr, 1, pool, resource_pool, method, field, resource[field], False) + field_obj = resource_pool._all_columns.get(field).column if field_obj._type in ('one2many','many2many'): - #checking if an audittrail rule apply in super admin mode + # check if an audittrail rule apply in super admin mode if self.check_rules(cr, 1, field_obj._obj, method): - #checking if the model associated to a *2m field exists, in super admin mode + # check if the model associated to a *2m field exists, in super admin mode x2m_model_ids = pool.get('ir.model').search(cr, 1, [('model', '=', field_obj._obj)]) x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj)) x2m_model = pool.get('ir.model').browse(cr, 1, x2m_model_id) + #recursive call on x2m fields that need to be checked too data.update(self.get_data(cr, 1, pool, resource[field], x2m_model, method)) + data[(model.id, resource_id)] = {'text':values_text, 'value': values} return data - def prepare_audittrail_log_line(self, cr, uid, pool, model, resource, method, old_values, new_values): + def prepare_audittrail_log_line(self, cr, uid, pool, model, resource_id, method, old_values, new_values): """ This function compares the old data (i.e before the method was executed) and the new data (after the method was executed) and returns a structure with all the needed information to log those differences. :param cr: the current row, from the database cursor, - :param uid: the current user’s ID, + :param uid: the current user’s ID. This parameter is currently not used as every + operation to get data is made as super admin. Though, it could be usefull later. :param pool: current db's pooler object. :param model: model object which values are being changed - :param resource: dictionary mapping all the fields of a given resource and its current values + :param resource_id: ID of record to which values are being changed :param method: method to log: create, read, unlink, write, actions, workflow actions :param old_values: dict of values read before execution of the method :param new_values: dict of values read after execution of the method @@ -409,21 +409,20 @@ class audittrail_objects_proxy(object_proxy): * keys: tuples build as ID of model object to log and ID of resource to log * values: list of all the changes in field values for this couple (model, resource) return { - (model.id, resource['id']): [] + (model.id, resource_id): [] } The reason why the structure returned is build as above is because when modifying an existing record (res.partner, for example), we may have to log a change done in a x2many field (on res.partner.address, for example) """ - key = (model.id, resource['id']) + key = (model.id, resource_id) lines = { key: [] } - for field in resource: - if field in ('__last_update', 'id'): - continue - field_obj = (pool.get(model.model)._all_columns.get(field)).column + # loop on all the fields + for field_name, field_definition in pool.get(model.model)._all_columns.items(): + field_obj = field_definition.column if field_obj._type in ('one2many','many2many'): # checking if an audittrail rule apply in super admin mode if self.check_rules(cr, 1, field_obj._obj, method): @@ -432,23 +431,19 @@ class audittrail_objects_proxy(object_proxy): x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj)) x2m_model = pool.get('ir.model').browse(cr, 1, x2m_model_id) - resource_ids = list(set(old_values[(model.id, resource['id'])]['value'][field] + new_values[(model.id, resource['id'])]['value'][field])) - if resource_ids: - for resource_id in resource_ids: - if (x2m_model_id, resource_id) in new_values: - x2many_values = new_values[(x2m_model_id, resource_id)] - else: - x2many_values = old_values[(x2m_model_id, resource_id)] - x2many_values['value'].update({'id': resource_id}) - lines.update(self.prepare_audittrail_log_line(cr, 1, pool, x2m_model, x2many_values['value'], method, old_values, new_values)) + # the resource_ids that need to be checked are the sum of both old and previous values (because we + # need to log also creation or deletion in those list). We use list(set(...)) to remove duplicates. + res_ids = list(set(old_values[key]['value'][field_name] + new_values[key]['value'][field_name])) + for res_id in res_ids: + lines.update(self.prepare_audittrail_log_line(cr, 1, pool, x2m_model, res_id, method, old_values, new_values)) # if the value value is different than the old value: record the change - if key not in old_values or key not in new_values or old_values[key]['value'][field] != new_values[key]['value'][field]: + if key not in old_values or key not in new_values or old_values[key]['value'][field_name] != new_values[key]['value'][field_name]: data = { - 'name': field, - 'new_value': resource[field], - 'old_value': key in old_values and old_values[key]['value'].get(field), - 'new_value_text': key in new_values and new_values[key]['text'].get(field), - 'old_value_text': key in old_values and old_values[key]['text'].get(field) + 'name': field_name, + 'new_value': key in new_values and new_values[key]['value'].get(field_name), + 'old_value': key in old_values and old_values[key]['value'].get(field_name), + 'new_value_text': key in new_values and new_values[key]['text'].get(field_name), + 'old_value_text': key in old_values and old_values[key]['text'].get(field_name) } lines[key].append(data) return lines @@ -469,10 +464,10 @@ class audittrail_objects_proxy(object_proxy): :param new_values: dict of values read after execution of the method :return: True """ - # read all the field of the given resource in super admin mode - for resource in pool.get(model.model).read(cr, 1, res_ids): + # loop on all the given ids + for res_id in res_ids: # compare old and new values and get audittrail log lines accordingly - lines = self.prepare_audittrail_log_line(cr, uid, pool, model, resource, method, old_values, new_values) + lines = self.prepare_audittrail_log_line(cr, uid, pool, model, res_id, method, old_values, new_values) # if at least one modification has been found for model_id, resource_id in lines: @@ -499,77 +494,6 @@ class audittrail_objects_proxy(object_proxy): self.create_log_line(cr, 1, log_id, model, lines[(model_id, resource_id)]) return True - def process_data_old(self, cr, uid_orig, pool, res_ids, model, method, original_values={}, type='new'): - """ - This is specially created to log actions and workflow actions on an object recursively. - It processes and iterates recursively on old data (i.e before the method was executed ) - and stores it in a dict. Then this dict is used to compare with the new data - (i.e after the method execution) and log the changes. - - :param cr: the current row, from the database cursor, - :param uid_orig: the current user’s ID, - :param pool: current db's pooler object. - :param res_ids: Id's of resource to be logged/compared. - :param model: Object whose values are being changed - :param method: method to log: create, read, unlink,write,actions,workflow actions - :param original_values: dict of values of res_ids read before execution of the method only when type is 'new' - :param type: Either of 'new' or 'old' to know which data to process. - :return: dict of values - """ - resource_pool = pool.get(model.model) - resource_data = resource_pool.read(cr, 1, res_ids) - _old_values = {} - for resource in resource_data: - _old_values_text = {} - _old_value = {} - resource_id = resource['id'] - lines = [] - for field in resource: - if field in ('__last_update', 'id'):continue - field_obj = (resource_pool._all_columns.get(field)).column - if field_obj._type in ('one2many','many2many'): - #checking if an audittrail rule apply in super admin mode - if self.check_rules(cr, 1, field_obj._obj, method): - #checking if the model associated to a *2m field exists, in super admin mode - x2m_model_ids = pool.get('ir.model').search(cr, 1, [('model', '=', field_obj._obj)]) - x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False - assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj)) - x2m_model = pool.get('ir.model').browse(cr, 1, x2m_model_id) - _old_values[field] = self.process_data(cr, 1, pool, resource[field], x2m_model, method, original_values.get(field,{}), type=type) - ret_val = self.get_value_text(cr, 1, pool, resource_pool, method, field, resource[field], False) - if type == 'new': - line = { - 'name': field, - 'new_value': resource[field], - 'old_value': resource_id in original_values and original_values[resource_id]['value'].get(field), - 'new_value_text': ret_val and ret_val or resource[field], - 'old_value_text': resource_id in original_values and original_values[resource_id]['text'].get(field) - } - if line.get('new_value_text') != line.get('old_value_text'): - lines.append(line) - else: - _old_value[field] = resource[field] - _old_values_text[field] = ret_val and ret_val or resource[field] - if type == 'new': - if lines: - vals = { - 'method': method, - 'object_id': model.id, - 'user_id': uid_orig, - 'res_id': resource_id, - } - if resource_id not in original_values and method !='copy': - # the resource was not existing so we are forcing the method to 'create' - # (because it could also come with the value 'write' if we are creating - # new record through a one2many field) - vals.update({'method': 'create'}) - # create the audittrail log in super admin mode - log_id = pool.get('audittrail.log').create(cr, 1, vals) - self.create_log_line(cr, 1, log_id, model, lines) - else: - _old_values[resource_id] = {'text':_old_values_text, 'value': _old_value} - return _old_values - def check_rules(self, cr, uid, model, method): """ Checks if auditrails is installed for that db and then if one rule match From 017f591cd42a6ae8ce337ba3feacb89d7a9930f0 Mon Sep 17 00:00:00 2001 From: Antoine Huvelle Date: Mon, 21 Nov 2011 16:50:11 +0100 Subject: [PATCH 082/106] [IMP] Taking review remarks into account bzr revid: ahu@openerp.com-20111121155011-h0oln1fdurkm941e --- .../static/src/css/web_calendar.css | 173 +++++++++--------- 1 file changed, 90 insertions(+), 83 deletions(-) diff --git a/addons/web_calendar/static/src/css/web_calendar.css b/addons/web_calendar/static/src/css/web_calendar.css index e7178f993ca..3736a62b064 100644 --- a/addons/web_calendar/static/src/css/web_calendar.css +++ b/addons/web_calendar/static/src/css/web_calendar.css @@ -10,7 +10,6 @@ .openerp .dhx_cal_container, .openerp .dhx_cal_event { background-position:0 24px; background-repeat:repeat-x; - background-color:white; font-family: Ubuntu, Helvetica, sans-serif; position:relative; overflow:hidden; @@ -229,7 +228,8 @@ position:absolute; top:44px; width:600px; - overflow-y:auto;overflow-x:hidden; + overflow-y:auto; + overflow-x:hidden; } .openerp .dhx_cal_data tr td { @@ -245,9 +245,28 @@ border-left:1px dotted #586A7E; } -.openerp .dhx_scale_holder{position:absolute;border-right:1px dotted #586A7E;background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/databg.png");} -.openerp .dhx_scale_holder_now{position:absolute;border-right:1px dotted #586A7E;background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/databg_now.png");}. -openerp .dhx_scale_hour{height:41px;width:50px;border-bottom:1px dotted #8894A3;background-color:#C2D5FC;text-align:center;line-height:40px;color:#586A7E;overflow:hidden;} +.openerp .dhx_scale_holder{ + position:absolute; + border-right:1px solid #ccc; + background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/databg.png"); +} +.openerp .dhx_scale_holder_now{ + position:absolute; + border-right:1px solid #ccc; + background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/databg_now.png"); +} + +.openerp .dhx_scale_hour{ + height:41px; + width:50px; + border-bottom:1px dotted #8894A3; + border-right:1px dotted #8894A3; + background-color:#ddd; + text-align:center; + line-height:40px; + color:#586A7E; + overflow:hidden; +} .openerp .dhx_month_head{ background-color:#F4F4F4; @@ -255,20 +274,22 @@ openerp .dhx_scale_hour{height:41px;width:50px;border-bottom:1px dotted #8894A3; text-shadow: 0 1px 0 white; font-weight:bold; text-align:center; - border-right:1px dotted #586A7E; + border-left:1px solid #E9E9E9; height:18px; - padding-right:6px; + padding-right:4px; padding-top:4px; text-align:right; font-size:0.9em; } - -.openerp .dhx_month_body{ - border-right:1px dotted #586A7E; - border-bottom:1px dotted #586A7E; - background-color:#FFF; +.openerp .dhx_mini_calendar .dhx_month_head{ + padding-right:6px; } +.openerp .dhx_cal_data table tbody tr td:nth-child(7) { + color:red; +} + + .openerp .dhx_now .openerp .dhx_month_body{ background-color:#cccccc; } @@ -285,11 +306,30 @@ openerp .dhx_scale_hour{height:41px;width:50px;border-bottom:1px dotted #8894A3; .openerp .dhx_loading{position:absolute;width:128px;height:15px;background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/loading.gif);z-index:9999;} -.openerp .dhx_multi_day_icon,.openerp .dhx_multi_day{background-color:#E1E6FF;background-repeat:no-repeat;border-right:1px dotted #8894A3;}.openerp .dhx_multi_day{position:absolute;border-top:1px dotted #8894A3;}. +.openerp .dhx_multi_day_icon, .openerp .dhx_multi_day{ + background-color:#ddd; + background-repeat:no-repeat; + /*border-right:1px dotted #8894A3;*/ +} +.openerp .dhx_multi_day{ + position:absolute; +/* border-top:1px dotted #8894A3;*/ +} -dhx_multi_day_icon{background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/clock_big.gif);}.openerp .dhx_multi_day_icon_small{background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/clock_small.gif);} +.openerp .dhx_multi_day_icon{ + background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/clock_big.gif); +} -.openerp .dhx_multi_day_icon, .openerp .dhx_multi_day_icon_small{background-position:center center;background-color:#E1E6FF;background-repeat:no-repeat;border-bottom:1px dotted #8894A3;border-right:1px dotted #8894A3;} +.openerp .dhx_multi_day_icon_small { + background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/clock_small.gif); +} + +.openerp .dhx_multi_day_icon, .openerp .dhx_multi_day_icon_small{ + background-position:center center; + background-repeat:no-repeat; + border:1px dotted #8894A3; + border-left:0px; +} .openerp .dhtmlxLayoutPolyContainer_dhx_skyblue .dhx_cal_container{background-color:none;} @@ -328,14 +368,24 @@ dhx_multi_day_icon{background-image:url(/web_calendar/static/lib/dhtmlxScheduler .openerp .dhx_cal_event .dhx_body{ border-width:0 1px 1px 1px; - padding:5px; + padding:0px 5px; -moz-border-radius-bottomleft: 3px; -webkit-border-bottom-left-radius: 3px; border-bottom-left-radius: 3px; -moz-border-radius-bottomright: 3px; -webkit-border-bottom-right-radius: 3px; border-bottom-right-radius: 3px; font-size:90%; + line-height:9px; } -.openerp .dhx_resize_denied .dhx_cal_event .dhx_footer{cursor:default;} +.openerp .dhx_resize_denied .dhx_cal_event .dhx_footer{ + cursor:default; +} -.openerp .dhx_cal_event .dhx_footer{height:1px;margin-left:2px;border-width:0 1px 1px 1px;cursor:s-resize;} +.openerp .dhx_cal_event .dhx_footer{ + height:2px; + margin-left:2px; + border-width:0 1px 1px 1px; + cursor:s-resize; + overflow:auto; + background-color:red; +} /* The old one @@ -370,9 +420,27 @@ The old one .openerp .dhx_in_move{background-color:#FFFF80;} -.openerp div .dhx_cal_editor{background-color:#FFE763;border:1px solid #B7A543;border-top-style:dotted;z-index:999;position:absolute;overflow:hidden;} +.openerp div .dhx_cal_editor{ + background-color:white; + border:1px solid #B7A543; + width:100%; + /*min-height:40px;*/ + height:100%; + z-index:999; + position:absolute; + overflow:hidden; +} -.openerp textarea .dhx_cal_editor{width:100%;height:100%;border:0 solid black;margin:none;padding:none;overflow:auto;} +.openerp textarea .dhx_cal_editor{ + background-color:white; + width:100%; +/* min-height:40px;*/ + height:100%; + border:0 solid black; + margin:none; + padding:none; + overflow:auto; +} .openerp div .dhx_menu_head{background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/controls.gif);background-position:0 -43px;width:10px;height:10px;margin-left:5px;margin-top:1px;border:none;cursor:default;} @@ -575,12 +643,6 @@ font-size:11px;line-height:24px;} .openerp .dhx_cal_light_rec .dhx_cal_light_wide{width:816px;} .openerp .dhx_cal_light_rec .dhx_cal_light_wide .dhx_cal_larea{width:808px;} -.openerp .dhx_multi_day{border:none;border-top:1px solid #A4BED4;} - -.openerp .dhx_multi_day_icon,.openerp .dhx_multi_day_icon_small{border-right:none;} - - - .openerp .dhx_cal_navline{background-color:none;height:23px!important;} @@ -588,14 +650,7 @@ font-size:11px;line-height:24px;} .openerp .dhx_scale_bar{/*background-image:url(imgs/top-separator.gif);background-position:0 0;background-repeat:no-repeat; */background-color:transparent;padding-top:3px;border-left:0;} -.openerp .dhx_scale_holder{border-right:1px solid #A4BED4;} - -.openerp .dhx_scale_holder_now{border-right:1px solid #A4BED4;} -.openerp .dhx_scale_hour{background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/left-time-bg.png);border-bottom:1px solid #A4BED4;color:#2F3A48;} - -.openerp .dhx_multi_day{background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/multi-days-bg.png);background-repeat:repeat;border-bottom:1px solid #A4BED4;border-left:0;} - -.openerp .dhx_multi_day_icon,.openerp .dhx_multi_day_icon_small{background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/multi-days-bg.png);border-bottom:1px solid #A4BED4;border-left:1px solid #fff;background-position:0 0;background-repeat:repeat;} +.openerp .dhx_multi_day{background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/multi-days-bg.png);background-repeat:repeat;} .openerp .dhx_month_head{background-color:#F4F4F4;} @@ -630,10 +685,8 @@ font-size:11px;line-height:24px;} .openerp .div .dhx_cal_editor{background-color:#FFE4AB;} -.openerp .dhx_month_head{border-right:1px solid #E9E9E9;} - .openerp .dhx_month_body{ - border-right:1px solid #E9E9E9; + border-left:1px solid #E9E9E9; border-bottom:1px solid #E9E9E9; } @@ -671,11 +724,6 @@ font-size:11px;line-height:24px;} border-left:1px dotted #7e7e7e; */ } -.openerp .dhx_scale_hour { - background-color:#bac6cf; - border-bottom:1px dotted #7e7e7e; - color: #020202; -} .openerp .dhx_cal_drag { background-color:#ff8d8d; @@ -689,16 +737,6 @@ font-size:11px;line-height:24px;} } -.openerp .dhx_scale_holder { - background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/databg.png"); - border-right:1px dotted #7e7e7e; -} - -.openerp .dhx_scale_holder_now { - background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/databg_now.png"); - border-right:1px dotted #7e7e7e; -} - .openerp .dhx_cal_event div .dhx_menu_icon { border: medium none; } @@ -840,34 +878,6 @@ div.openerp .dhx_repeat_divider { background-color:none; } - -.openerp .dhx_scale_holder { - border-right:1px solid #757575; -} - -.openerp .dhx_scale_holder_now{ - border-right:1px solid #757575; -} - -.openerp .dhx_scale_hour{ - background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/left-time-bg.png"); - border-bottom:1px solid #757575; - color: #020202; -} - -.openerp .dhx_multi_day{ - background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/multi-days-bg.png"); - border-bottom:1px solid #757575; -} - -.openerp .dhx_multi_day_icon, .openerp .dhx_multi_day_icon_small{ - background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/multi-days-bg.png"); - border-bottom:1px solid #757575; - border-left:1px solid #FFFFFF; -} - - - .openerp .dhx_in_move{ background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/move.png"); } @@ -1052,6 +1062,3 @@ div.openerp .dhx_cal_editor textarea { .openerp .dhx_cal_event .dhx_header, .openerp .dhx_cal_event .dhx_header { display:none; } -.openerp .dhx_scale_holder .dhx_cal_event .dhx_footer, .openerp .dhx_scale_holder_now .dhx_cal_event .dhx_footer { - display:none; -} From b2c3de062a638a6add58a3da74ace18470a5430c Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 21 Nov 2011 17:10:51 +0100 Subject: [PATCH 083/106] [REF] audittrail: refactoring of audittrail module. (read, unlink and create) bzr revid: qdp-launchpad@openerp.com-20111121161051-rskfs0gfkh3e73d7 --- addons/audittrail/audittrail.py | 111 ++++++++++++-------------------- 1 file changed, 40 insertions(+), 71 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 1baf767fcac..d26d43f00e5 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -173,7 +173,7 @@ class audittrail_log_line(osv.osv): class audittrail_objects_proxy(object_proxy): """ Uses Object proxy for auditing changes on object of subscribed Rules""" - def get_value_text(self, cr, uid, pool, resource_pool, method, field, value, recursive=True): + def get_value_text(self, cr, uid, pool, resource_pool, method, field, value): """ Gets textual values for the fields. If the field is a many2one, it returns the name. @@ -191,8 +191,6 @@ class audittrail_objects_proxy(object_proxy): field_obj = (resource_pool._all_columns.get(field)).column if field_obj._type in ('one2many','many2many'): - if recursive: - self.log_fct(cr, uid, field_obj._obj, method, None, value, 'child_relation_log') data = pool.get(field_obj._obj).name_get(cr, uid, value) #return the modifications on x2many fields as a list of names res = map(lambda x:x[1], data) @@ -242,40 +240,6 @@ class audittrail_objects_proxy(object_proxy): line_id = log_line_pool.create(cr, uid, vals) return True - def start_log_process(self, cr, user_id, model, method, resource_data, pool, resource_pool): - """ - Logging function: This function performs the logging operation for create/read/unlink operation - :param cr: the current row, from the database cursor, - :param user_id: the current user’s ID, - :param model: record of ir.model related to the object which values are being changed - :param method: method to log: create, read, unlink - :param resource_data: list of data modified for the model - :param pool: current db's pooler object. - :param resource_pool: pooler object of the model who's values are being changed. - :return:True - """ - #checking if an audittrail rule apply in super admin mode - if self.check_rules(cr, 1, model.model, method): - key1 = '%s_value'%(method == 'create' and 'new' or 'old') - key2 = '%s_value_text'%(method == 'create' and 'new' or 'old') - vals = {'method': method, 'object_id': model.id,'user_id': user_id} - for resource, fields in resource_data.iteritems(): - lines = [] - for field_key, value in fields.iteritems(): - if field_key in ('__last_update', 'id'):continue - ret_val = self.get_value_text(cr, 1, pool, resource_pool, method, field_key, value, method != 'read') - line = { - 'name': field_key, - key1: value, - key2: ret_val and ret_val or value - } - lines.append(line) - if lines: - vals.update({'res_id': resource}) - log_id = pool.get('audittrail.log').create(cr, 1, vals) - self.create_log_line(cr, 1, log_id, model, lines) - return True - def log_fct(self, cr, uid_orig, model, method, fct_src, *args): """ Logging function: This function is performing the logging operation @@ -292,35 +256,28 @@ class audittrail_objects_proxy(object_proxy): model_id = model_ids and model_ids[0] or False assert model_id, _("'%s' Model does not exist..." %(model)) model = model_pool.browse(cr, 1, model_id) - relational_table_log = True if (args and args[-1] == 'child_relation_log') else False + field_list = [] if method == 'create': - resource_data = {} - fields_to_read = [] - if relational_table_log: - res = args[0] - else: - res = fct_src(cr, uid_orig, model.model, method, *args) - fields_to_read = args[0].keys() - if res: - resource = resource_pool.read(cr, 1, res, fields_to_read) - if not isinstance(resource,list): - resource = [resource] - map(lambda x: resource_data.setdefault(x['id'], x), resource) - self.start_log_process(cr, uid_orig, model, method, resource_data, pool, resource_pool) - elif method == 'read': old_values = {} res = fct_src(cr, uid_orig, model.model, method, *args) - map(lambda x: old_values.setdefault(x['id'], x), res) - self.start_log_process(cr, uid_orig, model, method, old_values, pool, resource_pool) + if res: + res_ids = [res] + new_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) + elif method == 'read': + new_values = {} + old_values = {} + res = fct_src(cr, uid_orig, model.model, method, *args) + field_list = args[1] + res_ids = [] + for record in res: + res_ids.append(record['id']) + old_values[(model.id, record['id'])] = {'value': record, 'text': record} elif method == 'unlink': res_ids = args[0] - old_values = {} - res = resource_pool.read(cr, 1, res_ids) - map(lambda x:old_values.setdefault(x['id'], x), res) - self.start_log_process(cr, uid_orig, model, method, old_values, pool, resource_pool) - if not relational_table_log: - res = fct_src(cr, uid_orig, model.model, method, *args) + old_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) + res = fct_src(cr, uid_orig, model.model, method, *args) + new_values = {} else: #method is write, action or workflow action res_ids = [] if args: @@ -337,8 +294,8 @@ class audittrail_objects_proxy(object_proxy): if res_ids: #check the new values and store them into a dictionary new_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) - #compare the old and new values and create audittrail log if needed - self.process_data(cr, uid_orig, pool, res_ids, model, method, old_values, new_values) + #compare the old and new values and create audittrail log if needed + self.process_data(cr, uid_orig, pool, res_ids, model, method, old_values, new_values, field_list) return res def get_data(self, cr, uid, pool, res_ids, model, method): @@ -389,7 +346,7 @@ class audittrail_objects_proxy(object_proxy): data[(model.id, resource_id)] = {'text':values_text, 'value': values} return data - def prepare_audittrail_log_line(self, cr, uid, pool, model, resource_id, method, old_values, new_values): + def prepare_audittrail_log_line(self, cr, uid, pool, model, resource_id, method, old_values, new_values, field_list=[]): """ This function compares the old data (i.e before the method was executed) and the new data (after the method was executed) and returns a structure with all the needed information to @@ -404,8 +361,11 @@ class audittrail_objects_proxy(object_proxy): :param method: method to log: create, read, unlink, write, actions, workflow actions :param old_values: dict of values read before execution of the method :param new_values: dict of values read after execution of the method + :param field_list: optional argument containing the list of fields to log. Currently only + used when performing a read, it could be usefull later on if we want to log the write + on specific fields only. - :return: dictionary with + :return: dictionary with * keys: tuples build as ID of model object to log and ID of resource to log * values: list of all the changes in field values for this couple (model, resource) return { @@ -422,6 +382,9 @@ class audittrail_objects_proxy(object_proxy): } # loop on all the fields for field_name, field_definition in pool.get(model.model)._all_columns.items(): + #if the field_list param is given, skip all the fields not in that list + if field_list and field_name not in field_list: + continue field_obj = field_definition.column if field_obj._type in ('one2many','many2many'): # checking if an audittrail rule apply in super admin mode @@ -432,10 +395,13 @@ class audittrail_objects_proxy(object_proxy): assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj)) x2m_model = pool.get('ir.model').browse(cr, 1, x2m_model_id) # the resource_ids that need to be checked are the sum of both old and previous values (because we - # need to log also creation or deletion in those list). We use list(set(...)) to remove duplicates. - res_ids = list(set(old_values[key]['value'][field_name] + new_values[key]['value'][field_name])) + # need to log also creation or deletion in those lists). + x2m_old_values_ids = old_values.get(key, {'value': {}})['value'].get(field_name, []) + x2m_new_values_ids = new_values.get(key, {'value': {}})['value'].get(field_name, []) + # We use list(set(...)) to remove duplicates. + res_ids = list(set(x2m_old_values_ids + x2m_new_values_ids)) for res_id in res_ids: - lines.update(self.prepare_audittrail_log_line(cr, 1, pool, x2m_model, res_id, method, old_values, new_values)) + lines.update(self.prepare_audittrail_log_line(cr, 1, pool, x2m_model, res_id, method, old_values, new_values, field_list)) # if the value value is different than the old value: record the change if key not in old_values or key not in new_values or old_values[key]['value'][field_name] != new_values[key]['value'][field_name]: data = { @@ -448,7 +414,7 @@ class audittrail_objects_proxy(object_proxy): lines[key].append(data) return lines - def process_data(self, cr, uid, pool, res_ids, model, method, old_values={}, new_values={}): + def process_data(self, cr, uid, pool, res_ids, model, method, old_values={}, new_values={}, field_list=[]): """ This function processes and iterates recursively to log the difference between the old data (i.e before the method was executed) and the new data and creates audittrail log @@ -462,12 +428,15 @@ class audittrail_objects_proxy(object_proxy): :param method: method to log: create, read, unlink, write, actions, workflow actions :param old_values: dict of values read before execution of the method :param new_values: dict of values read after execution of the method + :param field_list: optional argument containing the list of fields to log. Currently only + used when performing a read, it could be usefull later on if we want to log the write + on specific fields only. :return: True """ # loop on all the given ids for res_id in res_ids: # compare old and new values and get audittrail log lines accordingly - lines = self.prepare_audittrail_log_line(cr, uid, pool, model, res_id, method, old_values, new_values) + lines = self.prepare_audittrail_log_line(cr, uid, pool, model, res_id, method, old_values, new_values, field_list) # if at least one modification has been found for model_id, resource_id in lines: @@ -477,12 +446,12 @@ class audittrail_objects_proxy(object_proxy): 'user_id': uid, 'res_id': resource_id, } - if (model_id, resource_id) not in old_values and method !='copy': + if (model_id, resource_id) not in old_values and method not in ('copy', 'read'): # the resource was not existing so we are forcing the method to 'create' # (because it could also come with the value 'write' if we are creating # new record through a one2many field) vals.update({'method': 'create'}) - if (model_id, resource_id) not in new_values and method !='copy': + if (model_id, resource_id) not in new_values and method not in ('copy', 'read'): # the resource is not existing anymore so we are forcing the method to 'unlink' # (because it could also come with the value 'write' if we are deleting the # record through a one2many field) From a8437d1e5892c2efef2724c985690d21ccbbf01c Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 21 Nov 2011 17:20:32 +0100 Subject: [PATCH 084/106] [REF] audittrail: refactoring of audittrail module. added few comments bzr revid: qdp-launchpad@openerp.com-20111121162032-st1jejch7nrrfj86 --- addons/audittrail/audittrail.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index d26d43f00e5..0b39a71fce7 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -244,7 +244,7 @@ class audittrail_objects_proxy(object_proxy): """ Logging function: This function is performing the logging operation @param model: Object whose values are being changed - @param method: method to log: create, read, write, unlink + @param method: method to log: create, read, write, unlink, action or workflow action @param fct_src: execute method of Object proxy @return: Returns result as per method of Object proxy @@ -256,45 +256,47 @@ class audittrail_objects_proxy(object_proxy): model_id = model_ids and model_ids[0] or False assert model_id, _("'%s' Model does not exist..." %(model)) model = model_pool.browse(cr, 1, model_id) + + # fields to log. currently only used by log on read() field_list = [] + old_values = new_values = {} if method == 'create': - old_values = {} res = fct_src(cr, uid_orig, model.model, method, *args) if res: res_ids = [res] new_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) elif method == 'read': - new_values = {} - old_values = {} res = fct_src(cr, uid_orig, model.model, method, *args) - field_list = args[1] + # build the res_ids and the old_values dict. Here we don't use get_data() to + # avoid performing an additional read() res_ids = [] for record in res: res_ids.append(record['id']) old_values[(model.id, record['id'])] = {'value': record, 'text': record} + # log only the fields read + field_list = args[1] elif method == 'unlink': res_ids = args[0] old_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) res = fct_src(cr, uid_orig, model.model, method, *args) - new_values = {} - else: #method is write, action or workflow action + else: # method is write, action or workflow action res_ids = [] if args: res_ids = args[0] if isinstance(res_ids, (long, int)): res_ids = [res_ids] if res_ids: - #store the old values into a dictionary + # store the old values into a dictionary old_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) - #process the original function, workflow trigger... + # process the original function, workflow trigger... res = fct_src(cr, uid_orig, model.model, method, *args) if method == 'copy': res_ids = [res] if res_ids: - #check the new values and store them into a dictionary + # check the new values and store them into a dictionary new_values = self.get_data(cr, uid_orig, pool, res_ids, model, method) - #compare the old and new values and create audittrail log if needed + # compare the old and new values and create audittrail log if needed self.process_data(cr, uid_orig, pool, res_ids, model, method, old_values, new_values, field_list) return res From 42bc324cb78ed28a682b4c3b20b06536fcdf2bfb Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 21 Nov 2011 17:27:12 +0100 Subject: [PATCH 085/106] [REF] audittrail: refactoring of audittrail module. fixed a forgotten 'extra and removed' paramater in function call + improved search view bzr revid: qdp-launchpad@openerp.com-20111121162712-wqvcc24nm5fci591 --- addons/audittrail/audittrail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index 0b39a71fce7..302d6e146bd 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -332,7 +332,7 @@ class audittrail_objects_proxy(object_proxy): continue values[field] = resource[field] # get the textual value of that field for this record - values_text[field] = self.get_value_text(cr, 1, pool, resource_pool, method, field, resource[field], False) + values_text[field] = self.get_value_text(cr, 1, pool, resource_pool, method, field, resource[field]) field_obj = resource_pool._all_columns.get(field).column if field_obj._type in ('one2many','many2many'): From 64ce2476c14244aa9218df12f39590b0ef217fe4 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 21 Nov 2011 17:33:36 +0100 Subject: [PATCH 086/106] [REF] stock, location_product wizard: context['active_id'] instead of context.get('active_id'). This syntax change is to emphasize the fact that active_id _is_ required in the context when reaching this line. So it's better to crash directly if it's not there. Courtesy from xmo bzr revid: qdp-launchpad@openerp.com-20111121163336-2pn5hcub4qs3klx1 --- addons/stock/wizard/stock_location_product.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/addons/stock/wizard/stock_location_product.py b/addons/stock/wizard/stock_location_product.py index 2ac350cb108..49dc048d0ab 100644 --- a/addons/stock/wizard/stock_location_product.py +++ b/addons/stock/wizard/stock_location_product.py @@ -43,15 +43,15 @@ class stock_location_product(osv.osv_memory): location_products = self.read(cr, uid, ids, ['from_date', 'to_date'], context=context) if location_products: return { - 'name': False, - 'view_type': 'form', - 'view_mode': 'tree,form', - 'res_model': 'product.product', - 'type': 'ir.actions.act_window', - 'context': {'location': context.get('active_id'), - 'from_date': location_products[0]['from_date'], - 'to_date': location_products[0]['to_date']}, - 'domain': [('type', '<>', 'service')], + 'name': False, + 'view_type': 'form', + 'view_mode': 'tree,form', + 'res_model': 'product.product', + 'type': 'ir.actions.act_window', + 'context': {'location': context['active_id'], + 'from_date': location_products[0]['from_date'], + 'to_date': location_products[0]['to_date']}, + 'domain': [('type', '<>', 'service')], } stock_location_product() From 89e5c72b6ea9e29b7f8a2e73b97e4cfa51e165f2 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 21 Nov 2011 17:34:12 +0100 Subject: [PATCH 087/106] [ADD] cache eviction for buffereddataset on records on which call_button has been invoked lp bug: https://launchpad.net/bugs/885679 fixed bzr revid: xmo@openerp.com-20111121163412-jyvpoa9smrk4qy2g --- addons/web/static/src/js/data.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index 69d8fd9ddfd..0d3833ee835 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -730,6 +730,19 @@ openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({ return_records(); } return completion.promise(); + }, + call_button: function (method, args, callback, error_callback) { + var id = args[0][0], index; + for(var i=0, len=this.cache.length; i Date: Mon, 21 Nov 2011 17:34:41 +0100 Subject: [PATCH 088/106] [IMP] Ensure form is saved when xmo's protocol for sidebar context is used bzr revid: fme@openerp.com-20111121163441-y200rwxk4g2jtzuj --- addons/web/static/src/js/view_form.js | 3 +-- addons/web/static/src/js/views.js | 26 ++++++++++---------------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 36e5491dad1..8a58dec13ec 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -580,8 +580,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# return true; }, sidebar_context: function () { - // TODO: ensure form is saved? - return $.Deferred().resolve(this.get_fields_values()).promise(); + return this.do_save().pipe($.proxy(this, 'get_fields_values')); } }); openerp.web.FormDialog = openerp.web.Dialog.extend({ diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index e119f2deabe..5a26ef58b03 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -679,13 +679,7 @@ session.web.Sidebar = session.web.Widget.extend({ item.callback.apply(self, [item]); } if (item.action) { - if (self.widget_parent instanceof session.web.FormView) { - self.widget_parent.do_save(function() { - self.on_item_action_clicked(item); - }); - } else { - self.on_item_action_clicked(item); - } + self.on_item_action_clicked(item); } return false; }); @@ -699,16 +693,16 @@ session.web.Sidebar = session.web.Widget.extend({ }, on_item_action_clicked: function(item) { var self = this; - var ids = self.widget_parent.get_selected_ids(); - if (ids.length == 0) { - //TODO: make prettier warning? - $("
").text(_t("You must choose at least one record.")).dialog({ - title: _t("Warning"), - modal: true - }); - return false; - } self.widget_parent.sidebar_context().then(function (context) { + var ids = self.widget_parent.get_selected_ids(); + if (ids.length == 0) { + //TODO: make prettier warning? + $("
").text(_t("You must choose at least one record.")).dialog({ + title: _t("Warning"), + modal: true + }); + return false; + } var additional_context = _.extend({ active_id: ids[0], active_ids: ids, From a50af56a050508e6aa76b20958076ddac36d59b4 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Mon, 21 Nov 2011 17:43:26 +0100 Subject: [PATCH 089/106] [FIX] orm.read_group: fix merge logic for read_group_full: - Properly merge results with list of values, even with reversed sort - Pass `read_group_order` to `_group_by_full` implementations to let them handle sorting if they want. bzr revid: odo@openerp.com-20111121164326-un722g5nsuzq94m5 --- openerp/osv/orm.py | 81 +++++++++++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 26 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 3c0a2c0133b..414f4f1fcea 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -2359,43 +2359,70 @@ class BaseModel(object): pass - def _read_group_fill_results(self, cr, uid, domain, groupby, groupby_list, aggregated_fields, read_group_result, context=None): - """Helper method for filling in read_group results for all missing values of - the field being grouped by, in case self._group_by_full provides methods - to give the list of all the values that should be displayed.""" + def _read_group_fill_results(self, cr, uid, domain, groupby, groupby_list, aggregated_fields, + read_group_result, read_group_order=None, context=None): + """Helper method for filling in empty groups for all possible values of + the field being grouped by""" + # self._group_by_full should map groupable fields to a method that returns - # a list of all aggregated values that we want to display for this field + # a list of all aggregated values that we want to display for this field, + # in the form of a m2o-like pair (key,label). # This is useful to implement kanban views for instance, where all columns # should be displayed even if they don't contain any record. - # let "groups" represent the various possible values for the group_by field + + # Grab the list of all groups that should be displayed, including all present groups present_group_ids = [x[groupby][0] for x in read_group_result if x[groupby]] - # grab the list of all groups that should be displayed, including all present groups all_groups = self._group_by_full[groupby](self, cr, uid, present_group_ids, domain, - context=context) + read_group_order=read_group_order, context=context) + result_template = dict.fromkeys(aggregated_fields, False) - result_template.update({'__context':{'group_by':groupby_list[1:]}, groupby + '_count':0}) + result_template.update({groupby + '_count':0}) + if groupby_list and len(groupby_list) > 1: + result_template.update(__context={'group_by': groupby_list[1:]}) + + # Merge the left_side (current results as dicts) with the right_side (all + # possible values as m2o pairs). Both lists are supposed to be using the + # same ordering, and can be merged in one pass. result = [] - def append_filler_line(right_side): - line = dict(result_template) - line.update({ - groupby: right_side, - '__domain': [(groupby, '=', right_side[0])] + domain, - }) - result.append(line) - #as both lists use the same ordering, we can merge in one pass + known_values = {} + def append_left(left_side): + grouped_value = left_side[groupby] and left_side[groupby][0] + if not grouped_value in known_values: + result.append(left_side) + known_values[grouped_value] = left_side + else: + count_attr = groupby + '_count' + known_values[grouped_value].update({count_attr: left_side[count_attr]}) + def append_right(right_side): + grouped_value = right_side[0] + if not grouped_value in known_values: + line = dict(result_template) + line.update({ + groupby: right_side, + '__domain': [(groupby,'=',grouped_value)] + domain, + }) + result.append(line) + known_values[grouped_value] = line while read_group_result or all_groups: left_side = read_group_result[0] if read_group_result else None right_side = all_groups[0] if all_groups else None + assert left_side is None or left_side[groupby] is False \ + or isinstance(left_side[groupby], (tuple,list)), \ + 'M2O-like pair expected, got %r' % left_side[groupby] + assert right_side is None or isinstance(right_side, (tuple,list)), \ + 'M2O-like pair expected, got %r' % right_side if left_side is None: - append_filler_line(all_groups.pop(0)) + append_right(all_groups.pop(0)) elif right_side is None: - result.append(read_group_result.pop(0)) - elif left_side[groupby][0] == right_side[0]: - result.append(read_group_result.pop(0)) - all_groups.pop(0) + append_left(read_group_result.pop(0)) + elif left_side[groupby] == right_side: + append_left(read_group_result.pop(0)) + all_groups.pop(0) # discard right_side + elif not left_side[groupby] or not left_side[groupby][0]: + # left side == "Undefined" entry, not present on right_side + append_left(read_group_result.pop(0)) else: - result.append(read_group_result.pop(0)) # should be False - append_filler_line(all_groups.pop(0)) + append_right(all_groups.pop(0)) return result def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False): @@ -2491,7 +2518,8 @@ class BaseModel(object): alldata[r['id']] = r del r['id'] - data_ids = self.search(cr, uid, [('id', 'in', alldata.keys())], order=orderby or groupby, context=context) + order = orderby or groupby + data_ids = self.search(cr, uid, [('id', 'in', alldata.keys())], order=order, context=context) # the IDS of records that have groupby field value = False or '' should be sorted too data_ids += filter(lambda x:x not in data_ids, alldata.keys()) data = self.read(cr, uid, data_ids, groupby and [groupby] or ['id'], context=context) @@ -2518,7 +2546,8 @@ class BaseModel(object): if groupby and groupby in self._group_by_full: data = self._read_group_fill_results(cr, uid, domain, groupby, groupby_list, - aggregated_fields, data, context=context) + aggregated_fields, data, read_group_order=order, + context=context) return data From 2f8f34c56b30e65f6486a96a940fb079ec99e03a Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Mon, 21 Nov 2011 17:49:40 +0100 Subject: [PATCH 090/106] [IMP] hr,crm,project: better _group_by_full imp: heed sorting bzr revid: odo@openerp.com-20111121164940-5d6d6jccex0eeaq6 --- addons/crm/crm_lead.py | 14 +++++-- addons/hr_recruitment/hr_recruitment.py | 14 +++++-- addons/project/project.py | 55 ++++++++++++++++++++----- 3 files changed, 64 insertions(+), 19 deletions(-) diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 91c8a453cd6..e72358a79a5 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -42,11 +42,17 @@ class crm_lead(crm_case, osv.osv): _order = "priority,date_action,id desc" _inherit = ['mail.thread','res.partner.address'] - def _read_group_stage_ids(self, cr, uid, ids, domain, context=None): - context = context or {} + def _read_group_stage_ids(self, cr, uid, ids, domain, read_group_order=None, context=None): stage_obj = self.pool.get('crm.case.stage') - stage_ids = stage_obj.search(cr, uid, ['|', ('id','in',ids), ('case_default','=',1)], context=context) - return stage_obj.name_get(cr, uid, stage_ids, context=context) + order = stage_obj._order + if read_group_order == 'stage_id desc': + # lame hack to allow reverting search, should just work in the trivial case + order = "%s desc" % order + stage_ids = stage_obj.search(cr, uid, ['|', ('id','in',ids),('case_default','=',1)], order=order, context=context) + result = stage_obj.name_get(cr, uid, stage_ids, context=context) + # restore order of the search + result.sort(lambda x,y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0]))) + return result _group_by_full = { 'stage_id': _read_group_stage_ids diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py index 34a91c0f3f5..d9438e9beee 100644 --- a/addons/hr_recruitment/hr_recruitment.py +++ b/addons/hr_recruitment/hr_recruitment.py @@ -197,11 +197,17 @@ class hr_applicant(crm.crm_case, osv.osv): 'color': 0, } - def _read_group_stage_ids(self, cr, uid, ids, domain, context=None): - context = context or {} + def _read_group_stage_ids(self, cr, uid, ids, domain, read_group_order=None, context=None): stage_obj = self.pool.get('hr.recruitment.stage') - stage_ids = stage_obj.search(cr, uid, ['|',('id','in',ids), ('department_id','=',False)], context=context) - return stage_obj.name_get(cr, uid, stage_ids, context=context) + order = stage_obj._order + if read_group_order == 'stage_id desc': + # lame hack to allow reverting search, should just work in the trivial case + order = "%s desc" % order + stage_ids = stage_obj.search(cr, uid, ['|',('id','in',ids),('department_id','=',False)], order=order, context=context) + result = stage_obj.name_get(cr, uid, stage_ids, context=context) + # restore order of the search + result.sort(lambda x,y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0]))) + return result _group_by_full = { 'stage_id': _read_group_stage_ids diff --git a/addons/project/project.py b/addons/project/project.py index b49e5f424ed..0b5271e0cdb 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -424,20 +424,53 @@ class task(osv.osv): _log_create = True _date_name = "date_start" - def _read_group_type_id(self, cr, uid, ids, domain, context=None): - stage_obj = self.pool.get('project.task.type') - stage_ids = stage_obj.search(cr, uid, ['|',('id','in',ids),('project_default','=',1)], context=context) - return stage_obj.name_get(cr, uid, stage_ids, context=context) - def _read_group_user_id(self, cr, uid, ids, domain, context=None): + def _resolve_project_id_from_context(self, cr, uid, context=None): + """Return ID of project based on the value of 'project_id' + context key, or None if it cannot be resolved to a single project. + """ if context is None: context = {} + if type(context.get('project_id')) in (int, long): + project_id = context['project_id'] + return project_id + if isinstance(context.get('project_id'), basestring): + project_name = context['project_id'] + project_ids = self.pool.get('project.project').name_search(cr, uid, name=project_name) + if len(project_ids) == 1: + return project_ids[0][0] + + def _read_group_type_id(self, cr, uid, ids, domain, read_group_order=None, context=None): + stage_obj = self.pool.get('project.task.type') + project_id = self._resolve_project_id_from_context(cr, uid, context=context) + order = stage_obj._order + if read_group_order == 'type_id desc': + # lame way to allow reverting search, should just work in the trivial case + order = '%s desc' % order + if project_id: + domain = ['|', ('id','in',ids), ('project_ids','in',project_id)] + else: + domain = ['|', ('id','in',ids), ('project_default','=',1)] + stage_ids = stage_obj.search(cr, uid, domain, order=order, context=context) + result = stage_obj.name_get(cr, uid, stage_ids, context=context) + # restore order of the search + result.sort(lambda x,y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0]))) + return result + + def _read_group_user_id(self, cr, uid, ids, domain, read_group_order=None, context=None): res_users = self.pool.get('res.users') - if type(context.get('project_id')) not in (int, long): - return res_users.name_get(cr, uid, ids, context=context) - proj = self.pool.get('project.project').browse(cr, uid, context['project_id'], context=context) - ids += [x.id for x in proj.members] - user_ids = res_users.search(cr, uid, [('id','in',ids)], context=context) - return res_users.name_get(cr, uid, user_ids, context=context) + project_id = self._resolve_project_id_from_context(cr, uid, context=context) + if project_id: + ids += self.pool.get('project.project').read(cr, uid, project_id, ['members'], context=context)['members'] + order = res_users._order + # lame way to allow reverting search, should just work in the trivial case + if read_group_order == 'user_id desc': + order = '%s desc' % order + # de-duplicate and apply search order + ids = res_users.search(cr, uid, [('id','in',ids)], order=order, context=context) + result = res_users.name_get(cr, uid, ids, context=context) + # restore order of the search + result.sort(lambda x,y: cmp(ids.index(x[0]), ids.index(y[0]))) + return result _group_by_full = { 'type_id': _read_group_type_id, From 6e34277ae0b77d985d9a597b8a22e96b4db5ff96 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Mon, 21 Nov 2011 17:52:47 +0100 Subject: [PATCH 091/106] [IMP] project.task: reset kanban_state whenever stage changes + tooltip bzr revid: odo@openerp.com-20111121165247-nmu30cwvxeyiyct5 --- addons/project/project.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/addons/project/project.py b/addons/project/project.py index 0b5271e0cdb..589d3ebde97 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -592,7 +592,12 @@ class task(osv.osv): 'state': fields.selection([('draft', 'New'),('open', 'In Progress'),('pending', 'Pending'), ('done', 'Done'), ('cancelled', 'Cancelled')], 'State', readonly=True, required=True, help='If the task is created the state is \'Draft\'.\n If the task is started, the state becomes \'In Progress\'.\n If review is needed the task is in \'Pending\' state.\ \n If the task is over, the states is set to \'Done\'.'), - 'kanban_state': fields.selection([('blocked', 'Blocked'),('normal', 'Normal'),('done', 'Done')], 'Kanban State', readonly=True, required=False), + 'kanban_state': fields.selection([('normal', 'Normal'),('blocked', 'Blocked'),('done', 'Ready To Pull')], 'Kanban State', + help="A task's kanban state indicates special situations affecting it:\n" + " * Normal is the default situation\n" + " * Blocked indicates something is preventing the progress of this task\n" + " * Ready To Pull indicates the task is ready to be pulled to the next stage", + readonly=True, required=False), 'create_date': fields.datetime('Create Date', readonly=True,select=True), 'date_start': fields.datetime('Starting Date',select=True), 'date_end': fields.datetime('Ending Date',select=True), @@ -967,6 +972,20 @@ class task(osv.osv): def prev_type(self, cr, uid, ids, *args): return self._change_type(cr, uid, ids, False, *args) + # Overridden to reset the kanban_state to normal whenever + # the stage (type_id) of the task changes. + def write(self, cr, uid, ids, vals, context=None): + if isinstance(ids, (int, long)): + ids = [ids] + if vals and not 'kanban_state' in vals and 'type_id' in vals: + new_stage = vals.get('type_id') + vals_reset_kstate = dict(vals, kanban_state='normal') + for t in self.browse(cr, uid, ids, context=context): + write_vals = vals_reset_kstate if t.type_id != new_stage else vals + super(task,self).write(cr, uid, [t.id], write_vals, context=context) + return True + return super(task,self).write(cr, uid, ids, vals, context=context) + def unlink(self, cr, uid, ids, context=None): if context == None: context = {} From 36d244705895e492f0d3d4ea6741d6f566bb6875 Mon Sep 17 00:00:00 2001 From: "Kunal Chavda (OpenERP)" Date: Tue, 22 Nov 2011 10:26:39 +0530 Subject: [PATCH 092/106] [FIX]Fixed code for showing stackbar chart. dhtmlxchart not support forward or backward slash in key to get value from result. lp bug: https://launchpad.net/bugs/889731 fixed bzr revid: kch@tinyerp.com-20111122045639-2y6b5el3a2bjthis --- addons/web_graph/static/src/js/graph.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/addons/web_graph/static/src/js/graph.js b/addons/web_graph/static/src/js/graph.js index f2af5503381..f940cac8b0b 100644 --- a/addons/web_graph/static/src/js/graph.js +++ b/addons/web_graph/static/src/js/graph.js @@ -187,7 +187,6 @@ openerp.web_graph.GraphView = openerp.web.View.extend({ schedule_bar: function(results) { var self = this; - var group_list, view_chart; if (!this.group_field) { view_chart = (this.orientation === 'horizontal') ? 'barH' : 'bar'; @@ -220,7 +219,7 @@ openerp.web_graph.GraphView = openerp.web.View.extend({ .map(function (value, index) { return { group: self.ordinate + '_' + - value.toLowerCase().replace(/\s/g, '_'), + value.toLowerCase().replace(/[\s\/]+/g,'_'), text: value, color: COLOR_PALETTE[index % COLOR_PALETTE.length] }; @@ -235,21 +234,19 @@ openerp.web_graph.GraphView = openerp.web.View.extend({ _(records).each(function (record) { var key = _.str.sprintf('%s_%s', self.ordinate, - record[self.group_field].toLowerCase().replace(/\s/g, '_')); + record[self.group_field].toLowerCase().replace(/[\s\/]+/g,'_')); r[key] = record[self.ordinate]; }); return r; }) .value(); } - var abscissa_description = { title: "" + this.fields[this.abscissa].string + "", template: function (obj) { return obj[self.abscissa] || 'Undefined'; } }; - var ordinate_description = { lines: true, title: "" + this.fields[this.ordinate].string + "" @@ -263,7 +260,6 @@ openerp.web_graph.GraphView = openerp.web.View.extend({ x_axis = abscissa_description; y_axis = ordinate_description; } - var renderer = function () { if (self.$element.is(':hidden')) { self.renderer = setTimeout(renderer, 100); From b0e90fcf591b44ae9fc47eb6b3daeec4ef1aad52 Mon Sep 17 00:00:00 2001 From: Launchpad Translations on behalf of openerp <> Date: Tue, 22 Nov 2011 05:00:17 +0000 Subject: [PATCH 093/106] Launchpad automatic translations update. bzr revid: launchpad_translations_on_behalf_of_openerp-20111122050017-0wnwpg2yvzk0xrln --- openerp/addons/base/i18n/ar.po | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/openerp/addons/base/i18n/ar.po b/openerp/addons/base/i18n/ar.po index e04d61effb3..42f5f757988 100644 --- a/openerp/addons/base/i18n/ar.po +++ b/openerp/addons/base/i18n/ar.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2011-01-11 11:14+0000\n" -"PO-Revision-Date: 2011-11-20 09:04+0000\n" -"Last-Translator: Ahmad Khayyat \n" +"PO-Revision-Date: 2011-11-21 12:13+0000\n" +"Last-Translator: kifcaliph \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: 2011-11-21 05:22+0000\n" +"X-Launchpad-Export-Date: 2011-11-22 05:00+0000\n" "X-Generator: Launchpad (build 14299)\n" #. module: base @@ -307,7 +307,7 @@ msgstr "خطوات إعداد المعالج" #. module: base #: model:ir.model,name:base.model_ir_ui_view_sc msgid "ir.ui.view_sc" -msgstr "" +msgstr "ir.ui.view_sc" #. module: base #: field:res.widget.user,widget_id:0 @@ -338,7 +338,7 @@ msgstr "اختر نوع الإجراء" #. module: base #: model:res.country,name:base.tv msgid "Tuvalu" -msgstr "" +msgstr "توفالو" #. module: base #: selection:ir.model,state:0 @@ -482,7 +482,7 @@ msgstr "مورّدون متنوعون" #: code:addons/base/ir/ir_model.py:255 #, python-format msgid "Custom fields must have a name that starts with 'x_' !" -msgstr "" +msgstr "الحقول الخاصة يجب أن تيدأ باسم يبدأ بـ 'x_' !" #. module: base #: help:ir.actions.server,action_id:0 @@ -720,7 +720,7 @@ msgstr "أيام العمل" #. module: base #: selection:ir.module.module,license:0 msgid "Other OSI Approved Licence" -msgstr "رخص أخرى تعترف بها \"مبادرة المصدر المفتوح\" (OSI)" +msgstr "رخص أخرى تعترف بها الـ (OSI)" #. module: base #: help:res.config.users,context_lang:0 @@ -777,7 +777,7 @@ msgstr "ir.config_parameter" #. module: base #: selection:base.language.export,format:0 msgid "TGZ Archive" -msgstr "" +msgstr "ملف TGZ" #. module: base #: view:res.lang:0 From 0e8b9138423513343f0eae5a3b5c35f60c664569 Mon Sep 17 00:00:00 2001 From: Launchpad Translations on behalf of openerp <> Date: Tue, 22 Nov 2011 05:13:16 +0000 Subject: [PATCH 094/106] Launchpad automatic translations update. bzr revid: launchpad_translations_on_behalf_of_openerp-20111122050046-eb2hd81qu2801nxi bzr revid: launchpad_translations_on_behalf_of_openerp-20111122051316-eovfu9qj7puxspbf --- addons/account_accountant/i18n/bn.po | 36 + addons/account_cancel/i18n/bn.po | 36 + addons/base_calendar/i18n/bn.po | 1658 ++++++++++++++++++++++++++ addons/hr/i18n/bn.po | 829 +++++++++++++ addons/web/po/pt.po | 688 +++++++++++ addons/web_calendar/po/pt.po | 22 + addons/web_mobile/po/pt.po | 66 + 7 files changed, 3335 insertions(+) create mode 100644 addons/account_accountant/i18n/bn.po create mode 100644 addons/account_cancel/i18n/bn.po create mode 100644 addons/base_calendar/i18n/bn.po create mode 100644 addons/hr/i18n/bn.po create mode 100644 addons/web/po/pt.po create mode 100644 addons/web_calendar/po/pt.po create mode 100644 addons/web_mobile/po/pt.po diff --git a/addons/account_accountant/i18n/bn.po b/addons/account_accountant/i18n/bn.po new file mode 100644 index 00000000000..9b62c14de4e --- /dev/null +++ b/addons/account_accountant/i18n/bn.po @@ -0,0 +1,36 @@ +# Bengali translation for openobject-addons +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openobject-addons package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openobject-addons\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-01-11 11:14+0000\n" +"PO-Revision-Date: 2011-11-21 12:33+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Bengali \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2011-11-22 05:00+0000\n" +"X-Generator: Launchpad (build 14299)\n" + +#. module: account_accountant +#: model:ir.module.module,description:account_accountant.module_meta_information +msgid "" +"\n" +"This module gives the admin user the access to all the accounting features " +"like the journal\n" +"items and the chart of accounts.\n" +" " +msgstr "" +"\n" +"এই মডিউল admin ব্যবহারকারীকে সকল হিসাবরক্ষন এর সুবিধা দিবে\n" +" " + +#. module: account_accountant +#: model:ir.module.module,shortdesc:account_accountant.module_meta_information +msgid "Accountant" +msgstr "হিসাবরক্ষনকারী" diff --git a/addons/account_cancel/i18n/bn.po b/addons/account_cancel/i18n/bn.po new file mode 100644 index 00000000000..3ba41e3969f --- /dev/null +++ b/addons/account_cancel/i18n/bn.po @@ -0,0 +1,36 @@ +# Bengali translation for openobject-addons +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openobject-addons package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openobject-addons\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-01-11 11:14+0000\n" +"PO-Revision-Date: 2011-11-21 12:37+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Bengali \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2011-11-22 05:00+0000\n" +"X-Generator: Launchpad (build 14299)\n" + +#. module: account_cancel +#: model:ir.module.module,description:account_cancel.module_meta_information +msgid "" +"\n" +" Module adds 'Allow cancelling entries' field on form view of account " +"journal. If set to true it allows user to cancel entries & invoices.\n" +" " +msgstr "" +"\n" +" মডিউলটি 'Allow cancelling entries' ফিল্ড যুক্ত করবে যা দিয়ে জাবেদা " +"অন্তর্ভুক্তি বাতিল করা যাবে।\n" +" " + +#. module: account_cancel +#: model:ir.module.module,shortdesc:account_cancel.module_meta_information +msgid "Account Cancel" +msgstr "হিসাব বাতিল" diff --git a/addons/base_calendar/i18n/bn.po b/addons/base_calendar/i18n/bn.po new file mode 100644 index 00000000000..e0d0b9c7cca --- /dev/null +++ b/addons/base_calendar/i18n/bn.po @@ -0,0 +1,1658 @@ +# Bengali translation for openobject-addons +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openobject-addons package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openobject-addons\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-01-11 11:14+0000\n" +"PO-Revision-Date: 2011-11-21 12:57+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Bengali \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2011-11-22 05:00+0000\n" +"X-Generator: Launchpad (build 14299)\n" + +#. module: base_calendar +#: selection:calendar.alarm,trigger_related:0 +#: selection:res.alarm,trigger_related:0 +msgid "The event starts" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,freq:0 +msgid "Hourly" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +msgid "Required to Join" +msgstr "" + +#. module: base_calendar +#: help:calendar.event,exdate:0 +#: help:calendar.todo,exdate:0 +msgid "" +"This property defines the list of date/time exceptions for a recurring " +"calendar component." +msgstr "" + +#. module: base_calendar +#: constraint:res.users:0 +msgid "The chosen company is not in the allowed companies for this user" +msgstr "" + +#. module: base_calendar +#: field:calendar.event.edit.all,name:0 +msgid "Title" +msgstr "শিরোনাম" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,freq:0 +#: selection:calendar.event,rrule_type:0 +#: selection:calendar.todo,rrule_type:0 +msgid "Monthly" +msgstr "মাসভিত্তিক" + +#. module: base_calendar +#: view:calendar.attendee:0 +msgid "Invited User" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +msgid "Invitation" +msgstr "" + +#. module: base_calendar +#: help:calendar.event,recurrency:0 +#: help:calendar.todo,recurrency:0 +msgid "Recurrent Meeting" +msgstr "" + +#. module: base_calendar +#: model:ir.actions.act_window,name:base_calendar.action_res_alarm_view +#: model:ir.ui.menu,name:base_calendar.menu_crm_meeting_avail_alarm +msgid "Alarms" +msgstr "অ্যালার্ম" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,week_list:0 +#: selection:calendar.event,week_list:0 +#: selection:calendar.todo,week_list:0 +msgid "Sunday" +msgstr "রবিবার" + +#. module: base_calendar +#: view:calendar.attendee:0 +#: field:calendar.attendee,role:0 +msgid "Role" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +#: view:calendar.event:0 +msgid "Invitation details" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,byday:0 +#: selection:calendar.event,byday:0 +#: selection:calendar.todo,byday:0 +msgid "Fourth" +msgstr "" + +#. module: base_calendar +#: field:calendar.event,show_as:0 +#: field:calendar.todo,show_as:0 +msgid "Show as" +msgstr "" + +#. module: base_calendar +#: field:base.calendar.set.exrule,day:0 +#: selection:base.calendar.set.exrule,select1:0 +#: field:calendar.event,day:0 +#: selection:calendar.event,select1:0 +#: field:calendar.todo,day:0 +#: selection:calendar.todo,select1:0 +msgid "Date of month" +msgstr "" + +#. module: base_calendar +#: selection:calendar.event,class:0 +#: selection:calendar.todo,class:0 +msgid "Public" +msgstr "পাবলিক" + +#. module: base_calendar +#: view:calendar.event:0 +msgid " " +msgstr " " + +#. module: base_calendar +#: selection:base.calendar.set.exrule,month_list:0 +#: selection:calendar.event,month_list:0 +#: selection:calendar.todo,month_list:0 +msgid "March" +msgstr "মার্চ" + +#. module: base_calendar +#: code:addons/base_calendar/base_calendar.py:414 +#: code:addons/base_calendar/wizard/base_calendar_set_exrule.py:90 +#, python-format +msgid "Warning !" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,week_list:0 +#: selection:calendar.event,week_list:0 +#: selection:calendar.todo,week_list:0 +msgid "Friday" +msgstr "শুক্রবার" + +#. module: base_calendar +#: field:calendar.event,allday:0 +#: field:calendar.todo,allday:0 +msgid "All Day" +msgstr "সারাদিন" + +#. module: base_calendar +#: field:base.calendar.set.exrule,select1:0 +#: field:calendar.event,select1:0 +#: field:calendar.todo,select1:0 +msgid "Option" +msgstr "বিকল্প" + +#. module: base_calendar +#: selection:calendar.attendee,availability:0 +#: selection:calendar.event,show_as:0 +#: selection:calendar.todo,show_as:0 +#: selection:res.users,availability:0 +msgid "Free" +msgstr "ফ্রী" + +#. module: base_calendar +#: help:calendar.attendee,rsvp:0 +msgid "Indicats whether the favor of a reply is requested" +msgstr "" + +#. module: base_calendar +#: model:ir.model,name:base_calendar.model_ir_attachment +msgid "ir.attachment" +msgstr "" + +#. module: base_calendar +#: help:calendar.attendee,delegated_to:0 +msgid "The users that the original request was delegated to" +msgstr "" + +#. module: base_calendar +#: field:calendar.attendee,ref:0 +msgid "Event Ref" +msgstr "" + +#. module: base_calendar +#: field:base.calendar.set.exrule,we:0 +#: field:calendar.event,we:0 +#: field:calendar.todo,we:0 +msgid "Wed" +msgstr "বুধ" + +#. module: base_calendar +#: view:calendar.event:0 +msgid "Show time as" +msgstr "" + +#. module: base_calendar +#: field:base.calendar.set.exrule,tu:0 +#: field:calendar.event,tu:0 +#: field:calendar.todo,tu:0 +msgid "Tue" +msgstr "মঙ্গল" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,freq:0 +#: selection:calendar.event,rrule_type:0 +#: selection:calendar.todo,rrule_type:0 +msgid "Yearly" +msgstr "বাৎসরিক" + +#. module: base_calendar +#: selection:calendar.alarm,trigger_related:0 +#: selection:res.alarm,trigger_related:0 +msgid "The event ends" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,byday:0 +#: selection:calendar.event,byday:0 +#: selection:calendar.todo,byday:0 +msgid "Last" +msgstr "শেষ" + +#. module: base_calendar +#: help:calendar.attendee,state:0 +msgid "Status of the attendee's participation" +msgstr "" + +#. module: base_calendar +#: selection:calendar.attendee,cutype:0 +msgid "Room" +msgstr "রুম" + +#. module: base_calendar +#: selection:calendar.alarm,trigger_interval:0 +#: selection:calendar.event,freq:0 +#: selection:calendar.todo,freq:0 +#: selection:res.alarm,trigger_interval:0 +msgid "Days" +msgstr "দিন" + +#. module: base_calendar +#: view:calendar.attendee:0 +#: view:calendar.event:0 +msgid "Invitation Detail" +msgstr "" + +#. module: base_calendar +#: code:addons/base_calendar/base_calendar.py:1355 +#: code:addons/base_calendar/wizard/base_calendar_invite_attendee.py:96 +#: code:addons/base_calendar/wizard/base_calendar_invite_attendee.py:143 +#: code:addons/base_calendar/wizard/base_calendar_set_exrule.py:128 +#: code:addons/base_calendar/wizard/base_calendar_set_exrule.py:136 +#, python-format +msgid "Error!" +msgstr "ভুল" + +#. module: base_calendar +#: selection:calendar.attendee,role:0 +msgid "Chair Person" +msgstr "" + +#. module: base_calendar +#: selection:calendar.alarm,action:0 +msgid "Procedure" +msgstr "" + +#. module: base_calendar +#: selection:calendar.event,state:0 +#: selection:calendar.todo,state:0 +msgid "Cancelled" +msgstr "বাতিল করা হয়েছে" + +#. module: base_calendar +#: selection:calendar.alarm,trigger_interval:0 +#: selection:res.alarm,trigger_interval:0 +msgid "Minutes" +msgstr "মিনিট" + +#. module: base_calendar +#: selection:calendar.alarm,action:0 +msgid "Display" +msgstr "প্রদর্শন" + +#. module: base_calendar +#: view:calendar.event.edit.all:0 +msgid "Edit all Occurrences" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +msgid "Invitation type" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,freq:0 +msgid "Secondly" +msgstr "" + +#. module: base_calendar +#: field:calendar.alarm,event_date:0 +#: field:calendar.attendee,event_date:0 +#: view:calendar.event:0 +msgid "Event Date" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +#: view:calendar.event:0 +msgid "Group By..." +msgstr "...দিয়ে গ্রুপ করুন" + +#. module: base_calendar +#: help:base_calendar.invite.attendee,email:0 +msgid "Provide external email address who will receive this invitation." +msgstr "" + +#. module: base_calendar +#: model:ir.module.module,description:base_calendar.module_meta_information +msgid "" +"Full featured calendar system that supports:\n" +" - Calendar of events\n" +" - Alerts (create requests)\n" +" - Recurring events\n" +" - Invitations to people" +msgstr "" + +#. module: base_calendar +#: help:calendar.attendee,cutype:0 +msgid "Specify the type of Invitation" +msgstr "" + +#. module: base_calendar +#: selection:calendar.event,freq:0 +#: selection:calendar.todo,freq:0 +msgid "Years" +msgstr "বছর" + +#. module: base_calendar +#: field:calendar.alarm,event_end_date:0 +#: field:calendar.attendee,event_end_date:0 +msgid "Event End Date" +msgstr "" + +#. module: base_calendar +#: selection:calendar.attendee,role:0 +msgid "Optional Participation" +msgstr "" + +#. module: base_calendar +#: field:calendar.event,date_deadline:0 +#: field:calendar.todo,date_deadline:0 +msgid "Deadline" +msgstr "ডেডলাইন" + +#. module: base_calendar +#: code:addons/base_calendar/base_calendar.py:385 +#: code:addons/base_calendar/base_calendar.py:1088 +#: code:addons/base_calendar/base_calendar.py:1090 +#, python-format +msgid "Warning!" +msgstr "" + +#. module: base_calendar +#: help:calendar.event,active:0 +#: help:calendar.todo,active:0 +msgid "" +"If the active field is set to true, it will allow you to hide the " +"event alarm information without removing it." +msgstr "" + +#. module: base_calendar +#: model:ir.module.module,shortdesc:base_calendar.module_meta_information +msgid "Basic Calendar Functionality" +msgstr "" + +#. module: base_calendar +#: field:calendar.event,organizer:0 +#: field:calendar.event,organizer_id:0 +#: field:calendar.todo,organizer:0 +#: field:calendar.todo,organizer_id:0 +msgid "Organizer" +msgstr "আয়োজক" + +#. module: base_calendar +#: view:calendar.attendee:0 +#: view:calendar.event:0 +#: field:calendar.event,user_id:0 +#: field:calendar.todo,user_id:0 +msgid "Responsible" +msgstr "দায়িত্বপ্রাপ্ত" + +#. module: base_calendar +#: view:calendar.event:0 +#: model:res.request.link,name:base_calendar.request_link_meeting +msgid "Event" +msgstr "ইভেন্ট" + +#. module: base_calendar +#: help:calendar.event,edit_all:0 +#: help:calendar.todo,edit_all:0 +msgid "Edit all Occurrences of recurrent Meeting." +msgstr "" + +#. module: base_calendar +#: selection:calendar.alarm,trigger_occurs:0 +#: selection:res.alarm,trigger_occurs:0 +msgid "Before" +msgstr "আগে" + +#. module: base_calendar +#: view:calendar.event:0 +#: selection:calendar.event,state:0 +#: selection:calendar.todo,state:0 +msgid "Confirmed" +msgstr "নিশ্চিত" + +#. module: base_calendar +#: model:ir.actions.act_window,name:base_calendar.action_calendar_event_edit_all +msgid "Edit all events" +msgstr "" + +#. module: base_calendar +#: field:calendar.alarm,attendee_ids:0 +#: field:calendar.event,attendee_ids:0 +#: field:calendar.todo,attendee_ids:0 +msgid "Attendees" +msgstr "" + +#. module: base_calendar +#: view:calendar.event:0 +msgid "Confirm" +msgstr "নিশ্চিত" + +#. module: base_calendar +#: model:ir.model,name:base_calendar.model_calendar_todo +msgid "Calendar Task" +msgstr "" + +#. module: base_calendar +#: field:base.calendar.set.exrule,su:0 +#: field:calendar.event,su:0 +#: field:calendar.todo,su:0 +msgid "Sun" +msgstr "রবি" + +#. module: base_calendar +#: field:calendar.attendee,cutype:0 +msgid "Invite Type" +msgstr "" + +#. module: base_calendar +#: help:calendar.attendee,partner_id:0 +msgid "Partner related to contact" +msgstr "" + +#. module: base_calendar +#: view:res.alarm:0 +msgid "Reminder details" +msgstr "" + +#. module: base_calendar +#: field:calendar.attendee,parent_ids:0 +msgid "Delegrated From" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,select1:0 +#: selection:calendar.event,select1:0 +#: selection:calendar.todo,select1:0 +msgid "Day of month" +msgstr "" + +#. module: base_calendar +#: view:calendar.event:0 +#: field:calendar.event,location:0 +#: field:calendar.event.edit.all,location:0 +#: field:calendar.todo,location:0 +msgid "Location" +msgstr "স্থান" + +#. module: base_calendar +#: field:base_calendar.invite.attendee,send_mail:0 +msgid "Send mail?" +msgstr "" + +#. module: base_calendar +#: field:base_calendar.invite.attendee,email:0 +#: selection:calendar.alarm,action:0 +#: field:calendar.attendee,email:0 +msgid "Email" +msgstr "ই-মেইল" + +#. module: base_calendar +#: view:calendar.attendee:0 +msgid "Event Detail" +msgstr "" + +#. module: base_calendar +#: selection:calendar.alarm,state:0 +msgid "Run" +msgstr "চালাও" + +#. module: base_calendar +#: field:calendar.event,exdate:0 +#: field:calendar.todo,exdate:0 +msgid "Exception Date/Times" +msgstr "" + +#. module: base_calendar +#: selection:calendar.event,class:0 +#: selection:calendar.todo,class:0 +msgid "Confidential" +msgstr "গুপ্ত" + +#. module: base_calendar +#: field:base.calendar.set.exrule,end_date:0 +#: field:calendar.event,end_date:0 +#: field:calendar.todo,end_date:0 +msgid "Repeat Until" +msgstr "" + +#. module: base_calendar +#: model:ir.actions.act_window,help:base_calendar.action_res_alarm_view +msgid "" +"Create specific calendar alarms that may be assigned to calendar events or " +"meetings." +msgstr "" + +#. module: base_calendar +#: view:calendar.event:0 +msgid "Visibility" +msgstr "দৃশ্যমানতা" + +#. module: base_calendar +#: field:calendar.attendee,rsvp:0 +msgid "Required Reply?" +msgstr "" + +#. module: base_calendar +#: field:calendar.event,base_calendar_url:0 +#: field:calendar.todo,base_calendar_url:0 +msgid "Caldav URL" +msgstr "" + +#. module: base_calendar +#: view:base.calendar.set.exrule:0 +msgid "Select range to Exclude" +msgstr "" + +#. module: base_calendar +#: field:calendar.event,recurrent_uid:0 +#: field:calendar.todo,recurrent_uid:0 +msgid "Recurrent ID" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,month_list:0 +#: selection:calendar.event,month_list:0 +#: selection:calendar.todo,month_list:0 +msgid "July" +msgstr "জুলাই" + +#. module: base_calendar +#: view:calendar.attendee:0 +#: selection:calendar.attendee,state:0 +msgid "Accepted" +msgstr "গৃহীত" + +#. module: base_calendar +#: field:base.calendar.set.exrule,th:0 +#: field:calendar.event,th:0 +#: field:calendar.todo,th:0 +msgid "Thu" +msgstr "বৃহঃ" + +#. module: base_calendar +#: field:calendar.attendee,child_ids:0 +msgid "Delegrated To" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +msgid "Required Reply" +msgstr "উত্তর প্রয়োজন" + +#. module: base_calendar +#: selection:calendar.event,end_type:0 +#: selection:calendar.todo,end_type:0 +msgid "Forever" +msgstr "চিরকাল" + +#. module: base_calendar +#: selection:calendar.attendee,role:0 +msgid "Participation required" +msgstr "অংশগ্রহণ প্রয়োজন" + +#. module: base_calendar +#: view:base.calendar.set.exrule:0 +msgid "_Cancel" +msgstr "বাতিল (_C)" + +#. module: base_calendar +#: field:calendar.event,create_date:0 +#: field:calendar.todo,create_date:0 +msgid "Created" +msgstr "তৈরী হয়েছে" + +#. module: base_calendar +#: selection:calendar.event,class:0 +#: selection:calendar.todo,class:0 +msgid "Private" +msgstr "ব্যক্তিগত" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,freq:0 +#: selection:calendar.event,rrule_type:0 +#: selection:calendar.todo,rrule_type:0 +msgid "Daily" +msgstr "দৈনিক" + +#. module: base_calendar +#: code:addons/base_calendar/base_calendar.py:385 +#, python-format +msgid "Can not Duplicate" +msgstr "" + +#. module: base_calendar +#: field:calendar.event,class:0 +#: field:calendar.todo,class:0 +msgid "Mark as" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +#: field:calendar.attendee,partner_address_id:0 +msgid "Contact" +msgstr "যোগাযোগ" + +#. module: base_calendar +#: help:calendar.event,rrule_type:0 +#: help:calendar.todo,rrule_type:0 +msgid "Let the event automatically repeat at that interval" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +#: view:calendar.event:0 +msgid "Delegate" +msgstr "" + +#. module: base_calendar +#: field:base_calendar.invite.attendee,partner_id:0 +#: view:calendar.attendee:0 +#: field:calendar.attendee,partner_id:0 +msgid "Partner" +msgstr "" + +#. module: base_calendar +#: view:base_calendar.invite.attendee:0 +#: selection:base_calendar.invite.attendee,type:0 +msgid "Partner Contacts" +msgstr "" + +#. module: base_calendar +#: view:base.calendar.set.exrule:0 +msgid "_Ok" +msgstr "ঠিক আছে(_O)" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,byday:0 +#: selection:calendar.event,byday:0 +#: selection:calendar.todo,byday:0 +msgid "First" +msgstr "প্রথম" + +#. module: base_calendar +#: view:calendar.event:0 +msgid "Privacy" +msgstr "প্রাইভেসি" + +#. module: base_calendar +#: field:calendar.event,vtimezone:0 +#: field:calendar.todo,vtimezone:0 +msgid "Timezone" +msgstr "টাইমজোন" + +#. module: base_calendar +#: view:calendar.event:0 +msgid "Subject" +msgstr "বিষয়" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,month_list:0 +#: selection:calendar.event,month_list:0 +#: selection:calendar.todo,month_list:0 +msgid "September" +msgstr "সেপ্টেম্বর" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,month_list:0 +#: selection:calendar.event,month_list:0 +#: selection:calendar.todo,month_list:0 +msgid "December" +msgstr "" + +#. module: base_calendar +#: help:base_calendar.invite.attendee,send_mail:0 +msgid "Check this if you want to send an Email to Invited Person" +msgstr "" + +#. module: base_calendar +#: view:calendar.event:0 +msgid "Availability" +msgstr "" + +#. module: base_calendar +#: view:calendar.event.edit.all:0 +msgid "_Save" +msgstr "সংরক্ষণ (_S)" + +#. module: base_calendar +#: selection:calendar.attendee,cutype:0 +msgid "Individual" +msgstr "" + +#. module: base_calendar +#: help:calendar.event,count:0 +#: help:calendar.todo,count:0 +msgid "Repeat x times" +msgstr "" + +#. module: base_calendar +#: field:calendar.alarm,user_id:0 +msgid "Owner" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +msgid "Delegation Info" +msgstr "" + +#. module: base_calendar +#: view:calendar.event:0 +#: field:calendar.event.edit.all,date:0 +msgid "Start Date" +msgstr "" + +#. module: base_calendar +#: field:calendar.attendee,cn:0 +msgid "Common name" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +#: selection:calendar.attendee,state:0 +msgid "Declined" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +msgid "My Role" +msgstr "" + +#. module: base_calendar +#: view:calendar.event:0 +msgid "My Events" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +#: view:calendar.event:0 +msgid "Decline" +msgstr "" + +#. module: base_calendar +#: selection:calendar.event,freq:0 +#: selection:calendar.todo,freq:0 +msgid "Weeks" +msgstr "" + +#. module: base_calendar +#: selection:calendar.attendee,cutype:0 +msgid "Group" +msgstr "" + +#. module: base_calendar +#: field:calendar.event,edit_all:0 +#: field:calendar.todo,edit_all:0 +msgid "Edit All" +msgstr "" + +#. module: base_calendar +#: field:base_calendar.invite.attendee,contact_ids:0 +msgid "Contacts" +msgstr "" + +#. module: base_calendar +#: model:ir.model,name:base_calendar.model_res_alarm +msgid "Basic Alarm Information" +msgstr "" + +#. module: base_calendar +#: field:base.calendar.set.exrule,fr:0 +#: field:calendar.event,fr:0 +#: field:calendar.todo,fr:0 +msgid "Fri" +msgstr "" + +#. module: base_calendar +#: selection:calendar.alarm,trigger_interval:0 +#: selection:calendar.event,freq:0 +#: selection:calendar.todo,freq:0 +#: selection:res.alarm,trigger_interval:0 +msgid "Hours" +msgstr "" + +#. module: base_calendar +#: code:addons/base_calendar/base_calendar.py:1090 +#, python-format +msgid "Count can not be Negative" +msgstr "" + +#. module: base_calendar +#: field:calendar.attendee,member:0 +msgid "Member" +msgstr "" + +#. module: base_calendar +#: help:calendar.event,location:0 +#: help:calendar.todo,location:0 +msgid "Location of Event" +msgstr "" + +#. module: base_calendar +#: field:calendar.event,rrule:0 +#: field:calendar.todo,rrule:0 +msgid "Recurrent Rule" +msgstr "" + +#. module: base_calendar +#: selection:calendar.alarm,state:0 +msgid "Draft" +msgstr "" + +#. module: base_calendar +#: field:calendar.alarm,attach:0 +msgid "Attachment" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +msgid "Invitation From" +msgstr "" + +#. module: base_calendar +#: view:calendar.event:0 +msgid "End of recurrency" +msgstr "" + +#. module: base_calendar +#: view:calendar.event:0 +#: field:calendar.event.edit.all,alarm_id:0 +msgid "Reminder" +msgstr "" + +#. module: base_calendar +#: view:base.calendar.set.exrule:0 +#: model:ir.model,name:base_calendar.model_base_calendar_set_exrule +msgid "Set Exrule" +msgstr "" + +#. module: base_calendar +#: view:calendar.event:0 +#: model:ir.actions.act_window,name:base_calendar.action_view_event +#: model:ir.ui.menu,name:base_calendar.menu_events +msgid "Events" +msgstr "" + +#. module: base_calendar +#: model:ir.actions.act_window,name:base_calendar.action_view_calendar_invite_attendee_wizard +#: model:ir.model,name:base_calendar.model_base_calendar_invite_attendee +msgid "Invite Attendees" +msgstr "" + +#. module: base_calendar +#: help:calendar.attendee,email:0 +msgid "Email of Invited Person" +msgstr "" + +#. module: base_calendar +#: field:calendar.alarm,repeat:0 +#: field:calendar.event,count:0 +#: field:calendar.todo,count:0 +#: field:res.alarm,repeat:0 +msgid "Repeat" +msgstr "" + +#. module: base_calendar +#: help:calendar.attendee,dir:0 +msgid "" +"Reference to the URIthat points to the directory information corresponding " +"to the attendee." +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,month_list:0 +#: selection:calendar.event,month_list:0 +#: selection:calendar.todo,month_list:0 +msgid "August" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,week_list:0 +#: selection:calendar.event,week_list:0 +#: selection:calendar.todo,week_list:0 +msgid "Monday" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,byday:0 +#: selection:calendar.event,byday:0 +#: selection:calendar.todo,byday:0 +msgid "Third" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,month_list:0 +#: selection:calendar.event,month_list:0 +#: selection:calendar.todo,month_list:0 +msgid "June" +msgstr "" + +#. module: base_calendar +#: field:calendar.alarm,alarm_id:0 +msgid "Basic Alarm" +msgstr "" + +#. module: base_calendar +#: view:base.calendar.set.exrule:0 +#: view:calendar.event:0 +msgid "The" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +#: field:calendar.attendee,delegated_from:0 +msgid "Delegated From" +msgstr "" + +#. module: base_calendar +#: field:calendar.attendee,user_id:0 +msgid "User" +msgstr "" + +#. module: base_calendar +#: view:calendar.event:0 +#: field:calendar.event,date:0 +msgid "Date" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,month_list:0 +#: selection:calendar.event,month_list:0 +#: selection:calendar.todo,month_list:0 +msgid "November" +msgstr "" + +#. module: base_calendar +#: help:calendar.attendee,member:0 +msgid "Indicate the groups that the attendee belongs to" +msgstr "" + +#. module: base_calendar +#: view:base_calendar.invite.attendee:0 +msgid "Data" +msgstr "" + +#. module: base_calendar +#: field:base.calendar.set.exrule,mo:0 +#: field:calendar.event,mo:0 +#: field:calendar.todo,mo:0 +msgid "Mon" +msgstr "" + +#. module: base_calendar +#: field:base.calendar.set.exrule,count:0 +msgid "Count" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,freq:0 +#: selection:calendar.event,freq:0 +#: selection:calendar.todo,freq:0 +msgid "No Repeat" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,month_list:0 +#: selection:calendar.event,month_list:0 +#: selection:calendar.todo,month_list:0 +msgid "October" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +#: view:calendar.event:0 +msgid "Uncertain" +msgstr "" + +#. module: base_calendar +#: field:calendar.attendee,language:0 +msgid "Language" +msgstr "" + +#. module: base_calendar +#: field:calendar.alarm,trigger_occurs:0 +#: field:res.alarm,trigger_occurs:0 +msgid "Triggers" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,month_list:0 +#: selection:calendar.event,month_list:0 +#: selection:calendar.todo,month_list:0 +msgid "January" +msgstr "" + +#. module: base_calendar +#: field:calendar.alarm,trigger_related:0 +#: field:res.alarm,trigger_related:0 +msgid "Related to" +msgstr "" + +#. module: base_calendar +#: field:base.calendar.set.exrule,interval:0 +#: field:calendar.alarm,trigger_interval:0 +#: field:res.alarm,trigger_interval:0 +msgid "Interval" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,week_list:0 +#: selection:calendar.event,week_list:0 +#: selection:calendar.todo,week_list:0 +msgid "Wednesday" +msgstr "" + +#. module: base_calendar +#: code:addons/base_calendar/base_calendar.py:1088 +#, python-format +msgid "Interval can not be Negative" +msgstr "" + +#. module: base_calendar +#: field:calendar.alarm,name:0 +#: view:calendar.event:0 +msgid "Summary" +msgstr "" + +#. module: base_calendar +#: field:calendar.alarm,active:0 +#: field:calendar.event,active:0 +#: field:calendar.todo,active:0 +#: field:res.alarm,active:0 +msgid "Active" +msgstr "" + +#. module: base_calendar +#: view:calendar.event:0 +msgid "Choose day in the month where repeat the meeting" +msgstr "" + +#. module: base_calendar +#: field:calendar.alarm,action:0 +msgid "Action" +msgstr "" + +#. module: base_calendar +#: help:base_calendar.invite.attendee,type:0 +msgid "Select whom you want to Invite" +msgstr "" + +#. module: base_calendar +#: help:calendar.alarm,duration:0 +#: help:res.alarm,duration:0 +msgid "" +"Duration' and 'Repeat' are both optional, but if one occurs, so MUST the " +"other" +msgstr "" + +#. module: base_calendar +#: model:ir.model,name:base_calendar.model_calendar_event_edit_all +msgid "Calendar Edit all event" +msgstr "" + +#. module: base_calendar +#: help:calendar.attendee,role:0 +msgid "Participation role for the calendar user" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +#: field:calendar.attendee,delegated_to:0 +msgid "Delegated To" +msgstr "" + +#. module: base_calendar +#: help:calendar.alarm,action:0 +msgid "Defines the action to be invoked when an alarm is triggered" +msgstr "" + +#. module: base_calendar +#: selection:calendar.event,end_type:0 +#: selection:calendar.todo,end_type:0 +msgid "End date" +msgstr "" + +#. module: base_calendar +#: view:calendar.event:0 +msgid "Search Events" +msgstr "" + +#. module: base_calendar +#: view:calendar.event:0 +msgid "Recurrency Option" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,freq:0 +#: selection:calendar.event,rrule_type:0 +#: selection:calendar.todo,rrule_type:0 +msgid "Weekly" +msgstr "" + +#. module: base_calendar +#: help:calendar.alarm,active:0 +#: help:res.alarm,active:0 +msgid "" +"If the active field is set to true, it will allow you to hide the event " +"alarm information without removing it." +msgstr "" + +#. module: base_calendar +#: field:calendar.event,recurrent_id:0 +#: field:calendar.todo,recurrent_id:0 +msgid "Recurrent ID date" +msgstr "" + +#. module: base_calendar +#: sql_constraint:res.users:0 +msgid "You can not have two users with the same login !" +msgstr "" + +#. module: base_calendar +#: field:calendar.alarm,state:0 +#: view:calendar.attendee:0 +#: field:calendar.attendee,state:0 +#: view:calendar.event:0 +#: field:calendar.event,state:0 +#: field:calendar.todo,state:0 +msgid "State" +msgstr "" + +#. module: base_calendar +#: view:res.alarm:0 +msgid "Reminder Details" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +msgid "To Review" +msgstr "" + +#. module: base_calendar +#: field:base.calendar.set.exrule,freq:0 +#: field:calendar.event,freq:0 +#: field:calendar.todo,freq:0 +msgid "Frequency" +msgstr "" + +#. module: base_calendar +#: selection:calendar.alarm,state:0 +msgid "Done" +msgstr "" + +#. module: base_calendar +#: help:calendar.event,interval:0 +#: help:calendar.todo,interval:0 +msgid "Repeat every (Days/Week/Month/Year)" +msgstr "" + +#. module: base_calendar +#: view:base_calendar.invite.attendee:0 +#: field:base_calendar.invite.attendee,user_ids:0 +msgid "Users" +msgstr "" + +#. module: base_calendar +#: view:base.calendar.set.exrule:0 +msgid "of" +msgstr "" + +#. module: base_calendar +#: view:base_calendar.invite.attendee:0 +#: view:calendar.event:0 +#: view:calendar.event.edit.all:0 +msgid "Cancel" +msgstr "" + +#. module: base_calendar +#: model:ir.model,name:base_calendar.model_res_users +msgid "res.users" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,week_list:0 +#: selection:calendar.event,week_list:0 +#: selection:calendar.todo,week_list:0 +msgid "Tuesday" +msgstr "" + +#. module: base_calendar +#: help:calendar.alarm,description:0 +msgid "" +"Provides a more complete description of the " +"calendar component, than that provided by the " +"\"SUMMARY\" property" +msgstr "" + +#. module: base_calendar +#: view:calendar.event:0 +msgid "Responsible User" +msgstr "" + +#. module: base_calendar +#: selection:calendar.attendee,availability:0 +#: selection:calendar.event,show_as:0 +#: selection:calendar.todo,show_as:0 +#: selection:res.users,availability:0 +msgid "Busy" +msgstr "" + +#. module: base_calendar +#: model:ir.model,name:base_calendar.model_calendar_event +msgid "Calendar Event" +msgstr "" + +#. module: base_calendar +#: selection:calendar.attendee,state:0 +#: selection:calendar.event,state:0 +#: selection:calendar.todo,state:0 +msgid "Tentative" +msgstr "" + +#. module: base_calendar +#: field:calendar.event,interval:0 +#: field:calendar.todo,interval:0 +msgid "Repeat every" +msgstr "" + +#. module: base_calendar +#: selection:calendar.event,end_type:0 +#: selection:calendar.todo,end_type:0 +msgid "Fix amout of times" +msgstr "" + +#. module: base_calendar +#: field:calendar.event,recurrency:0 +#: field:calendar.todo,recurrency:0 +msgid "Recurrent" +msgstr "" + +#. module: base_calendar +#: field:calendar.event,rrule_type:0 +#: field:calendar.todo,rrule_type:0 +msgid "Recurrency" +msgstr "" + +#. module: base_calendar +#: model:ir.actions.act_window,name:base_calendar.action_view_attendee_form +#: model:ir.ui.menu,name:base_calendar.menu_attendee_invitations +msgid "Event Invitations" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,week_list:0 +#: selection:calendar.event,week_list:0 +#: selection:calendar.todo,week_list:0 +msgid "Thursday" +msgstr "" + +#. module: base_calendar +#: field:calendar.event,exrule:0 +#: field:calendar.todo,exrule:0 +msgid "Exception Rule" +msgstr "" + +#. module: base_calendar +#: help:calendar.attendee,language:0 +msgid "" +"To specify the language for text values in aproperty or property parameter." +msgstr "" + +#. module: base_calendar +#: view:calendar.event:0 +msgid "Details" +msgstr "" + +#. module: base_calendar +#: help:calendar.event,exrule:0 +#: help:calendar.todo,exrule:0 +msgid "" +"Defines a rule or repeating pattern of time to exclude from the recurring " +"rule." +msgstr "" + +#. module: base_calendar +#: field:base.calendar.set.exrule,month_list:0 +#: field:calendar.event,month_list:0 +#: field:calendar.todo,month_list:0 +msgid "Month" +msgstr "" + +#. module: base_calendar +#: view:base_calendar.invite.attendee:0 +#: view:calendar.event:0 +msgid "Invite People" +msgstr "" + +#. module: base_calendar +#: help:calendar.event,rrule:0 +#: help:calendar.todo,rrule:0 +msgid "" +"Defines a rule or repeating pattern for recurring events\n" +"e.g.: Every other month on the last Sunday of the month for 10 occurrences: " +" FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=-1SU" +msgstr "" + +#. module: base_calendar +#: field:calendar.attendee,dir:0 +msgid "URI Reference" +msgstr "" + +#. module: base_calendar +#: field:calendar.alarm,description:0 +#: view:calendar.event:0 +#: field:calendar.event,description:0 +#: field:calendar.event,name:0 +#: field:calendar.todo,description:0 +#: field:calendar.todo,name:0 +msgid "Description" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,month_list:0 +#: selection:calendar.event,month_list:0 +#: selection:calendar.todo,month_list:0 +msgid "May" +msgstr "" + +#. module: base_calendar +#: field:base_calendar.invite.attendee,type:0 +#: view:calendar.attendee:0 +msgid "Type" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +msgid "Search Invitations" +msgstr "" + +#. module: base_calendar +#: selection:calendar.alarm,trigger_occurs:0 +#: selection:res.alarm,trigger_occurs:0 +msgid "After" +msgstr "" + +#. module: base_calendar +#: selection:calendar.alarm,state:0 +msgid "Stop" +msgstr "" + +#. module: base_calendar +#: model:ir.model,name:base_calendar.model_ir_values +msgid "ir.values" +msgstr "" + +#. module: base_calendar +#: model:ir.model,name:base_calendar.model_ir_model +msgid "Objects" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +#: selection:calendar.attendee,state:0 +msgid "Delegated" +msgstr "" + +#. module: base_calendar +#: field:base.calendar.set.exrule,sa:0 +#: field:calendar.event,sa:0 +#: field:calendar.todo,sa:0 +msgid "Sat" +msgstr "" + +#. module: base_calendar +#: view:calendar.event:0 +msgid "Choose day where repeat the meeting" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,freq:0 +msgid "Minutely" +msgstr "" + +#. module: base_calendar +#: help:calendar.attendee,sent_by:0 +msgid "Specify the user that is acting on behalf of the calendar user" +msgstr "" + +#. module: base_calendar +#: view:calendar.event:0 +#: field:calendar.event.edit.all,date_deadline:0 +msgid "End Date" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,month_list:0 +#: selection:calendar.event,month_list:0 +#: selection:calendar.todo,month_list:0 +msgid "February" +msgstr "" + +#. module: base_calendar +#: selection:calendar.event,freq:0 +#: selection:calendar.todo,freq:0 +msgid "Months" +msgstr "" + +#. module: base_calendar +#: selection:calendar.attendee,cutype:0 +msgid "Resource" +msgstr "" + +#. module: base_calendar +#: field:res.alarm,name:0 +msgid "Name" +msgstr "" + +#. module: base_calendar +#: model:ir.model,name:base_calendar.model_calendar_alarm +msgid "Event alarm information" +msgstr "" + +#. module: base_calendar +#: help:calendar.alarm,name:0 +msgid "" +"Contains the text to be used as the message subject for " +"email or contains the text to be used for display" +msgstr "" + +#. module: base_calendar +#: field:calendar.event,alarm_id:0 +#: field:calendar.event,base_calendar_alarm_id:0 +#: field:calendar.todo,alarm_id:0 +#: field:calendar.todo,base_calendar_alarm_id:0 +msgid "Alarm" +msgstr "" + +#. module: base_calendar +#: code:addons/base_calendar/wizard/base_calendar_set_exrule.py:90 +#, python-format +msgid "Please Apply Recurrency before applying Exception Rule." +msgstr "" + +#. module: base_calendar +#: field:calendar.attendee,sent_by_uid:0 +msgid "Sent By User" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,month_list:0 +#: selection:calendar.event,month_list:0 +#: selection:calendar.todo,month_list:0 +msgid "April" +msgstr "" + +#. module: base_calendar +#: view:calendar.event:0 +msgid "Recurrency period" +msgstr "" + +#. module: base_calendar +#: field:base.calendar.set.exrule,week_list:0 +#: field:calendar.event,week_list:0 +#: field:calendar.todo,week_list:0 +msgid "Weekday" +msgstr "" + +#. module: base_calendar +#: field:base.calendar.set.exrule,byday:0 +#: field:calendar.event,byday:0 +#: field:calendar.todo,byday:0 +msgid "By day" +msgstr "" + +#. module: base_calendar +#: field:calendar.alarm,model_id:0 +msgid "Model" +msgstr "" + +#. module: base_calendar +#: selection:calendar.alarm,action:0 +msgid "Audio" +msgstr "" + +#. module: base_calendar +#: field:calendar.event,id:0 +#: field:calendar.todo,id:0 +msgid "ID" +msgstr "" + +#. module: base_calendar +#: selection:calendar.attendee,role:0 +msgid "For information Purpose" +msgstr "" + +#. module: base_calendar +#: view:base_calendar.invite.attendee:0 +msgid "Invite" +msgstr "" + +#. module: base_calendar +#: model:ir.model,name:base_calendar.model_calendar_attendee +msgid "Attendee information" +msgstr "" + +#. module: base_calendar +#: field:calendar.alarm,res_id:0 +msgid "Resource ID" +msgstr "" + +#. module: base_calendar +#: selection:calendar.attendee,state:0 +msgid "Needs Action" +msgstr "" + +#. module: base_calendar +#: field:calendar.attendee,sent_by:0 +msgid "Sent By" +msgstr "" + +#. module: base_calendar +#: field:calendar.event,sequence:0 +#: field:calendar.todo,sequence:0 +msgid "Sequence" +msgstr "" + +#. module: base_calendar +#: help:calendar.event,alarm_id:0 +#: help:calendar.todo,alarm_id:0 +msgid "Set an alarm at this time, before the event occurs" +msgstr "" + +#. module: base_calendar +#: selection:base_calendar.invite.attendee,type:0 +msgid "Internal User" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +#: view:calendar.event:0 +msgid "Accept" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,week_list:0 +#: selection:calendar.event,week_list:0 +#: selection:calendar.todo,week_list:0 +msgid "Saturday" +msgstr "" + +#. module: base_calendar +#: view:calendar.attendee:0 +msgid "Invitation To" +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,byday:0 +#: selection:calendar.event,byday:0 +#: selection:calendar.todo,byday:0 +msgid "Second" +msgstr "" + +#. module: base_calendar +#: field:calendar.attendee,availability:0 +#: field:res.users,availability:0 +msgid "Free/Busy" +msgstr "" + +#. module: base_calendar +#: field:calendar.event,end_type:0 +#: field:calendar.todo,end_type:0 +msgid "Way to end reccurency" +msgstr "" + +#. module: base_calendar +#: field:calendar.alarm,duration:0 +#: field:calendar.alarm,trigger_duration:0 +#: field:calendar.event,duration:0 +#: field:calendar.todo,date:0 +#: field:calendar.todo,duration:0 +#: field:res.alarm,duration:0 +#: field:res.alarm,trigger_duration:0 +msgid "Duration" +msgstr "" + +#. module: base_calendar +#: selection:base_calendar.invite.attendee,type:0 +msgid "External Email" +msgstr "" + +#. module: base_calendar +#: field:calendar.alarm,trigger_date:0 +msgid "Trigger Date" +msgstr "" + +#. module: base_calendar +#: help:calendar.alarm,attach:0 +msgid "" +"* Points to a sound resource, which is rendered when the " +"alarm is triggered for audio,\n" +" * File which is intended to be sent as message " +"attachments for email,\n" +" * Points to a procedure resource, which is invoked when " +" the alarm is triggered for procedure." +msgstr "" + +#. module: base_calendar +#: selection:base.calendar.set.exrule,byday:0 +#: selection:calendar.event,byday:0 +#: selection:calendar.todo,byday:0 +msgid "Fifth" +msgstr "" diff --git a/addons/hr/i18n/bn.po b/addons/hr/i18n/bn.po new file mode 100644 index 00000000000..05fd169ae01 --- /dev/null +++ b/addons/hr/i18n/bn.po @@ -0,0 +1,829 @@ +# Bengali translation for openobject-addons +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openobject-addons package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openobject-addons\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-01-11 11:15+0000\n" +"PO-Revision-Date: 2011-11-21 12:43+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Bengali \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2011-11-22 05:00+0000\n" +"X-Generator: Launchpad (build 14299)\n" + +#. module: hr +#: model:process.node,name:hr.process_node_openerpuser0 +msgid "Openerp user" +msgstr "Openerp ব্যাবহারকারী" + +#. module: hr +#: view:hr.job:0 +#: field:hr.job,requirements:0 +msgid "Requirements" +msgstr "আবশ্যকতা" + +#. module: hr +#: constraint:hr.department:0 +msgid "Error! You can not create recursive departments." +msgstr "ভুল! আপনি রিকারসিভ দপ্তর তৈরি করতে পারবেন না।" + +#. module: hr +#: model:process.transition,name:hr.process_transition_contactofemployee0 +msgid "Link the employee to information" +msgstr "তথ্যের সাথে কর্মচারী যুক্ত করুন" + +#. module: hr +#: field:hr.employee,sinid:0 +msgid "SIN No" +msgstr "ন্যাশনাল আইডি নং" + +#. module: hr +#: model:ir.module.module,shortdesc:hr.module_meta_information +#: model:ir.ui.menu,name:hr.menu_hr_deshboard +#: model:ir.ui.menu,name:hr.menu_hr_main +#: model:ir.ui.menu,name:hr.menu_hr_management +#: model:ir.ui.menu,name:hr.menu_hr_root +msgid "Human Resources" +msgstr "জনসম্পদ" + +#. module: hr +#: view:hr.employee:0 +#: view:hr.job:0 +msgid "Group By..." +msgstr "...দিয়ে গ্রুপ করুন" + +#. module: hr +#: model:ir.actions.act_window,help:hr.action_hr_job +msgid "" +"Job Positions are used to define jobs and their requirements. You can keep " +"track of the number of employees you have per job position and how many you " +"expect in the future. You can also attach a survey to a job position that " +"will be used in the recruitment process to evaluate the applicants for this " +"job position." +msgstr "" + +#. module: hr +#: view:hr.employee:0 +#: field:hr.employee,department_id:0 +#: view:hr.job:0 +#: field:hr.job,department_id:0 +#: view:res.users:0 +msgid "Department" +msgstr "বিভাগ" + +#. module: hr +#: help:hr.installer,hr_attendance:0 +msgid "Simplifies the management of employee's attendances." +msgstr "কর্মচারী উপস্থিতি ম্যানেজমেন্ট সহজতর করে" + +#. module: hr +#: view:hr.job:0 +msgid "Mark as Old" +msgstr "" + +#. module: hr +#: view:hr.job:0 +msgid "Jobs" +msgstr "কাজ" + +#. module: hr +#: view:hr.job:0 +msgid "In Recruitment" +msgstr "নিয়োগপ্রাপ্ত" + +#. module: hr +#: view:hr.installer:0 +msgid "title" +msgstr "শিরোনাম" + +#. module: hr +#: field:hr.department,company_id:0 +#: view:hr.employee:0 +#: view:hr.job:0 +#: field:hr.job,company_id:0 +msgid "Company" +msgstr "কোম্পানি" + +#. module: hr +#: field:hr.job,no_of_recruitment:0 +msgid "Expected in Recruitment" +msgstr "নিয়োগে কাম্য" + +#. module: hr +#: model:ir.ui.menu,name:hr.menu_open_view_attendance_reason_config +msgid "Holidays" +msgstr "ছুটির দিন" + +#. module: hr +#: help:hr.installer,hr_holidays:0 +msgid "Tracks employee leaves, allocation requests and planning." +msgstr "কর্মচারীদের ছুটির হিসাব রাখে" + +#. module: hr +#: model:ir.model,name:hr.model_hr_employee_marital_status +msgid "Employee Marital Status" +msgstr "কর্মচারীর বৈবাহিক অবস্থা" + +#. module: hr +#: help:hr.employee,partner_id:0 +msgid "" +"Partner that is related to the current employee. Accounting transaction will " +"be written on this partner belongs to employee." +msgstr "" + +#. module: hr +#: model:process.transition,name:hr.process_transition_employeeuser0 +msgid "Link a user to an employee" +msgstr "" + +#. module: hr +#: field:hr.installer,hr_contract:0 +msgid "Employee's Contracts" +msgstr "" + +#. module: hr +#: help:hr.installer,hr_payroll:0 +msgid "Generic Payroll system." +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "My Departments Employee" +msgstr "" + +#. module: hr +#: model:hr.employee.marital.status,name:hr.hr_employee_marital_status_married +msgid "Married" +msgstr "" + +#. module: hr +#: constraint:hr.employee:0 +msgid "" +"Error ! You cannot select a department for which the employee is the manager." +msgstr "" + +#. module: hr +#: help:hr.employee,passport_id:0 +msgid "Employee Passport Information" +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,help:hr.open_module_tree_department +msgid "" +"Your Company's Department Structure is used to manage all documents related " +"to employees by departments: expenses and timesheet validation, leaves " +"management, recruitments, etc." +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "Position" +msgstr "পদ" + +#. module: hr +#: model:ir.actions.act_window,name:hr.action2 +msgid "Employee Hierarchy" +msgstr "" + +#. module: hr +#: model:process.transition,note:hr.process_transition_employeeuser0 +msgid "" +"The Related user field on the Employee form allows to link the OpenERP user " +"(and her rights) to the employee." +msgstr "" + +#. module: hr +#: view:hr.job:0 +#: selection:hr.job,state:0 +msgid "In Recruitement" +msgstr "" + +#. module: hr +#: field:hr.employee,identification_id:0 +msgid "Identification No" +msgstr "" + +#. module: hr +#: field:hr.job,no_of_employee:0 +msgid "No of Employee" +msgstr "" + +#. module: hr +#: selection:hr.employee,gender:0 +msgid "Female" +msgstr "মহিলা" + +#. module: hr +#: help:hr.installer,hr_timesheet_sheet:0 +msgid "" +"Tracks and helps employees encode and validate timesheets and attendances." +msgstr "" + +#. module: hr +#: field:hr.installer,hr_evaluation:0 +msgid "Periodic Evaluations" +msgstr "" + +#. module: hr +#: field:hr.installer,hr_timesheet_sheet:0 +msgid "Timesheets" +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,name:hr.open_view_employee_tree +msgid "Employees Structure" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "Social IDs" +msgstr "" + +#. module: hr +#: help:hr.job,no_of_employee:0 +msgid "Number of employee with that job." +msgstr "" + +#. module: hr +#: field:hr.employee,work_phone:0 +msgid "Work Phone" +msgstr "কর্মস্থলের ফোন" + +#. module: hr +#: field:hr.employee.category,child_ids:0 +msgid "Child Categories" +msgstr "" + +#. module: hr +#: view:hr.job:0 +#: field:hr.job,description:0 +#: model:ir.model,name:hr.model_hr_job +msgid "Job Description" +msgstr "" + +#. module: hr +#: field:hr.employee,work_location:0 +msgid "Office Location" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +#: view:hr.job:0 +#: model:ir.model,name:hr.model_hr_employee +#: model:process.node,name:hr.process_node_employee0 +msgid "Employee" +msgstr "" + +#. module: hr +#: model:process.node,note:hr.process_node_employeecontact0 +msgid "Other information" +msgstr "" + +#. module: hr +#: field:hr.employee,work_email:0 +msgid "Work E-mail" +msgstr "" + +#. module: hr +#: field:hr.department,complete_name:0 +#: field:hr.employee.category,complete_name:0 +msgid "Name" +msgstr "নাম" + +#. module: hr +#: field:hr.employee,birthday:0 +msgid "Date of Birth" +msgstr "জন্মদিন" + +#. module: hr +#: model:ir.ui.menu,name:hr.menu_hr_reporting +msgid "Reporting" +msgstr "" + +#. module: hr +#: model:ir.model,name:hr.model_ir_actions_act_window +msgid "ir.actions.act_window" +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,name:hr.open_board_hr +msgid "Human Resources Dashboard" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +#: field:hr.employee,job_id:0 +#: view:hr.job:0 +msgid "Job" +msgstr "" + +#. module: hr +#: view:hr.department:0 +#: field:hr.department,member_ids:0 +msgid "Members" +msgstr "" + +#. module: hr +#: model:ir.ui.menu,name:hr.menu_hr_configuration +msgid "Configuration" +msgstr "" + +#. module: hr +#: view:hr.installer:0 +msgid "" +"You can enhance the base HR Application by installing few HR-related " +"functionalities." +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "Categories" +msgstr "" + +#. module: hr +#: field:hr.job,expected_employees:0 +msgid "Expected Employees" +msgstr "" + +#. module: hr +#: help:hr.employee,sinid:0 +msgid "Social Insurance Number" +msgstr "" + +#. module: hr +#: model:hr.employee.marital.status,name:hr.hr_employee_marital_status_divorced +msgid "Divorced" +msgstr "" + +#. module: hr +#: field:hr.employee.category,parent_id:0 +msgid "Parent Category" +msgstr "" + +#. module: hr +#: constraint:hr.employee.category:0 +msgid "Error ! You cannot create recursive Categories." +msgstr "" + +#. module: hr +#: view:hr.department:0 +#: model:ir.actions.act_window,name:hr.open_module_tree_department +#: model:ir.ui.menu,name:hr.menu_hr_department_tree +#: view:res.users:0 +#: field:res.users,context_department_id:0 +msgid "Departments" +msgstr "" + +#. module: hr +#: model:process.node,name:hr.process_node_employeecontact0 +msgid "Employee Contact" +msgstr "" + +#. module: hr +#: view:board.board:0 +msgid "My Board" +msgstr "" + +#. module: hr +#: selection:hr.employee,gender:0 +msgid "Male" +msgstr "" + +#. module: hr +#: field:hr.installer,progress:0 +msgid "Configuration Progress" +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,name:hr.open_view_categ_form +#: model:ir.ui.menu,name:hr.menu_view_employee_category_form +msgid "Categories of Employee" +msgstr "" + +#. module: hr +#: view:hr.employee.category:0 +#: model:ir.model,name:hr.model_hr_employee_category +msgid "Employee Category" +msgstr "" + +#. module: hr +#: field:hr.installer,config_logo:0 +msgid "Image" +msgstr "" + +#. module: hr +#: model:process.process,name:hr.process_process_employeecontractprocess0 +msgid "Employee Contract" +msgstr "" + +#. module: hr +#: help:hr.installer,hr_evaluation:0 +msgid "" +"Lets you create and manage the periodic evaluation and performance review of " +"employees." +msgstr "" + +#. module: hr +#: model:ir.model,name:hr.model_hr_department +msgid "hr.department" +msgstr "" + +#. module: hr +#: help:hr.employee,parent_id:0 +msgid "It is linked with manager of Department" +msgstr "" + +#. module: hr +#: field:hr.installer,hr_recruitment:0 +msgid "Recruitment Process" +msgstr "" + +#. module: hr +#: field:hr.employee,category_ids:0 +#: field:hr.employee.category,name:0 +msgid "Category" +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,help:hr.open_view_employee_list_my +msgid "" +"Here you can manage your work force by creating employees and assigning them " +"specific properties in the system. Maintain all employee related information " +"and keep track of anything that needs to be recorded for them. The personal " +"information tab will help you maintain their identity data. The Categories " +"tab gives you the opportunity to assign them related employee categories " +"depending on their position and activities within the company. A category " +"can be a seniority level within the company or a department. The Timesheets " +"tab allows to assign them a specific timesheet and analytic journal where " +"they will be able to enter time through the system. In the note tab, you can " +"enter text data that should be recorded for a specific employee." +msgstr "" + +#. module: hr +#: help:hr.employee,bank_account_id:0 +msgid "Employee bank salary account" +msgstr "" + +#. module: hr +#: field:hr.department,note:0 +msgid "Note" +msgstr "" + +#. module: hr +#: constraint:res.users:0 +msgid "The chosen company is not in the allowed companies for this user" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "Contact Information" +msgstr "" + +#. module: hr +#: field:hr.employee,address_id:0 +msgid "Working Address" +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,name:hr.open_board_hr_manager +msgid "HR Manager Dashboard" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "Status" +msgstr "" + +#. module: hr +#: view:hr.installer:0 +msgid "Configure" +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,name:hr.open_view_categ_tree +#: model:ir.ui.menu,name:hr.menu_view_employee_category_tree +msgid "Categories structure" +msgstr "" + +#. module: hr +#: field:hr.employee,partner_id:0 +msgid "unknown" +msgstr "" + +#. module: hr +#: field:hr.installer,hr_holidays:0 +msgid "Holidays / Leaves Management" +msgstr "" + +#. module: hr +#: field:hr.employee,ssnid:0 +msgid "SSN No" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "Active" +msgstr "" + +#. module: hr +#: constraint:hr.employee:0 +msgid "Error ! You cannot create recursive Hierarchy of Employees." +msgstr "" + +#. module: hr +#: view:hr.department:0 +msgid "Companies" +msgstr "" + +#. module: hr +#: model:ir.module.module,description:hr.module_meta_information +msgid "" +"\n" +" Module for human resource management. You can manage:\n" +" * Employees and hierarchies : You can define your employee with User and " +"display hierarchies\n" +" * HR Departments\n" +" * HR Jobs\n" +" " +msgstr "" + +#. module: hr +#: model:process.transition,note:hr.process_transition_contactofemployee0 +msgid "" +"In the Employee form, there are different kind of information like Contact " +"information." +msgstr "" + +#. module: hr +#: help:hr.job,expected_employees:0 +msgid "Required number of Employees in total for that job." +msgstr "" + +#. module: hr +#: selection:hr.job,state:0 +msgid "Old" +msgstr "" + +#. module: hr +#: field:hr.employee.marital.status,description:0 +msgid "Status Description" +msgstr "" + +#. module: hr +#: sql_constraint:res.users:0 +msgid "You can not have two users with the same login !" +msgstr "" + +#. module: hr +#: view:hr.job:0 +#: field:hr.job,state:0 +msgid "State" +msgstr "" + +#. module: hr +#: field:hr.employee,marital:0 +#: view:hr.employee.marital.status:0 +#: field:hr.employee.marital.status,name:0 +#: model:ir.actions.act_window,name:hr.action_hr_marital_status +#: model:ir.ui.menu,name:hr.hr_menu_marital_status +msgid "Marital Status" +msgstr "" + +#. module: hr +#: help:hr.installer,hr_recruitment:0 +msgid "Helps you manage and streamline your recruitment process." +msgstr "" + +#. module: hr +#: model:process.node,note:hr.process_node_employee0 +msgid "Employee form and structure" +msgstr "" + +#. module: hr +#: field:hr.employee,photo:0 +msgid "Photo" +msgstr "" + +#. module: hr +#: model:ir.model,name:hr.model_res_users +msgid "res.users" +msgstr "" + +#. module: hr +#: field:hr.installer,hr_payroll_account:0 +msgid "Payroll Accounting" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "Personal Information" +msgstr "" + +#. module: hr +#: field:hr.employee,passport_id:0 +msgid "Passport No" +msgstr "" + +#. module: hr +#: view:res.users:0 +msgid "Current Activity" +msgstr "" + +#. module: hr +#: help:hr.installer,hr_expense:0 +msgid "" +"Tracks and manages employee expenses, and can automatically re-invoice " +"clients if the expenses are project-related." +msgstr "" + +#. module: hr +#: view:hr.job:0 +msgid "Current" +msgstr "" + +#. module: hr +#: field:hr.department,parent_id:0 +msgid "Parent Department" +msgstr "" + +#. module: hr +#: view:hr.employee.category:0 +msgid "Employees Categories" +msgstr "" + +#. module: hr +#: field:hr.employee,address_home_id:0 +msgid "Home Address" +msgstr "" + +#. module: hr +#: field:hr.installer,hr_attendance:0 +#: model:ir.ui.menu,name:hr.menu_open_view_attendance_reason_new_config +msgid "Attendances" +msgstr "" + +#. module: hr +#: view:hr.employee.marital.status:0 +#: view:hr.job:0 +msgid "Description" +msgstr "" + +#. module: hr +#: help:hr.installer,hr_contract:0 +msgid "Extends employee profiles to help manage their contracts." +msgstr "" + +#. module: hr +#: field:hr.installer,hr_payroll:0 +msgid "Payroll" +msgstr "" + +#. module: hr +#: model:hr.employee.marital.status,name:hr.hr_employee_marital_status_single +msgid "Single" +msgstr "" + +#. module: hr +#: field:hr.job,name:0 +msgid "Job Name" +msgstr "" + +#. module: hr +#: view:hr.job:0 +#: selection:hr.job,state:0 +msgid "In Position" +msgstr "" + +#. module: hr +#: field:hr.employee,mobile_phone:0 +msgid "Mobile" +msgstr "" + +#. module: hr +#: view:hr.department:0 +msgid "department" +msgstr "" + +#. module: hr +#: field:hr.employee,country_id:0 +msgid "Nationality" +msgstr "" + +#. module: hr +#: view:hr.department:0 +#: view:hr.employee:0 +#: field:hr.employee,notes:0 +msgid "Notes" +msgstr "" + +#. module: hr +#: model:ir.model,name:hr.model_hr_installer +msgid "hr.installer" +msgstr "" + +#. module: hr +#: view:board.board:0 +msgid "HR Manager Board" +msgstr "" + +#. module: hr +#: field:hr.employee,resource_id:0 +msgid "Resource" +msgstr "" + +#. module: hr +#: view:hr.installer:0 +#: model:ir.actions.act_window,name:hr.action_hr_installer +msgid "Human Resources Application Configuration" +msgstr "" + +#. module: hr +#: field:hr.employee,gender:0 +msgid "Gender" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +#: field:hr.job,employee_ids:0 +#: model:ir.actions.act_window,name:hr.hr_employee_normal_action_tree +#: model:ir.actions.act_window,name:hr.open_view_employee_list +#: model:ir.actions.act_window,name:hr.open_view_employee_list_my +#: model:ir.ui.menu,name:hr.menu_open_view_employee_list_my +#: model:ir.ui.menu,name:hr.menu_view_employee_category_configuration_form +msgid "Employees" +msgstr "" + +#. module: hr +#: field:hr.employee,bank_account_id:0 +msgid "Bank Account" +msgstr "" + +#. module: hr +#: field:hr.department,name:0 +msgid "Department Name" +msgstr "" + +#. module: hr +#: help:hr.employee,ssnid:0 +msgid "Social Security Number" +msgstr "" + +#. module: hr +#: model:process.node,note:hr.process_node_openerpuser0 +msgid "Creation of a OpenERP user" +msgstr "" + +#. module: hr +#: field:hr.department,child_ids:0 +msgid "Child Departments" +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,name:hr.action_hr_job +#: model:ir.ui.menu,name:hr.menu_hr_job +msgid "Job Positions" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +#: field:hr.employee,coach_id:0 +msgid "Coach" +msgstr "" + +#. module: hr +#: view:hr.installer:0 +msgid "Configure Your Human Resources Application" +msgstr "" + +#. module: hr +#: field:hr.installer,hr_expense:0 +msgid "Expenses" +msgstr "" + +#. module: hr +#: field:hr.department,manager_id:0 +#: view:hr.employee:0 +#: field:hr.employee,parent_id:0 +msgid "Manager" +msgstr "" + +#. module: hr +#: model:hr.employee.marital.status,name:hr.hr_employee_marital_status_widower +msgid "Widower" +msgstr "" + +#. module: hr +#: help:hr.installer,hr_payroll_account:0 +msgid "Generic Payroll system Integrated with Accountings." +msgstr "" + +#. module: hr +#: field:hr.employee,child_ids:0 +msgid "Subordinates" +msgstr "" diff --git a/addons/web/po/pt.po b/addons/web/po/pt.po new file mode 100644 index 00000000000..ca98e18bce9 --- /dev/null +++ b/addons/web/po/pt.po @@ -0,0 +1,688 @@ +# Portuguese translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:38+0200\n" +"PO-Revision-Date: 2011-11-21 22:22+0000\n" +"Last-Translator: Daniel Reis \n" +"Language-Team: Portuguese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2011-11-22 05:13+0000\n" +"X-Generator: Launchpad (build 14299)\n" + +#: addons/web/static/src/js/view_form.js:355 +msgid "" +"Warning, the record has been modified, your changes will be discarded." +msgstr "" +"Atenção, o o registo foi modificado, as suas alterações serão descartadas." + +#: addons/web/static/src/js/view_form.js:1659 +msgid "   Search More..." +msgstr "" + +#: addons/web/static/src/js/view_form.js:1672 +#, python-format +msgid "   Create \"%s\"" +msgstr "" + +#: addons/web/static/src/js/view_form.js:1678 +msgid "   Create and Edit..." +msgstr "" + +#: addons/web/static/src/js/views.js:568 +msgid "You must choose at least one record." +msgstr "Escolha pelo menos um registo." + +#: addons/web/static/src/js/views.js:569 +msgid "Warning" +msgstr "Aviso" + +#: addons/web/static/src/js/views.js:609 +msgid "Translations" +msgstr "Traduções" + +#: addons/web/static/src/js/views.js:614 addons/web/static/src/xml/base.xml:0 +msgid "Save" +msgstr "Guardar" + +#: addons/web/static/src/js/views.js:615 +msgid "Close" +msgstr "Fechar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "x" +msgstr "x" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#{title}" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#{text}" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Powered by" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "openerp.com" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Loading..." +msgstr "A carregar ..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create" +msgstr "Criar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Drop" +msgstr "Excluir" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Backup" +msgstr "Cópia de segurança" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Restore" +msgstr "Restaurar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Password" +msgstr "Senha" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Back to Login" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CREATE DATABASE" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Master password:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New database name:" +msgstr "Nome da nova base de dados" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Load Demonstration data:" +msgstr "Carregar dados de demonstração" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Default language:" +msgstr "Idioma predefinido:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Admin password:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm password:" +msgstr "Confirmar senha:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "DROP DATABASE" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Database:" +msgstr "Base de dados:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Master Password:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "BACKUP DATABASE" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "RESTORE DATABASE" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "File:" +msgstr "Ficheiro:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CHANGE MASTER PASSWORD" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New master password:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm new master password:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "User:" +msgstr "Utilizador:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Password:" +msgstr "Senha:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Database" +msgstr "Base de dados" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Login" +msgstr "Iniciar sessão" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Bad username or password" +msgstr "Nome de utilizador ou senha incorrectos" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"We think that daily job activities can be more intuitive, efficient, " +"automated, .. and even fun." +msgstr "" +"Pensamos que as atividades do trabalho diário pode ser mais intuitivas, " +"eficientes, automatizadas, ... e até mesmo divertidas." + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP's vision to be:" +msgstr "A visão do OpenERP é:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Full featured" +msgstr "Pleno de funcionalidade" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Today's enterprise challenges are multiple. We provide one module for each " +"need." +msgstr "" +"Os desafios atuais das empresas são múltiplos. Nós fornecemos um módulo para " +"cada necessidade." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Open Source" +msgstr "Código aberto" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"To Build a great product, we rely on the knowledge of thousands of " +"contributors." +msgstr "" +"Para construir um grande produto, nós contamos com o conhecimento de " +"milhares de contribuidores." + +#: addons/web/static/src/xml/base.xml:0 +msgid "User Friendly" +msgstr "Amigável para o utilizador" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"In order to be productive, people need clean and easy to use interface." +msgstr "" +"Para serem produtivas, as pessoas precisam de uma interface simples e fácil " +"de usar." + +#: addons/web/static/src/xml/base.xml:0 +msgid "(" +msgstr "(" + +#: addons/web/static/src/xml/base.xml:0 +msgid ")" +msgstr ")" + +#: addons/web/static/src/xml/base.xml:0 +msgid "LOGOUT" +msgstr "SAIR" + +#: addons/web/static/src/xml/base.xml:0 +msgid "«" +msgstr "«" + +#: addons/web/static/src/xml/base.xml:0 +msgid "»" +msgstr "»" + +#: addons/web/static/src/xml/base.xml:0 +msgid "oe_secondary_menu_item" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "oe_secondary_submenu_item" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Hide this tip" +msgstr "Ocultar esta dica" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Disable all tips" +msgstr "Desativar todas as dicas" + +#: addons/web/static/src/xml/base.xml:0 +msgid "View#" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Fields" +msgstr "Campos" + +#: addons/web/static/src/xml/base.xml:0 +msgid "View labels" +msgstr "Ver etiquetas" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Sidebar Relates" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Field" +msgstr "Campo" + +#: addons/web/static/src/xml/base.xml:0 +msgid ":" +msgstr ":" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Translate view" +msgstr "Traduzir vista" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Translate sidebar" +msgstr "Traduzir barra lateral" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Delete" +msgstr "Apagar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "First" +msgstr "Primeiro" + +#: addons/web/static/src/xml/base.xml:0 +msgid "<" +msgstr "<" + +#: addons/web/static/src/xml/base.xml:0 +msgid ">" +msgstr ">" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Last" +msgstr "Último" + +#: addons/web/static/src/xml/base.xml:0 +msgid "♻" +msgstr "♻" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & Edit" +msgstr "Gravar & Editar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create & Edit" +msgstr "Criar & Editar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New" +msgstr "Novo" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Duplicate" +msgstr "Duplicar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Readonly/Editable" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "<<" +msgstr "<<" + +#: addons/web/static/src/xml/base.xml:0 +msgid "0" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "/" +msgstr "/" + +#: addons/web/static/src/xml/base.xml:0 +msgid ">>" +msgstr ">>" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Add" +msgstr "Acrescentar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Unhandled widget" +msgstr "Widget não tratado" + +#: addons/web/static/src/xml/base.xml:0 +msgid "?" +msgstr "?" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#" +msgstr "#" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Done" +msgstr "Concluído" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Open..." +msgstr "Abrir..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create..." +msgstr "Criar..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Search..." +msgstr "Procurar..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "..." +msgstr "..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Uploading ..." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Select" +msgstr "Selecionar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save As" +msgstr "Guardar como" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Clear" +msgstr "Limpar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Advanced Filter" +msgstr "Filtro avançados" + +#: addons/web/static/src/xml/base.xml:0 +msgid "-- Filters --" +msgstr "-- Filtros --" + +#: addons/web/static/src/xml/base.xml:0 +msgid "-- Actions --" +msgstr "-- Ações --" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save Filter" +msgstr "Guardar filtro" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Manage Filters" +msgstr "Gerir filtros" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Filter Name:" +msgstr "Nome do filtro:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "(Any existing filter with the same name will be replaced)" +msgstr "(filtros existentes com esse nome serão substituídos)" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Any of the following conditions must match" +msgstr "Deve satisfazer alguma das seguintes condições" + +#: addons/web/static/src/xml/base.xml:0 +msgid "All the following conditions must match" +msgstr "Deve satisfazer toas as seguintes condições" + +#: addons/web/static/src/xml/base.xml:0 +msgid "None of the following conditions must match" +msgstr "Não deve satisfazernenhuma das seguintes condições" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Add condition" +msgstr "Acrescentar condição" + +#: addons/web/static/src/xml/base.xml:0 +msgid "and" +msgstr "e" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Cancel" +msgstr "Cancelar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & New" +msgstr "Guardar & Novo" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & Close" +msgstr "Guardar & Fechar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export" +msgstr "Exportar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"This wizard will export all data that matches the current search criteria to " +"a CSV file.\n" +" You can export all data or only the fields that can be " +"reimported after modification." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export Type:" +msgstr "Tipo de exportação:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import Compatible Export" +msgstr "Exportação compatível com importação" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export all Data" +msgstr "Exportar todos os dados" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export Formats" +msgstr "Formatos de exportação" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Available fields" +msgstr "Campos disponíveis" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Fields to export" +msgstr "Campos a exportar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save fields list" +msgstr "Gravar lista de campos" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Remove" +msgstr "Remover" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Remove All" +msgstr "Remover tudo" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Name" +msgstr "Nome" + +#: addons/web/static/src/xml/base.xml:0 +msgid " " +msgstr " " + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save as:" +msgstr "Guardar como:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Ok" +msgstr "Ok" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Saved exports:" +msgstr "Exportações guardadas:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Old Password:" +msgstr "Senha antiga:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New Password:" +msgstr "Nova senha:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm Password:" +msgstr "Confirme a senha:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import" +msgstr "Importar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "1. Import a .CSV file" +msgstr "1. Importar um ficheiro .CSV" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Select a .CSV file to import. If you need a sample of file to import,\n" +" you should use the export tool with the \"Import Compatible\" option." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CSV File:" +msgstr "Ficheiro CSV:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "2. Check your file format" +msgstr "2. Verifique o formato do ficheiro" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import Options" +msgstr "Opções de importação" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Does your file have titles?" +msgstr "O ficheiro tem títulos?" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Separator:" +msgstr "Separador:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Delimiter:" +msgstr "Delimitador:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Encoding:" +msgstr "Codificação:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "UTF-8" +msgstr "UTF-8" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Latin 1" +msgstr "Latin-1" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Lines to skip" +msgstr "Linhas a ignorar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "The import failed due to:" +msgstr "Importação falhou devido a:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Here is a preview of the file we could not import:" +msgstr "Previsão do ficheiro que não conseguiu ser importado:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP Web" +msgstr "OpenERP Web" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Version" +msgstr "Versão" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Copyright © 2011-TODAY OpenERP SA. All Rights Reserved." +msgstr "Copyright © 2011-HOJE OpenERP SA. Todos os direitos reservados." + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP is a trademark of the" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP SA Company" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Licenced under the terms of" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "GNU Affero General Public License" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "About OpenERP" +msgstr "Acerca do OpenERP" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP" +msgstr "OpenERP" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"is a free enterprise-scale software system that is designed to boost\n" +" productivity and profit through data integration. It connects, " +"improves and\n" +" manages business processes in areas such as sales, finance, " +"supply chain,\n" +" project management, production, services, CRM, etc..." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"The system is platform-independent, and can be installed on Windows, Mac OS " +"X,\n" +" and various Linux and other Unix-based distributions. Its " +"architecture enables\n" +" new functionality to be rapidly created, modifications to be " +"made to a\n" +" production system and migration to a new version to be " +"straightforward." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Depending on your needs, OpenERP is available through a web or application " +"client." +msgstr "" +"Dependendo de suas necessidades, o OpenERP está disponível através da web ou " +"de uma aplicação cliente." diff --git a/addons/web_calendar/po/pt.po b/addons/web_calendar/po/pt.po new file mode 100644 index 00000000000..a2ba6e02a2a --- /dev/null +++ b/addons/web_calendar/po/pt.po @@ -0,0 +1,22 @@ +# Portuguese translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:38+0200\n" +"PO-Revision-Date: 2011-11-21 21:57+0000\n" +"Last-Translator: Daniel Reis \n" +"Language-Team: Portuguese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2011-11-22 05:13+0000\n" +"X-Generator: Launchpad (build 14299)\n" + +#: addons/web_calendar/static/src/xml/web_calendar.xml:0 +msgid " " +msgstr " " diff --git a/addons/web_mobile/po/pt.po b/addons/web_mobile/po/pt.po new file mode 100644 index 00000000000..8054ab4ceac --- /dev/null +++ b/addons/web_mobile/po/pt.po @@ -0,0 +1,66 @@ +# Portuguese translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:39+0200\n" +"PO-Revision-Date: 2011-11-21 22:23+0000\n" +"Last-Translator: Daniel Reis \n" +"Language-Team: Portuguese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2011-11-22 05:13+0000\n" +"X-Generator: Launchpad (build 14299)\n" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "OpenERP" +msgstr "OpenERP" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Database:" +msgstr "Base de dados:" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Login:" +msgstr "Utilizador (login):" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Password:" +msgstr "Senha:" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Login" +msgstr "" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Bad username or password" +msgstr "Nome de utilizador ou senha incorrectos" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Favourite" +msgstr "Favorito" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Preference" +msgstr "Preferência" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Applications" +msgstr "Aplicações" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Options" +msgstr "Opções" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Logout" +msgstr "" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid ":" +msgstr "" From 452eca8952e8cb5c343441b2c714b422734b8530 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Tue, 22 Nov 2011 11:54:31 +0530 Subject: [PATCH 095/106] [imp] added replace() method in Widget to ease insertion at a precise place in the dom bzr revid: nicolas.vanhoren@openerp.com-20111122062431-zh762kivblfhwewk --- addons/web/static/src/js/core.js | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js index a9731ef5b16..906ddefc6e5 100644 --- a/addons/web/static/src/js/core.js +++ b/addons/web/static/src/js/core.js @@ -809,7 +809,7 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W */ tag_name: 'div', /** - * Construct the widget and set its parent if a parent is given. + * Constructs the widget and sets its parent if a parent is given. * * @constructs openerp.web.Widget * @extends openerp.web.CallbackEnabled @@ -841,7 +841,7 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W this.widget_is_stopped = false; }, /** - * Render the current widget and appends it to the given jQuery object or Widget. + * Renders the current widget and appends it to the given jQuery object or Widget. * * @param target A jQuery object or a Widget instance. */ @@ -852,7 +852,7 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W }, target); }, /** - * Render the current widget and prepends it to the given jQuery object or Widget. + * Renders the current widget and prepends it to the given jQuery object or Widget. * * @param target A jQuery object or a Widget instance. */ @@ -863,7 +863,7 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W }, target); }, /** - * Render the current widget and inserts it after to the given jQuery object or Widget. + * Renders the current widget and inserts it after to the given jQuery object or Widget. * * @param target A jQuery object or a Widget instance. */ @@ -874,7 +874,7 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W }, target); }, /** - * Render the current widget and inserts it before to the given jQuery object or Widget. + * Renders the current widget and inserts it before to the given jQuery object or Widget. * * @param target A jQuery object or a Widget instance. */ @@ -884,6 +884,16 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W self.$element.insertBefore(t); }, target); }, + /** + * Renders the current widget and replaces the given jQuery object. + * + * @param target A jQuery object or a Widget instance. + */ + replace: function(target) { + return this._render_and_insert(_.bind(function(t) { + this.$element.replaceAll(t); + }, this), target); + }, _render_and_insert: function(insertion, target) { this.render_element(); if (target instanceof openerp.web.Widget) @@ -929,7 +939,7 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W return $.Deferred().done().promise(); }, /** - * Destroys the current widget, also destroy all its children before destroying itself. + * Destroys the current widget, also destroys all its children before destroying itself. */ stop: function() { _.each(_.clone(this.widget_children), function(el) { @@ -945,7 +955,7 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W this.widget_is_stopped = true; }, /** - * Inform the action manager to do an action. Of course, this suppose that + * Informs the action manager to do an action. This supposes that * the action manager can be found amongst the ancestors of the current widget. * If that's not the case this method will simply return `false`. */ From c7de208ffaaca84f9ab51c4cf5df354260fb3a1c Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Tue, 22 Nov 2011 10:25:24 +0100 Subject: [PATCH 096/106] [FIX] account: set the default value for partner when encoding a new address through the invoice form view bzr revid: qdp-launchpad@openerp.com-20111122092524-uv3yzyd530xjsjnj --- addons/account/account_invoice_view.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml index efc7a24031c..54a60ee1b57 100644 --- a/addons/account/account_invoice_view.xml +++ b/addons/account/account_invoice_view.xml @@ -153,7 +153,7 @@