[FIX] base_automation: differentiate between creating and writing
Steps to reproduce:
-------------------
[A] Create an automated action with:
- Model: Tasks (project.task)
- Trigger: On save
- When updating: ID (to mimic "on_create" trigger)
- Execute code:
```py
record.message_post(body="This is a message from automated action (fields triggers: ['id'])")
```
[B] Create a server action (contextual action) with:
- Type: execute code
- Model: Tasks (project.task)
- code:
```py
record.write({})
```
[C] Test:
- create a new task --> message has been posted (OK)
- write some values on the task --> no message has been posted (OK)
- run the server action --> message has been posted (KO)
Issue:
------
No message should be posted as the ID field has not been modified.
Cause:
------
`if not self._context.get('old_values')` is considered as `True`
because we have an empty dict.
In fact, when we make a write on a record, old_values will be always a dict.
```py
old_values = {
old_vals.pop('id'): old_vals
for old_vals in (records.read(list(vals)) if vals else [])
}
```
Solution:
---------
Old values are not defined in the context during a create.
We can compare `self._context.get('old_values')` with `None`
to differentiate between creating and writing on records.
opw-3736068
closes odoo/odoo#155832
Signed-off-by: Rémy Voet (ryv) <ryv@odoo.com>
This commit is contained in:
@@ -680,7 +680,7 @@ class BaseAutomation(models.Model):
|
||||
# all fields are implicit triggers
|
||||
return True
|
||||
|
||||
if not self._context.get('old_values'):
|
||||
if self._context.get('old_values') is None:
|
||||
# this is a create: all fields are considered modified
|
||||
return True
|
||||
|
||||
|
||||
@@ -112,3 +112,46 @@ class TestAutomation(TransactionCaseWithUserDemo):
|
||||
# simulate a onchange call on name
|
||||
result = self_portal.onchange({}, [], {"name": {}, "active": {}})
|
||||
self.assertEqual(result["value"]["active"], False)
|
||||
|
||||
def test_04_on_create_or_write_differentiate(self):
|
||||
"""
|
||||
The purpose is to differentiate create and empty write.
|
||||
"""
|
||||
model = self.env.ref("base.model_res_partner")
|
||||
model_field_id = self.env['ir.model.fields'].search([('model', '=', model.model), ('name', '=', 'id')], limit=1)
|
||||
automation = self.env["base.automation"].create({
|
||||
"name": "Test automated action",
|
||||
"trigger": "on_create_or_write",
|
||||
"model_id": model.id,
|
||||
"trigger_field_ids": [Command.set([model_field_id.id])],
|
||||
})
|
||||
action = self.env["ir.actions.server"].create({
|
||||
"name": "Modify name",
|
||||
"base_automation_id": automation.id,
|
||||
"model_id": model.id,
|
||||
"state": "code",
|
||||
"code": "record.write({'name': 'Modified Name'})"
|
||||
})
|
||||
action.flush_recordset()
|
||||
automation.write({"action_server_ids": [Command.link(action.id)]})
|
||||
# action cached was cached with admin, force CacheMiss
|
||||
automation.env.clear()
|
||||
|
||||
server_action = self.env["ir.actions.server"].create({
|
||||
"name": "Empty write",
|
||||
"model_id": model.id,
|
||||
"state": "code",
|
||||
"code": "record.write({})"
|
||||
})
|
||||
|
||||
partner = self.env[model.model].create({'name': 'Test Name'})
|
||||
self.assertEqual(partner.name, 'Modified Name', 'The automatic action must be performed')
|
||||
partner.name = 'Reset Name'
|
||||
self.assertEqual(partner.name, 'Reset Name', 'The automatic action must not be performed')
|
||||
|
||||
context = {
|
||||
'active_model': model.model,
|
||||
'active_id': partner.id,
|
||||
}
|
||||
server_action.with_context(context).run()
|
||||
self.assertEqual(partner.name, 'Reset Name', 'The automatic action must not be performed')
|
||||
|
||||
Reference in New Issue
Block a user