diff --git a/auditlog/models/rule.py b/auditlog/models/rule.py index 8af2bedd1..ca48e4143 100644 --- a/auditlog/models/rule.py +++ b/auditlog/models/rule.py @@ -1,6 +1,8 @@ # Copyright 2015 ABF OSIELL # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +import copy + from odoo import models, fields, api, modules, _ FIELDS_BLACKLIST = [ @@ -208,37 +210,41 @@ class AuditlogRule(models.Model): self.ensure_one() log_type = self.log_type - @api.model + @api.model_create_multi @api.returns('self', lambda value: value.id) - def create_full(self, vals, **kwargs): + def create_full(self, vals_list, **kwargs): self = self.with_context(auditlog_disabled=True) rule_model = self.env['auditlog.rule'] - new_record = create_full.origin(self, vals, **kwargs) + new_records = create_full.origin(self, vals_list, **kwargs) # Take a snapshot of record values from the cache instead of using # 'read()'. It avoids issues with related/computed fields which # stored in the database only at the end of the transaction, but # their values exist in cache. - new_values = {new_record.id: {}} - for fname, field in new_record._fields.items(): - new_values[new_record.id][fname] = field.convert_to_read( - new_record[fname], new_record) + new_values = {} + for new_record in new_records: + new_values.setdefault(new_record.id, {}) + for fname, field in new_record._fields.items(): + new_values[new_record.id][fname] = field.convert_to_read( + new_record[fname], new_record) rule_model.sudo().create_logs( - self.env.uid, self._name, new_record.ids, + self.env.uid, self._name, new_records.ids, 'create', None, new_values, {'log_type': log_type}) - return new_record + return new_records - @api.model + @api.model_create_multi @api.returns('self', lambda value: value.id) - def create_fast(self, vals, **kwargs): + def create_fast(self, vals_list, **kwargs): self = self.with_context(auditlog_disabled=True) rule_model = self.env['auditlog.rule'] - vals2 = dict(vals) - new_record = create_fast.origin(self, vals, **kwargs) - new_values = {new_record.id: vals2} + vals_list2 = copy.deepcopy(vals_list) + new_records = create_fast.origin(self, vals_list, **kwargs) + new_values = {} + for vals, new_record in zip(vals_list2, new_records): + new_values.setdefault(new_record.id, vals) rule_model.sudo().create_logs( - self.env.uid, self._name, new_record.ids, + self.env.uid, self._name, new_records.ids, 'create', None, new_values, {'log_type': log_type}) - return new_record + return new_records return create_full if self.log_type == 'full' else create_fast diff --git a/auditlog/tests/test_auditlog.py b/auditlog/tests/test_auditlog.py index 996cf5fa1..9c490eb52 100644 --- a/auditlog/tests/test_auditlog.py +++ b/auditlog/tests/test_auditlog.py @@ -80,6 +80,33 @@ class AuditlogCommon(object): ('res_id', '=', testgroup4.id), ]).ensure_one()) + def test_LogCreation4(self): + """Fourth test, create several records at once (with create multi + feature starting from Odoo 12) and check that the same number of logs + has been generated. + """ + + self.groups_rule.subscribe() + + auditlog_log = self.env['auditlog.log'] + groups_vals = [ + {'name': 'testgroup1'}, + {'name': 'testgroup3'}, + {'name': 'testgroup2'}, + ] + groups = self.env['res.groups'].create(groups_vals) + # Ensure that the recordset returns is in the same order + # than list of vals + expected_names = ['testgroup1', 'testgroup3', 'testgroup2'] + self.assertEqual(groups.mapped('name'), expected_names) + + logs = auditlog_log.search([ + ('model_id', '=', self.groups_model_id), + ('method', '=', 'create'), + ('res_id', 'in', groups.ids), + ]) + self.assertEqual(len(logs), len(groups)) + class TestAuditlogFull(TransactionCase, AuditlogCommon):