diff --git a/NEWS.rst b/NEWS.rst
index cdec236693eb2b38992d54bbf240a0aa7b0e55c1_TkVXUy5yc3Q=..b4e27f823ace4a230c2cca4b0c95d6a4c8019b20_TkVXUy5yc3Q= 100644
--- a/NEWS.rst
+++ b/NEWS.rst
@@ -1,6 +1,18 @@
 Changelog
 =========
 
+18.0.5.0.0
+----------
+
+Fix Switch converter to call post_hook.
+
+Xref converter:
+
+- Allow prefix on Xref converter
+- Add option to include module name in messages. Incoming and outgoing message value have the same comportment.
+  For example, if __converter__ is used as the module, both generated messages and received message will contain __converter__.<name>.
+  Previously, generated messages would use the module name while received one would not.
+
 18.0.4.1.0
 ----------
 
diff --git a/__manifest__.py b/__manifest__.py
index cdec236693eb2b38992d54bbf240a0aa7b0e55c1_X19tYW5pZmVzdF9fLnB5..b4e27f823ace4a230c2cca4b0c95d6a4c8019b20_X19tYW5pZmVzdF9fLnB5 100644
--- 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.4.1.0",
+    "version": "18.0.5.0.0",
     "category": "Hidden",
     "author": "XCG Consulting",
     "website": "https://orbeet.io/",
diff --git a/models/ir_model_data.py b/models/ir_model_data.py
index cdec236693eb2b38992d54bbf240a0aa7b0e55c1_bW9kZWxzL2lyX21vZGVsX2RhdGEucHk=..b4e27f823ace4a230c2cca4b0c95d6a4c8019b20_bW9kZWxzL2lyX21vZGVsX2RhdGEucHk= 100644
--- a/models/ir_model_data.py
+++ b/models/ir_model_data.py
@@ -38,5 +38,5 @@
     _inherit = "ir.model.data"
 
     @api.model
-    def generate_name(self) -> str:
+    def generate_name(self, prefix: str = "") -> str:
         """Generate an xref for odoo record;
@@ -42,4 +42,5 @@
         """Generate an xref for odoo record;
+        :param prefix: prefix to use before the name.
         :return: a UUID from a string of 32 hex digit
         """
 
@@ -43,7 +44,7 @@
         :return: a UUID from a string of 32 hex digit
         """
 
-        return uuid.uuid4().hex
+        return prefix + uuid.uuid4().hex
 
     @api.model
     def object_to_module_and_name(
@@ -47,9 +48,12 @@
 
     @api.model
     def object_to_module_and_name(
-        self, record_set: models.BaseModel, module: str | None = _XREF_IMD_MODULE
+        self,
+        record_set: models.BaseModel,
+        module: str | None = _XREF_IMD_MODULE,
+        prefix: str = "",
     ) -> tuple[str, str]:
         """Retrieve an xref pointing to the specified Odoo record; create one
         when missing.
         :param module: Name of the module to use. None to use any name, if no
         xmlid exists "" will be used as the module name.
@@ -51,8 +55,9 @@
     ) -> tuple[str, str]:
         """Retrieve an xref pointing to the specified Odoo record; create one
         when missing.
         :param module: Name of the module to use. None to use any name, if no
         xmlid exists "" will be used as the module name.
+        :param prefix: prefix to use before the name.
         :return: tuple module and name
         """
         record_set.ensure_one()
@@ -63,6 +68,8 @@
         ]
         if module is not None:
             domain.append(("module", "=", module))
+        if prefix:
+            domain.append(("name", "=like", f"{prefix}%"))
 
         # Find an existing xref. See class docstring for details.
         imd = self.sudo().search(domain, limit=1)
@@ -70,7 +77,7 @@
             return imd.module, imd.name
 
         # Could not find an existing xref; create one.
-        name = self.generate_name()
+        name = self.generate_name(prefix)
         if module is None:
             module = ""
         self.set_xmlid(record_set, name, module)
@@ -78,9 +85,12 @@
 
     @api.model
     def object_to_xmlid(
-        self, record_set: models.BaseModel, module: str | None = _XREF_IMD_MODULE
+        self,
+        record_set: models.BaseModel,
+        module: str | None = _XREF_IMD_MODULE,
+        prefix: str = "",
     ) -> str:
         """Retrieve an xref pointing to the specified Odoo record; create one
         when missing.
         :param module: Name of the module to use. None to use any name, if no
         xmlid exists "" will be used as the module name.
@@ -82,7 +92,8 @@
     ) -> str:
         """Retrieve an xref pointing to the specified Odoo record; create one
         when missing.
         :param module: Name of the module to use. None to use any name, if no
         xmlid exists "" will be used as the module name.
+        :param prefix: prefix to use before the name.
         """
         return "{0[0]}.{0[1]}".format(
@@ -87,6 +98,6 @@
         """
         return "{0[0]}.{0[1]}".format(
-            self.object_to_module_and_name(record_set, module)
+            self.object_to_module_and_name(record_set, module, prefix)
         )
 
     @api.model
diff --git a/switch.py b/switch.py
index cdec236693eb2b38992d54bbf240a0aa7b0e55c1_c3dpdGNoLnB5..b4e27f823ace4a230c2cca4b0c95d6a4c8019b20_c3dpdGNoLnB5 100644
--- a/switch.py
+++ b/switch.py
@@ -22,7 +22,15 @@
 
 from odoo import api, models  # type: ignore[import-untyped]
 
-from .base import Context, ContextBuilder, Converter, NewinstanceType, Skip, SkipType
+from .base import (
+    Context,
+    ContextBuilder,
+    Converter,
+    NewinstanceType,
+    PostHookConverter,
+    Skip,
+    SkipType,
+)
 from .validate import Validation, Validator
 
 
@@ -26,7 +34,7 @@
 from .validate import Validation, Validator
 
 
-class Switch(Converter):
+class Switch(PostHookConverter):
     """A converter to handle switch cases.
     A list of converters are provided with a function. The first function to
     match is used, any function that is None will be used.
@@ -157,3 +165,10 @@
             if out_cond is None or out_cond(instance):
                 return converter.odoo_datatype(instance)
         return super().odoo_datatype(instance)
+
+    def post_hook(self, instance: models.BaseModel, message_data):
+        for _out_cond, in_cond, converter in self._converters:
+            if in_cond is None or in_cond(message_data):
+                if hasattr(converter, "post_hook"):
+                    converter.post_hook(instance, message_data)
+                return
diff --git a/tests/test_converters.py b/tests/test_converters.py
index cdec236693eb2b38992d54bbf240a0aa7b0e55c1_dGVzdHMvdGVzdF9jb252ZXJ0ZXJzLnB5..b4e27f823ace4a230c2cca4b0c95d6a4c8019b20_dGVzdHMvdGVzdF9jb252ZXJ0ZXJzLnB5 100644
--- a/tests/test_converters.py
+++ b/tests/test_converters.py
@@ -100,8 +100,8 @@
         return Model(
             # TODO add a schema to test validation
             {
-                "id": Xref(),
+                "id": Xref(include_module_name=True),
                 "country_code": RelationToOne(
                     "country_id", None, KeyField("code", "res.country")
                 ),
                 "name": Field("name"),
@@ -104,8 +104,10 @@
                 "country_code": RelationToOne(
                     "country_id", None, KeyField("code", "res.country")
                 ),
                 "name": Field("name"),
-                "partner_id": RelationToOne("partner_id", "res.partner", Xref()),
+                "partner_id": RelationToOne(
+                    "partner_id", "res.partner", Xref(include_module_name=True)
+                ),
             },
             __type__="test-type",
         )
diff --git a/tests/test_relation.py b/tests/test_relation.py
index cdec236693eb2b38992d54bbf240a0aa7b0e55c1_dGVzdHMvdGVzdF9yZWxhdGlvbi5weQ==..b4e27f823ace4a230c2cca4b0c95d6a4c8019b20_dGVzdHMvdGVzdF9yZWxhdGlvbi5weQ== 100644
--- a/tests/test_relation.py
+++ b/tests/test_relation.py
@@ -1,7 +1,7 @@
 ##############################################################################
 #
 #    Converter Odoo module
-#    Copyright © 2021, 2024 XCG Consulting <https://xcg-consulting.fr>
+#    Copyright © 2021, 2024, 2025 XCG Consulting <https://xcg-consulting.fr>
 #
 #    This program is free software: you can redistribute it and/or modify
 #    it under the terms of the GNU Affero General Public License as
@@ -36,7 +36,9 @@
     @classmethod
     def setUpClass(cls) -> None:
         super().setUpClass()
-        cls.converter1 = RelationToOne("company_id", "res.company", Xref(None))
+        cls.converter1 = RelationToOne(
+            "company_id", "res.company", Xref(None, prefix="main_")
+        )
         cls.converter2 = RelationToOne("action_id", "res.company", Xref(None))
         cls.converter3 = RelationToOne(
             "action_id", "res.company", Xref(None), send_empty=False
@@ -52,5 +54,5 @@
 
     def test_many2one_from_odoo(self):
         message = self.converter1.odoo_to_message(self.user_admin)
-        self.assertEqual(message, "base.main_company")
+        self.assertEqual(message, "company")
         message = self.converter1.odoo_to_message(self.user_root)
@@ -56,5 +58,5 @@
         message = self.converter1.odoo_to_message(self.user_root)
-        self.assertEqual(message, "base.main_company")
+        self.assertEqual(message, "company")
 
     def test_many2one_skip_from_odoo(self):
         message = self.converter4.odoo_to_message(self.user_admin)
@@ -58,7 +60,7 @@
 
     def test_many2one_skip_from_odoo(self):
         message = self.converter4.odoo_to_message(self.user_admin)
-        self.assertEqual(message, "base.main_company")
+        self.assertEqual(message, "main_company")
 
     def test_empty_many2one_from_odoo(self):
         message = self.converter2.odoo_to_message(self.user_root)
diff --git a/xref.py b/xref.py
index cdec236693eb2b38992d54bbf240a0aa7b0e55c1_eHJlZi5weQ==..b4e27f823ace4a230c2cca4b0c95d6a4c8019b20_eHJlZi5weQ== 100644
--- a/xref.py
+++ b/xref.py
@@ -19,7 +19,8 @@
 ##############################################################################
 import logging
 import os
-from typing import Any
+import uuid
+from typing import Any, Final
 
 from odoo import _, api, models  # type: ignore[import-untyped]
 
@@ -43,5 +44,9 @@
     """
 
     def __init__(
-        self, module: str | None = _XREF_IMD_MODULE, is_instance_getter: bool = True
+        self,
+        module: str | None = _XREF_IMD_MODULE,
+        is_instance_getter: bool = True,
+        include_module_name: bool = False,
+        prefix: str = "",
     ):
@@ -47,4 +52,8 @@
     ):
+        """
+        :param prefix: prefix to use in ir.model.data, nor sent nor received.
+          Used to prevent duplication if received id is too simple.
+        """
         super().__init__()
         self._module = module
         self._is_instance_getter = is_instance_getter
@@ -48,7 +57,9 @@
         super().__init__()
         self._module = module
         self._is_instance_getter = is_instance_getter
+        self._include_module_name: Final[bool] = include_module_name
+        self._prefix: Final[str] = prefix
 
     def odoo_to_message(self, instance: models.BaseModel, ctx: Context = None) -> Any:
         if not instance:
             return ""
@@ -51,7 +62,7 @@
 
     def odoo_to_message(self, instance: models.BaseModel, ctx: Context = None) -> Any:
         if not instance:
             return ""
-        return instance.env["ir.model.data"].object_to_xmlid(
-            instance, module=self._module
+        module, name = instance.env["ir.model.data"].object_to_module_and_name(
+            instance, self._module, self._prefix
         )
@@ -57,6 +68,11 @@
         )
+        if self._prefix is not None:
+            name = name[len(self._prefix) :]
+        if self._include_module_name:
+            return f"{module}.{name}"
+        return name
 
     def get_instance(
         self, odoo_env: api.Environment, message_data
     ) -> models.BaseModel | NewinstanceType | None:
         if self._is_instance_getter:
@@ -58,6 +74,7 @@
 
     def get_instance(
         self, odoo_env: api.Environment, message_data
     ) -> models.BaseModel | NewinstanceType | None:
         if self._is_instance_getter:
+            module, name = self._module_name(message_data)
             return odoo_env.ref(
@@ -63,8 +80,8 @@
             return odoo_env.ref(
-                ".".join(["" if self._module is None else self._module, message_data]),
+                f"{module}.{name}",
                 raise_if_not_found=False,
             )
         return None
 
     def post_hook(self, instance: models.BaseModel, message_data):
         # add xmlid to the newly created object
@@ -65,7 +82,8 @@
                 raise_if_not_found=False,
             )
         return None
 
     def post_hook(self, instance: models.BaseModel, message_data):
         # add xmlid to the newly created object
+        module, name = self._module_name(message_data)
         instance.env["ir.model.data"].set_xmlid(
@@ -71,4 +89,4 @@
         instance.env["ir.model.data"].set_xmlid(
-            instance, message_data, module=self._module, only_when_missing=True
+            instance, name, module=module, only_when_missing=True
         )
 
@@ -73,5 +91,16 @@
         )
 
+    def _module_name(self, value: str) -> tuple[str, str]:
+        """Return module and name depending on options"""
+        module = "" if self._module is None else self._module
+        name = value
+        if self._include_module_name:
+            module, name = value.split(".", 1)
+            assert module == self._module
+        if self._prefix is not None:
+            name = self._prefix + name
+        return module, name
+
     @property
     def is_instance_getter(self) -> bool:
         return self._is_instance_getter
@@ -115,4 +144,16 @@
         if not instance:
             return ""
 
+        imds = (
+            instance.env["ir.model.data"]
+            .sudo()
+            .search(
+                [
+                    ("module", "=", self._module),
+                    ("model", "=", instance._name),
+                    ("res_id", "=", instance.id),
+                ]
+            )
+        )
+
         ctx = build_context(instance, ctx, self._context)
@@ -118,11 +159,4 @@
         ctx = build_context(instance, ctx, self._context)
-        if self._unique_id_field is not None:
-            name = getattr(instance, self._unique_id_field)
-        else:
-            _module, name = instance.env["ir.model.data"].object_to_module_and_name(
-                instance, self._module
-            )
-
         jsonld_id_base_url = (
             instance.env["ir.config_parameter"]
             .sudo()
@@ -137,6 +171,7 @@
         if self.converter is not None:
             self._breadcrumb = self.converter.odoo_to_message(instance, ctx)
 
-        xref = os.path.join(
+        # xref does not exist or does not match the jsonld expected format, create it
+        schema_base = os.path.join(
             jsonld_id_base_url if self._has_base_url else "",
             self._breadcrumb if self._breadcrumb is not None else "",
@@ -141,4 +176,3 @@
             jsonld_id_base_url if self._has_base_url else "",
             self._breadcrumb if self._breadcrumb is not None else "",
-            name,
         )
@@ -144,5 +178,7 @@
         )
-        instance.env["ir.model.data"].set_xmlid(
-            instance, xref, module=self._module, only_when_missing=True
-        )
+        if not imds or all(not imd.name.startswith(schema_base) for imd in imds):
+            if self._unique_id_field is not None:
+                name = getattr(instance, self._unique_id_field)
+            else:
+                name = uuid.uuid4().hex
 
@@ -148,19 +184,8 @@
 
-        # In case of jsonld_id, replace the xref generated by
-        # `object_to_module_and_name` with jsonld format.
-        if self._has_base_url:
-            # Need sudo as typical user does not have the rights on ir.model.data
-            imd = (
-                instance.env["ir.model.data"]
-                .sudo()
-                .search(
-                    [
-                        ("module", "=", self._module),
-                        ("model", "=", instance._name),
-                        ("res_id", "=", instance.id),
-                    ]
-                )
-            )
-            imd.write({"name": xref})
-
+            xref = os.path.join(schema_base, name)
+            instance.env["ir.model.data"].set_xmlid(instance, xref, module=self._module)
+        else:
+            for imd in imds:
+                if imd.name.startswith(schema_base):
+                    xref = imd.name
         return xref