From 185958391e14846b2cea59e59129545eedc9fd85 Mon Sep 17 00:00:00 2001 From: Cyril VINH-TUNG Date: Fri, 29 May 2026 14:42:22 -1000 Subject: [PATCH] [ADD] event_multi_company module. It allows to share events between several companies --- event_multi_company/README.rst | 137 +++++ event_multi_company/__init__.py | 2 + event_multi_company/__manifest__.py | 22 + event_multi_company/hooks.py | 15 + event_multi_company/models/__init__.py | 1 + event_multi_company/models/event_event.py | 9 + event_multi_company/pyproject.toml | 3 + event_multi_company/readme/CONTRIBUTORS.md | 2 + event_multi_company/readme/DESCRIPTION.md | 15 + event_multi_company/readme/INSTALL.md | 8 + event_multi_company/readme/ROADMAP.md | 5 + event_multi_company/readme/USAGE.md | 15 + .../static/description/index.html | 483 ++++++++++++++++++ event_multi_company/tests/__init__.py | 1 + .../tests/test_event_multi_company.py | 53 ++ .../views/event_event_view.xml | 27 + 16 files changed, 798 insertions(+) create mode 100644 event_multi_company/README.rst create mode 100644 event_multi_company/__init__.py create mode 100644 event_multi_company/__manifest__.py create mode 100644 event_multi_company/hooks.py create mode 100644 event_multi_company/models/__init__.py create mode 100644 event_multi_company/models/event_event.py create mode 100644 event_multi_company/pyproject.toml create mode 100644 event_multi_company/readme/CONTRIBUTORS.md create mode 100644 event_multi_company/readme/DESCRIPTION.md create mode 100644 event_multi_company/readme/INSTALL.md create mode 100644 event_multi_company/readme/ROADMAP.md create mode 100644 event_multi_company/readme/USAGE.md create mode 100644 event_multi_company/static/description/index.html create mode 100644 event_multi_company/tests/__init__.py create mode 100644 event_multi_company/tests/test_event_multi_company.py create mode 100644 event_multi_company/views/event_event_view.xml diff --git a/event_multi_company/README.rst b/event_multi_company/README.rst new file mode 100644 index 00000000000..90ee6bd39d8 --- /dev/null +++ b/event_multi_company/README.rst @@ -0,0 +1,137 @@ +=================== +Event multi-company +=================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:524e7b296f4a97a0517a2be5dc2b3fc66fb4f5ae691ceb9c2401f46d263783d5 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fmulti--company-lightgray.png?logo=github + :target: https://github.com/OCA/multi-company/tree/18.0/event_multi_company + :alt: OCA/multi-company +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/multi-company-18-0/multi-company-18-0-event_multi_company + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/multi-company&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Based on ``base_multi_company`` module. Adds a ``company_ids`` Many2many +on ``event.event`` so an event can be assigned to several companies at +once. The standard ``company_id`` field becomes a computed/searched +proxy over ``company_ids`` via ``multi.company.abstract``. + +Backend visibility is handled transparently by Odoo's standard +multi-company record rule on ``event.event``, which +``multi.company.abstract`` automatically reroutes through +``company_ids``. + +If the optional ``website_event`` module is installed, the same rule +applies to the public ``/event`` listing on each website: an event is +only displayed on the websites of the companies listed in its +``company_ids``. No bridge module is needed. + +Same pattern as ``product_multi_company`` and ``partner_multi_company``. + +**Table of contents** + +.. contents:: + :local: + +Installation +============ + +Depends on ``base_multi_company`` (OCA/multi-company) and ``event`` +(core). + +A ``post_init_hook`` copies each event's existing ``company_id`` into +the new ``company_ids`` field, so pre-existing events keep their +visibility. + +Uninstall does **not** automatically restore the upstream ``company_id`` +behaviour. Run ``-u event`` afterwards (or restore from a backup) to +fully revert. + +Usage +===== + +On the event form, the standard *Company* field is replaced by a +*Companies* many2many tags field (visible to users of the *Multi +Companies* group). + +- Leave it empty → event accessible from every company (legacy + behaviour). +- Pick one or several companies → event accessible only to users of + those companies. + +If the ``website_event`` module is installed: + +- An event with empty ``company_ids`` is displayed on every website. +- An event with one or more companies is only displayed on the websites + of those companies. +- If you also set the per-event *Website* field, the event is restricted + to that single website. The website's company must be one of the + event's companies (upstream constraint). + +Known issues / Roadmap +====================== + +- ``event.registration`` is not multi-company. A future + ``event_registration_multi_company`` companion module would extend the + same pattern. +- Other OCA event addons (``event_session``, ``event_sale_session``, + etc.) are not audited for compatibility. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* INVITU + +Contributors +------------ + +- `INVITU `__: + + - Cyril VINH-TUNG + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/multi-company `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/event_multi_company/__init__.py b/event_multi_company/__init__.py new file mode 100644 index 00000000000..cc6b6354ad8 --- /dev/null +++ b/event_multi_company/__init__.py @@ -0,0 +1,2 @@ +from . import models +from .hooks import post_init_hook diff --git a/event_multi_company/__manifest__.py b/event_multi_company/__manifest__.py new file mode 100644 index 00000000000..a355c952732 --- /dev/null +++ b/event_multi_company/__manifest__.py @@ -0,0 +1,22 @@ +# Copyright 2026 INVITU () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Event multi-company", + "summary": "Assign an event to several companies (backend only).", + "version": "18.0.1.0.0", + "license": "AGPL-3", + "author": "INVITU, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/multi-company", + "category": "Marketing", + "depends": [ + "base_multi_company", + "event", + ], + "data": [ + "views/event_event_view.xml", + ], + "post_init_hook": "post_init_hook", + "installable": True, + "application": False, +} diff --git a/event_multi_company/hooks.py b/event_multi_company/hooks.py new file mode 100644 index 00000000000..559470344af --- /dev/null +++ b/event_multi_company/hooks.py @@ -0,0 +1,15 @@ +# Copyright 2026 INVITU () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import logging + +_logger = logging.getLogger(__name__) + +try: + from odoo.addons.base_multi_company import hooks +except ImportError: + _logger.info("Cannot find `base_multi_company` module in addons path.") + + +def post_init_hook(env): + hooks.fill_company_ids(env, "event.event") diff --git a/event_multi_company/models/__init__.py b/event_multi_company/models/__init__.py new file mode 100644 index 00000000000..b6bc3899716 --- /dev/null +++ b/event_multi_company/models/__init__.py @@ -0,0 +1 @@ +from . import event_event diff --git a/event_multi_company/models/event_event.py b/event_multi_company/models/event_event.py new file mode 100644 index 00000000000..568ffb80ebd --- /dev/null +++ b/event_multi_company/models/event_event.py @@ -0,0 +1,9 @@ +# Copyright 2026 INVITU () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models + + +class EventEvent(models.Model): + _inherit = ["multi.company.abstract", "event.event"] + _name = "event.event" diff --git a/event_multi_company/pyproject.toml b/event_multi_company/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/event_multi_company/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/event_multi_company/readme/CONTRIBUTORS.md b/event_multi_company/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..49ee8c364ac --- /dev/null +++ b/event_multi_company/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +- [INVITU](https://www.invitu.com): + - Cyril VINH-TUNG \<\> diff --git a/event_multi_company/readme/DESCRIPTION.md b/event_multi_company/readme/DESCRIPTION.md new file mode 100644 index 00000000000..bd7f522ad33 --- /dev/null +++ b/event_multi_company/readme/DESCRIPTION.md @@ -0,0 +1,15 @@ +Based on ``base_multi_company`` module. +Adds a ``company_ids`` Many2many on ``event.event`` so an event can be assigned +to several companies at once. The standard ``company_id`` field becomes a +computed/searched proxy over ``company_ids`` via ``multi.company.abstract``. + +Backend visibility is handled transparently by Odoo's standard multi-company +record rule on ``event.event``, which ``multi.company.abstract`` automatically +reroutes through ``company_ids``. + +If the optional ``website_event`` module is installed, the same rule applies +to the public ``/event`` listing on each website: an event is only displayed +on the websites of the companies listed in its ``company_ids``. No bridge +module is needed. + +Same pattern as ``product_multi_company`` and ``partner_multi_company``. diff --git a/event_multi_company/readme/INSTALL.md b/event_multi_company/readme/INSTALL.md new file mode 100644 index 00000000000..26250f8d3a0 --- /dev/null +++ b/event_multi_company/readme/INSTALL.md @@ -0,0 +1,8 @@ +Depends on ``base_multi_company`` (OCA/multi-company) and ``event`` (core). + +A ``post_init_hook`` copies each event's existing ``company_id`` into the new +``company_ids`` field, so pre-existing events keep their visibility. + +Uninstall does **not** automatically restore the upstream ``company_id`` +behaviour. Run ``-u event`` afterwards (or restore from a backup) to fully +revert. diff --git a/event_multi_company/readme/ROADMAP.md b/event_multi_company/readme/ROADMAP.md new file mode 100644 index 00000000000..6e1b5608e93 --- /dev/null +++ b/event_multi_company/readme/ROADMAP.md @@ -0,0 +1,5 @@ +* ``event.registration`` is not multi-company. A future + ``event_registration_multi_company`` companion module would extend the same + pattern. +* Other OCA event addons (``event_session``, ``event_sale_session``, etc.) are + not audited for compatibility. diff --git a/event_multi_company/readme/USAGE.md b/event_multi_company/readme/USAGE.md new file mode 100644 index 00000000000..ebd56d5b32e --- /dev/null +++ b/event_multi_company/readme/USAGE.md @@ -0,0 +1,15 @@ +On the event form, the standard *Company* field is replaced by a *Companies* +many2many tags field (visible to users of the *Multi Companies* group). + +* Leave it empty → event accessible from every company (legacy behaviour). +* Pick one or several companies → event accessible only to users of those + companies. + +If the ``website_event`` module is installed: + +* An event with empty ``company_ids`` is displayed on every website. +* An event with one or more companies is only displayed on the websites of + those companies. +* If you also set the per-event *Website* field, the event is restricted to + that single website. The website's company must be one of the event's + companies (upstream constraint). diff --git a/event_multi_company/static/description/index.html b/event_multi_company/static/description/index.html new file mode 100644 index 00000000000..5ea110a2ac3 --- /dev/null +++ b/event_multi_company/static/description/index.html @@ -0,0 +1,483 @@ + + + + + +Event multi-company + + + +
+

Event multi-company

+ + +

Beta License: AGPL-3 OCA/multi-company Translate me on Weblate Try me on Runboat

+

Based on base_multi_company module. Adds a company_ids Many2many +on event.event so an event can be assigned to several companies at +once. The standard company_id field becomes a computed/searched +proxy over company_ids via multi.company.abstract.

+

Backend visibility is handled transparently by Odoo’s standard +multi-company record rule on event.event, which +multi.company.abstract automatically reroutes through +company_ids.

+

If the optional website_event module is installed, the same rule +applies to the public /event listing on each website: an event is +only displayed on the websites of the companies listed in its +company_ids. No bridge module is needed.

+

Same pattern as product_multi_company and partner_multi_company.

+

Table of contents

+ +
+

Installation

+

Depends on base_multi_company (OCA/multi-company) and event +(core).

+

A post_init_hook copies each event’s existing company_id into +the new company_ids field, so pre-existing events keep their +visibility.

+

Uninstall does not automatically restore the upstream company_id +behaviour. Run -u event afterwards (or restore from a backup) to +fully revert.

+
+
+

Usage

+

On the event form, the standard Company field is replaced by a +Companies many2many tags field (visible to users of the Multi +Companies group).

+
    +
  • Leave it empty → event accessible from every company (legacy +behaviour).
  • +
  • Pick one or several companies → event accessible only to users of +those companies.
  • +
+

If the website_event module is installed:

+
    +
  • An event with empty company_ids is displayed on every website.
  • +
  • An event with one or more companies is only displayed on the websites +of those companies.
  • +
  • If you also set the per-event Website field, the event is restricted +to that single website. The website’s company must be one of the +event’s companies (upstream constraint).
  • +
+
+
+

Known issues / Roadmap

+
    +
  • event.registration is not multi-company. A future +event_registration_multi_company companion module would extend the +same pattern.
  • +
  • Other OCA event addons (event_session, event_sale_session, +etc.) are not audited for compatibility.
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • INVITU
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/multi-company project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/event_multi_company/tests/__init__.py b/event_multi_company/tests/__init__.py new file mode 100644 index 00000000000..bd6cfa6d3a2 --- /dev/null +++ b/event_multi_company/tests/__init__.py @@ -0,0 +1 @@ +from . import test_event_multi_company diff --git a/event_multi_company/tests/test_event_multi_company.py b/event_multi_company/tests/test_event_multi_company.py new file mode 100644 index 00000000000..73caf5a78f9 --- /dev/null +++ b/event_multi_company/tests/test_event_multi_company.py @@ -0,0 +1,53 @@ +# Copyright 2026 INVITU () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from datetime import timedelta + +from odoo import fields +from odoo.tests import common, tagged + + +@tagged("post_install", "-at_install") +class TestEventMultiCompany(common.TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.event_obj = cls.env["event.event"] + cls.company_1 = cls.env["res.company"].create({"name": "Test company 1"}) + + def _make_event_vals(self, name): + today = fields.Datetime.now() + return { + "name": name, + "date_begin": today + timedelta(days=10), + "date_end": today + timedelta(days=11), + "date_tz": "UTC", + } + + def test_inherit_multi_company_abstract(self): + # event.event has been mixed with multi.company.abstract: the M2M + # company_ids field exists and company_id is now computed. + self.assertIn("company_ids", self.event_obj._fields) + self.assertTrue(self.event_obj._fields["company_id"].compute) + + def test_create_with_company_id_populates_company_ids(self): + # The abstract's inverse copies company_id into company_ids on create. + event = self.event_obj.create( + {**self._make_event_vals("Test"), "company_id": self.company_1.id} + ) + self.assertEqual(event.company_ids, self.company_1) + + def test_post_init_hook(self): + # hooks.post_init_hook delegates to base_multi_company.fill_company_ids. + # Running it on a freshly created event is a no-op (company_ids + # already populated by the abstract's inverse) but exercises the + # imports and the function call. + from ..hooks import post_init_hook + + event = self.event_obj.create( + {**self._make_event_vals("Hooked"), "company_id": self.company_1.id} + ) + post_init_hook(self.env) + event.invalidate_recordset(["company_ids"]) + self.assertIn(self.company_1, event.company_ids) diff --git a/event_multi_company/views/event_event_view.xml b/event_multi_company/views/event_event_view.xml new file mode 100644 index 00000000000..a0b55933f94 --- /dev/null +++ b/event_multi_company/views/event_event_view.xml @@ -0,0 +1,27 @@ + + + + event.event.form (multi-company) + event.event + + + + 1 + + + + + + +