From 0cf9cc093bc41c9085104e8e248ef0418f656313 Mon Sep 17 00:00:00 2001 From: Don Kendall Date: Tue, 19 May 2026 14:56:46 -0400 Subject: [PATCH 1/2] [ADD] resource_booking_google_meet --- resource_booking_google_meet/README.rst | 111 +++++ resource_booking_google_meet/__init__.py | 1 + resource_booking_google_meet/__manifest__.py | 16 + .../models/__init__.py | 1 + .../models/resource_booking.py | 26 + resource_booking_google_meet/pyproject.toml | 7 + .../readme/CONTRIBUTORS.md | 1 + .../readme/DESCRIPTION.md | 18 + .../readme/HISTORY.md | 3 + .../static/description/index.html | 455 ++++++++++++++++++ .../tests/__init__.py | 3 + .../test_resource_booking_google_meet.py | 46 ++ 12 files changed, 688 insertions(+) create mode 100644 resource_booking_google_meet/README.rst create mode 100644 resource_booking_google_meet/__init__.py create mode 100644 resource_booking_google_meet/__manifest__.py create mode 100644 resource_booking_google_meet/models/__init__.py create mode 100644 resource_booking_google_meet/models/resource_booking.py create mode 100644 resource_booking_google_meet/pyproject.toml create mode 100644 resource_booking_google_meet/readme/CONTRIBUTORS.md create mode 100644 resource_booking_google_meet/readme/DESCRIPTION.md create mode 100644 resource_booking_google_meet/readme/HISTORY.md create mode 100644 resource_booking_google_meet/static/description/index.html create mode 100644 resource_booking_google_meet/tests/__init__.py create mode 100644 resource_booking_google_meet/tests/test_resource_booking_google_meet.py diff --git a/resource_booking_google_meet/README.rst b/resource_booking_google_meet/README.rst new file mode 100644 index 00000000..450f2ee3 --- /dev/null +++ b/resource_booking_google_meet/README.rst @@ -0,0 +1,111 @@ +========================================= +Resource Booking — Google Meet by default +========================================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:66ab976030b2bfcdaf7512ab210cee2e58ca838b4678ba56f059477473bf9d9c + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Fcalendar-lightgray.png?logo=github + :target: https://github.com/OCA/calendar/tree/18.0/resource_booking_google_meet + :alt: OCA/calendar +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/calendar-18-0/calendar-18-0-resource_booking_google_meet + :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/calendar&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +When a ``resource.booking`` is confirmed it creates a +``calendar.event``. This module ensures the ``google_calendar`` +integration auto-generates a unique Google Meet URL per booking — with +recording, "Take notes for me" Gemini summaries, and transcripts on +Google Workspace Business Standard and above. + +**How it works:** ``google_calendar`` adds conferencing to an event when +both ``videocall_location`` and ``location`` are empty on the event at +sync time. If the booking type has a physical address set, this module +clears ``location`` from the meeting vals so the conferencing condition +is always satisfied for bookings without a custom videocall URL. + +If the booking type has an explicit ``videocall_location`` (e.g. a +static Zoom personal room), the module leaves everything unchanged — the +static URL is preserved and Google won't add conferencing. + + **Note:** The Meet URL only appears after the first + ``google_calendar`` cron sync. The ``videocall_location`` field on + the calendar event is updated automatically once Google returns the + conferencing details. + +**Table of contents** + +.. contents:: + :local: + +Changelog +========= + +18.0.1.0.0 (2026-05-19) +----------------------- + +- [ADD] New module: default resource bookings to Google Meet videocall + +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 +------- + +* Ledo Enterprises + +Contributors +------------ + +- Don Kendall dkendall@ledoweb.com + +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. + +.. |maintainer-dnplkndll| image:: https://github.com/dnplkndll.png?size=40px + :target: https://github.com/dnplkndll + :alt: dnplkndll + +Current `maintainer `__: + +|maintainer-dnplkndll| + +This module is part of the `OCA/calendar `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/resource_booking_google_meet/__init__.py b/resource_booking_google_meet/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/resource_booking_google_meet/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/resource_booking_google_meet/__manifest__.py b/resource_booking_google_meet/__manifest__.py new file mode 100644 index 00000000..fa85b1cb --- /dev/null +++ b/resource_booking_google_meet/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2026 Ledo Enterprises - D. Kendall +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Resource Booking — Google Meet by default", + "version": "18.0.1.0.0", + "category": "Marketing/Online Appointment", + "summary": "Default new resource bookings to Google Meet for the videocall", + "author": "Ledo Enterprises, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/calendar", + "license": "AGPL-3", + "depends": ["resource_booking", "google_calendar"], + "data": [], + "installable": True, + "auto_install": False, + "maintainers": ["dnplkndll"], +} diff --git a/resource_booking_google_meet/models/__init__.py b/resource_booking_google_meet/models/__init__.py new file mode 100644 index 00000000..3efd32e8 --- /dev/null +++ b/resource_booking_google_meet/models/__init__.py @@ -0,0 +1 @@ +from . import resource_booking diff --git a/resource_booking_google_meet/models/resource_booking.py b/resource_booking_google_meet/models/resource_booking.py new file mode 100644 index 00000000..5cde23ad --- /dev/null +++ b/resource_booking_google_meet/models/resource_booking.py @@ -0,0 +1,26 @@ +# Copyright 2026 Ledo Enterprises - D. Kendall +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import models + + +class ResourceBooking(models.Model): + _inherit = "resource.booking" + + def _prepare_meeting_vals(self): + """Ensure google_calendar generates a per-booking Meet URL. + + Behaviour: + - Booking type with no videocall_location → clear location on the event + so google_calendar's _google_values() satisfies `not location` and sends + conferenceData to Google, which returns a unique meet.google.com URL. + - Booking type with a videocall_location URL → leave everything unchanged; + the static URL (Zoom, Whereby, etc.) is preserved and Google won't add + conferencing because videocall_location is already non-empty. + """ + vals = super()._prepare_meeting_vals() + if not vals.get("videocall_location"): + # google_calendar only requests a Meet URL when both videocall_location + # and location are falsy on the event. Clear location here so the sync + # condition passes even when the booking type has a physical address. + vals["location"] = False + return vals diff --git a/resource_booking_google_meet/pyproject.toml b/resource_booking_google_meet/pyproject.toml new file mode 100644 index 00000000..5cd673ae --- /dev/null +++ b/resource_booking_google_meet/pyproject.toml @@ -0,0 +1,7 @@ +[project] +name = "odoo-addon-resource-booking-google-meet" +version = "18.0.1.0.0" + +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/resource_booking_google_meet/readme/CONTRIBUTORS.md b/resource_booking_google_meet/readme/CONTRIBUTORS.md new file mode 100644 index 00000000..9e17a5fc --- /dev/null +++ b/resource_booking_google_meet/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +- Don Kendall diff --git a/resource_booking_google_meet/readme/DESCRIPTION.md b/resource_booking_google_meet/readme/DESCRIPTION.md new file mode 100644 index 00000000..b6aa971a --- /dev/null +++ b/resource_booking_google_meet/readme/DESCRIPTION.md @@ -0,0 +1,18 @@ +When a `resource.booking` is confirmed it creates a `calendar.event`. This module +ensures the `google_calendar` integration auto-generates a unique Google Meet URL per +booking — with recording, "Take notes for me" Gemini summaries, and transcripts on +Google Workspace Business Standard and above. + +**How it works:** `google_calendar` adds conferencing to an event when both +`videocall_location` and `location` are empty on the event at sync time. If the booking +type has a physical address set, this module clears `location` from the meeting vals so +the conferencing condition is always satisfied for bookings without a custom videocall +URL. + +If the booking type has an explicit `videocall_location` (e.g. a static Zoom personal +room), the module leaves everything unchanged — the static URL is preserved and Google +won't add conferencing. + +> **Note:** The Meet URL only appears after the first `google_calendar` cron sync. +> The `videocall_location` field on the calendar event is updated automatically once +> Google returns the conferencing details. diff --git a/resource_booking_google_meet/readme/HISTORY.md b/resource_booking_google_meet/readme/HISTORY.md new file mode 100644 index 00000000..06a13975 --- /dev/null +++ b/resource_booking_google_meet/readme/HISTORY.md @@ -0,0 +1,3 @@ +## 18.0.1.0.0 (2026-05-19) + +- \[ADD\] New module: default resource bookings to Google Meet videocall diff --git a/resource_booking_google_meet/static/description/index.html b/resource_booking_google_meet/static/description/index.html new file mode 100644 index 00000000..d7bed6ed --- /dev/null +++ b/resource_booking_google_meet/static/description/index.html @@ -0,0 +1,455 @@ + + + + + +Resource Booking — Google Meet by default + + + +
+

Resource Booking — Google Meet by default

+ + +

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

+

When a resource.booking is confirmed it creates a +calendar.event. This module ensures the google_calendar +integration auto-generates a unique Google Meet URL per booking — with +recording, “Take notes for me” Gemini summaries, and transcripts on +Google Workspace Business Standard and above.

+

How it works: google_calendar adds conferencing to an event when +both videocall_location and location are empty on the event at +sync time. If the booking type has a physical address set, this module +clears location from the meeting vals so the conferencing condition +is always satisfied for bookings without a custom videocall URL.

+

If the booking type has an explicit videocall_location (e.g. a +static Zoom personal room), the module leaves everything unchanged — the +static URL is preserved and Google won’t add conferencing.

+
+Note: The Meet URL only appears after the first +google_calendar cron sync. The videocall_location field on +the calendar event is updated automatically once Google returns the +conferencing details.
+

Table of contents

+ +
+

Changelog

+
+

18.0.1.0.0 (2026-05-19)

+
    +
  • [ADD] New module: default resource bookings to Google Meet videocall
  • +
+
+
+
+

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

+
    +
  • Ledo Enterprises
  • +
+
+
+

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.

+

Current maintainer:

+

dnplkndll

+

This module is part of the OCA/calendar project on GitHub.

+

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

+
+
+
+ + diff --git a/resource_booking_google_meet/tests/__init__.py b/resource_booking_google_meet/tests/__init__.py new file mode 100644 index 00000000..ba3ae65a --- /dev/null +++ b/resource_booking_google_meet/tests/__init__.py @@ -0,0 +1,3 @@ +# Copyright 2026 Ledo Enterprises - D. Kendall +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from . import test_resource_booking_google_meet diff --git a/resource_booking_google_meet/tests/test_resource_booking_google_meet.py b/resource_booking_google_meet/tests/test_resource_booking_google_meet.py new file mode 100644 index 00000000..f336b484 --- /dev/null +++ b/resource_booking_google_meet/tests/test_resource_booking_google_meet.py @@ -0,0 +1,46 @@ +# Copyright 2026 Ledo Enterprises - D. Kendall +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.tests.common import TransactionCase + + +class TestResourceBookingGoogleMeet(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.booking_type = cls.env["resource.booking.type"].create( + { + "name": "Test Booking Type", + "location": "123 Main St", + } + ) + + def test_prepare_meeting_vals_clears_location_when_no_videocall(self): + """location is cleared so google_calendar adds conferencing.""" + booking = self.env["resource.booking"].create( + { + "type_id": self.booking_type.id, + "partner_ids": [(4, self.env.ref("base.partner_demo").id)], + } + ) + vals = booking._prepare_meeting_vals() + self.assertFalse( + vals.get("location"), + "location must be falsy so google_calendar requests a Meet URL", + ) + + def test_prepare_meeting_vals_preserves_videocall_location(self): + """Static videocall_location (e.g. Zoom) is left unchanged.""" + self.booking_type.videocall_location = "https://zoom.us/j/123456" + booking = self.env["resource.booking"].create( + { + "type_id": self.booking_type.id, + "partner_ids": [(4, self.env.ref("base.partner_demo").id)], + } + ) + vals = booking._prepare_meeting_vals() + self.assertEqual( + vals.get("videocall_location"), + "https://zoom.us/j/123456", + "Static videocall_location must be preserved", + ) From ace94414c60f4fd14f5f059a9ca495c4535ca985 Mon Sep 17 00:00:00 2001 From: Don Kendall Date: Tue, 19 May 2026 17:52:52 -0400 Subject: [PATCH 2/2] [ADD] resource_booking_google_meet: send Meet link email when Google Calendar syncs --- resource_booking_google_meet/__manifest__.py | 2 +- .../data/mail_template_meet_link.xml | 87 +++++++++++++++++++ .../models/__init__.py | 1 + .../models/calendar_event.py | 29 +++++++ 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 resource_booking_google_meet/data/mail_template_meet_link.xml create mode 100644 resource_booking_google_meet/models/calendar_event.py diff --git a/resource_booking_google_meet/__manifest__.py b/resource_booking_google_meet/__manifest__.py index fa85b1cb..94fe127f 100644 --- a/resource_booking_google_meet/__manifest__.py +++ b/resource_booking_google_meet/__manifest__.py @@ -9,7 +9,7 @@ "website": "https://github.com/OCA/calendar", "license": "AGPL-3", "depends": ["resource_booking", "google_calendar"], - "data": [], + "data": ["data/mail_template_meet_link.xml"], "installable": True, "auto_install": False, "maintainers": ["dnplkndll"], diff --git a/resource_booking_google_meet/data/mail_template_meet_link.xml b/resource_booking_google_meet/data/mail_template_meet_link.xml new file mode 100644 index 00000000..1704254d --- /dev/null +++ b/resource_booking_google_meet/data/mail_template_meet_link.xml @@ -0,0 +1,87 @@ + + + + Resource Booking: Google Meet link ready + + Your Google Meet link — {{ object.type_id.name }} + {{ ','.join([p.email for p in object.partner_ids if p.email]) }} + + +
+
+
+

Your Google Meet link is ready

+
+ +
+

+ Hi {{ object.partner_ids[:1].name or 'there' }},

+ Your meeting room for {{ object.type_id.name }} is now set up. + Use the button below to join at the scheduled time. +

+ + + + + +
+

Meeting

+

{{ object.type_id.name }}

+

When

+

+ {{ format_datetime(object.start, dt_format='full') }} +

+
+ + + + + +
+ + Join Google Meet + +
+ +

+ Or copy this link: + + {{ object.meeting_id.videocall_location }} + +

+
+
+
+
+
+
diff --git a/resource_booking_google_meet/models/__init__.py b/resource_booking_google_meet/models/__init__.py index 3efd32e8..23a81192 100644 --- a/resource_booking_google_meet/models/__init__.py +++ b/resource_booking_google_meet/models/__init__.py @@ -1 +1,2 @@ +from . import calendar_event from . import resource_booking diff --git a/resource_booking_google_meet/models/calendar_event.py b/resource_booking_google_meet/models/calendar_event.py new file mode 100644 index 00000000..5bf38025 --- /dev/null +++ b/resource_booking_google_meet/models/calendar_event.py @@ -0,0 +1,29 @@ +# Copyright 2026 Ledo Enterprises - D. Kendall +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import models + + +class CalendarEvent(models.Model): + _inherit = "calendar.event" + + def write(self, vals): + # Capture events that are about to receive a Google Meet URL for the first time. + # Must run before super() so we can compare old vs new videocall_location. + to_notify = self.env["calendar.event"] + if "meet.google.com" in (vals.get("videocall_location") or ""): + to_notify = self.filtered( + lambda e: "meet.google.com" not in (e.videocall_location or "") + ) + result = super().write(vals) + if to_notify: + template = self.env.ref( + "resource_booking_google_meet.mail_template_meet_link", + raise_if_not_found=False, + ) + if template: + bookings = self.env["resource.booking"].search( + [("meeting_id", "in", to_notify.ids)] + ) + for booking in bookings: + template.send_mail(booking.id, force_send=True) + return result