# HG changeset patch # User szeka_wong <szeka.wong@xcg-consulting.fr> # Date 1733142720 -3600 # Mon Dec 02 13:32:00 2024 +0100 # Branch 18.0 # Node ID 11e3f9c0aeb967bddba69561086eab91dd5b1990 # Parent ce2b2a31d539d6fd773bf6882137a79dffc9ade4 Fix RelationToMany calling undefined fonction. diff --git a/NEWS.rst b/NEWS.rst --- a/NEWS.rst +++ b/NEWS.rst @@ -1,6 +1,11 @@ Changelog ========= +18.0.2.0.1 +---------- + +Fix RelationToMany calling undefined fonction. + 18.0.2.0.0 ---------- diff --git a/__manifest__.py b/__manifest__.py --- a/__manifest__.py +++ b/__manifest__.py @@ -21,7 +21,7 @@ "name": "Converter", "license": "AGPL-3", "summary": "Convert odoo records to/from plain data structures.", - "version": "18.0.2.0.0", + "version": "18.0.2.0.1", "category": "Hidden", "author": "XCG Consulting", "website": "https://orbeet.io/", diff --git a/relation.py b/relation.py --- a/relation.py +++ b/relation.py @@ -73,59 +73,13 @@ if not value_present: return {} - post_hook = getattr(self.converter, "post_hook", None) - - if self.converter.is_instance_getter: - rel_record: models.BaseModel | NewinstanceType | None = ( - self.converter.get_instance(odoo_env, message_value) - ) - - if rel_record is None: - return {self.field_name: None} - - if isinstance(rel_record, NewinstanceType): - rel_record = None - - updates = self.converter.message_to_odoo( - odoo_env, phase, message_value, rel_record, value_present - ) - - if updates: - if rel_record: - rel_record.write(updates) - else: - rel_record = odoo_env[self.model_name].create(updates) - - if post_hook: - post_hook(rel_record, message_value) + record = _update_record( + self, odoo_env, phase, message_value, instance, value_present + ) + if record is None: + return {} - if instance: - field_value = getattr(instance, self.field_name) - - if field_value and field_value.id == rel_record.id: - return {} - return {self.field_name: rel_record.id} - return {self.field_name: rel_record.id} - - else: - field_value = getattr(instance, self.field_name) if instance else None - - updates = self.converter.message_to_odoo( - odoo_env, phase, message_value, field_value, value_present - ) - - if updates: - if field_value: - field_value.write(updates) - if post_hook: - post_hook(field_value, message_value) - return {} - else: - rel_record = odoo_env[self.model_name].create(updates) - if post_hook: - post_hook(rel_record, message_value) - return {self.field_name: rel_record.id} - return {} + return {self.field_name: record.id} class RelationToMany(Field): @@ -181,8 +135,17 @@ return {} field_instances = odoo_env[self.model_name] for value in message_value: - field_instances |= odoo_env["ir.model.data"].browseXref(value) - if instance and getattr(instance, self.field_name) == field_instances: + record = _update_record( + self, odoo_env, phase, value, instance, value_present + ) + if record is not None: + field_instances |= record + + if ( + instance + and not isinstance(instance, NewinstanceType) + and getattr(instance, self.field_name) == field_instances + ): return {} return {self.field_name: [(6, 0, field_instances.ids)]} @@ -239,8 +202,17 @@ return {} field_instances = odoo_env[self.model_name] for value in message_value: - field_instances |= odoo_env["ir.model.data"].browseXref(value) - if instance and getattr(instance, self.field_name) == field_instances: + record = _update_record( + self, odoo_env, phase, value, instance, value_present + ) + if record is not None: + field_instances |= record + + if ( + instance + and not isinstance(instance, NewinstanceType) + and getattr(instance, self.field_name) == field_instances + ): return {} return {self.field_name: [(6, 0, field_instances.ids)]} @@ -259,3 +231,71 @@ else: converter = RelationToOne(name, model_name, converter) return converter + + +def _update_record( + self, + odoo_env: api.Environment, + phase: str, + message_value: Any, + instance: models.BaseModel, + value_present: bool = True, +) -> Any: + """Update or create a single record with the given values. + :param self: the actual converter class. + :param message_value: the message value for one record. + :return: the record id, if any, else None. + """ + post_hook = getattr(self.converter, "post_hook", None) + + if self.converter.is_instance_getter: + rel_record: models.BaseModel | NewinstanceType | None = ( + self.converter.get_instance(odoo_env, message_value) + ) + if rel_record is None: + return None + + if isinstance(rel_record, NewinstanceType): + rel_record = None + + updates = self.converter.message_to_odoo( + odoo_env, phase, message_value, rel_record, value_present + ) + + if updates: + if rel_record: + rel_record.write(updates) + else: + rel_record = odoo_env[self.model_name].create(updates) + if post_hook: + post_hook(rel_record, message_value) + + if instance and not isinstance(instance, NewinstanceType): + field_value = getattr(instance, self.field_name) + if field_value and rel_record.id in field_value.ids: + return None + + return rel_record + else: + field_value = ( + getattr(instance, self.field_name) + if instance and not isinstance(instance, NewinstanceType) + else None + ) + + updates = self.converter.message_to_odoo( + odoo_env, phase, message_value, field_value, value_present + ) + + if updates: + if field_value: + field_value.write(updates) + if post_hook: + post_hook(field_value, message_value) + return None + else: + rel_record = odoo_env[self.model_name].create(updates) + if post_hook: + post_hook(rel_record, message_value) + return rel_record + return None diff --git a/tests/test_relation.py b/tests/test_relation.py --- a/tests/test_relation.py +++ b/tests/test_relation.py @@ -24,6 +24,7 @@ from .. import ( Field, Model, + RelationToMany, RelationToOne, Skip, Xref, @@ -119,3 +120,50 @@ message_to_odoo(self.env, message, self.env["res.users"], converter) self.assertEqual(user.partner_id, new_partner) self.assertEqual(new_partner.color, 3) + + def test_many2many_to_odoo(self): + """Ensure multiple sub-objects linked from the main one gets updated + when Odoo receives a message. + """ + + # This converter wraps a user and adds info from its related partner. + converter = Model( + None, + { + "users": RelationToMany( + "user_ids", + "res.users", + Model( + "user", + { + "email": Field("email"), + "xref": Xref("base"), + }, + ), + ), + "xref": Xref("base"), + }, + ) + + partner = self.env.ref("base.main_partner") + self.assertFalse(partner.user_ids) + + # Run our message reception. + message: dict[str, Any] = { + "users": [ + { + "__type__": "user", + "xref": "user_admin", + }, + { + "__type__": "user", + "xref": "user_demo", + }, + ], + "xref": "main_partner", + } + message_to_odoo(self.env, message, self.env["res.partner"], converter) + + # Check the partner's users + self.assertTrue(partner.user_ids) + self.assertEqual(len(partner.user_ids), 2)