diff --git a/auditlog/models/rule.py b/auditlog/models/rule.py index 7781dae25..d2dbd7745 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 _, api, fields, models, modules FIELDS_BLACKLIST = [ @@ -234,50 +236,54 @@ 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, + 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, + 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 ed0b83456..652548fa4 100644 --- a/auditlog/tests/test_auditlog.py +++ b/auditlog/tests/test_auditlog.py @@ -100,6 +100,35 @@ class AuditlogCommon(object): ).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): def setUp(self):