From 91f9bf2b64fb2a9bc6f0da3b38bd8c9b34770269 Mon Sep 17 00:00:00 2001
From: pedrambiria <pebr@odoo.com>
Date: Tue, 10 Jan 2023 14:16:49 +0000
Subject: [PATCH] [FIX] google_calendar: avoiding return of recordset when
 using ormcache

Before this commit: In some cases where some events won't sync to
Odoo properly you got the "Unable to use a closed cursor." error. The
problem is that `_from_google_ids` function returns a recordset, and the
underlying cursor may be closed.

Steps to reproduce the issue:
 1. Create user_A and user_B in Odoo
 2. Sync user_A and user_B with Google calendar
 3. Create an event with user_B on the Google calendar
 4. Run the "Google Calendar: synchronization" cron
 5. Change the created event's owner to user_A on the Google calendar
 6. Run the "Google Calendar: synchronization" cron
=> You will get this error on the log, and the event won't sync:

```
Traceback (most recent call last):
  File "/home/odoo/src/odoo/odoo/api.py", line 886, in get
    return field_cache[record._ids[0]]
KeyError: 99

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/odoo/src/odoo/odoo/fields.py", line 1061, in __get__
    value = env.cache.get(record, self)
  File "/home/odoo/src/odoo/odoo/api.py", line 889, in get
    raise CacheMiss(record, field)
odoo.exceptions.CacheMiss: 'calendar.event(99,).google_id'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/odoo/src/odoo/addons/google_calendar/models/res_users.py", line 91, in _sync_all_google_calendar
    user.with_user(user).sudo()._sync_google_calendar(google)
  File "/home/odoo/src/odoo/addons/google_calendar/models/res_users.py", line 70, in _sync_google_calendar
    synced_events = self.env['calendar.event']._sync_google2odoo(events - recurrences, default_reminders=default_reminders)
  File "/home/odoo/src/odoo/addons/google_calendar/models/google_sync.py", line 147, in _sync_google2odoo
    existing = google_events.exists(self.env)
  File "/home/odoo/src/odoo/addons/google_calendar/utils/google_event.py", line 180, in exists
    events.odoo_ids(env)
  File "/home/odoo/src/odoo/addons/google_calendar/utils/google_event.py", line 88, in odoo_ids
    found = self._load_odoo_ids_from_db(env, model)
  File "/home/odoo/src/odoo/addons/google_calendar/utils/google_event.py", line 111, in _load_odoo_ids_from_db
    mapping = {e.google_id: e.id for e in odoo_events}  # {google_id: odoo_id}
  File "/home/odoo/src/odoo/addons/google_calendar/utils/google_event.py", line 111, in <dictcomp>
    mapping = {e.google_id: e.id for e in odoo_events}  # {google_id: odoo_id}
  File "/home/odoo/src/odoo/odoo/fields.py", line 1087, in __get__
    recs._fetch_field(self)
  File "/home/odoo/src/odoo/odoo/models.py", line 3276, in _fetch_field
    self._read(fnames)
  File "/home/odoo/src/odoo/addons/calendar/models/calendar_event.py", line 436, in _read
    super()._read(fields)
  File "/home/odoo/src/odoo/odoo/models.py", line 3343, in _read
    cr.execute(query_str, params + [sub_ids])
  File "<decorator-gen-20>", line 2, in execute
  File "/home/odoo/src/odoo/odoo/sql_db.py", line 89, in check
    raise psycopg2.OperationalError('Unable to use a closed cursor.')
```

The solution is to use ormcache on a function that returns the ids of the
events.

opw-3098799

closes odoo/odoo#109557

Signed-off-by: Arnaud Joset <arj@odoo.com>
---
 addons/google_calendar/models/google_sync.py | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/addons/google_calendar/models/google_sync.py b/addons/google_calendar/models/google_sync.py
index ad09d16c2d18..95e3c3637321 100644
--- a/addons/google_calendar/models/google_sync.py
+++ b/addons/google_calendar/models/google_sync.py
@@ -70,7 +70,7 @@ class GoogleSync(models.AbstractModel):
     def write(self, vals):
         google_service = GoogleCalendarService(self.env['google.service'])
         if 'google_id' in vals:
-            self._from_google_ids.clear_cache(self)
+            self._event_ids_from_google_ids.clear_cache(self)
         synced_fields = self._get_google_synced_fields()
         if 'need_sync' not in vals and vals.keys() & synced_fields:
             vals['need_sync'] = True
@@ -85,7 +85,7 @@ class GoogleSync(models.AbstractModel):
     @api.model_create_multi
     def create(self, vals_list):
         if any(vals.get('google_id') for vals in vals_list):
-            self._from_google_ids.clear_cache(self)
+            self._event_ids_from_google_ids.clear_cache(self)
         records = super().create(vals_list)
 
         google_service = GoogleCalendarService(self.env['google.service'])
@@ -111,12 +111,15 @@ class GoogleSync(models.AbstractModel):
             return True
         return super().unlink()
 
-    @api.model
-    @ormcache_context('google_ids', keys=('active_test',))
     def _from_google_ids(self, google_ids):
         if not google_ids:
             return self.browse()
-        return self.search([('google_id', 'in', google_ids)])
+        return self.browse(self._event_ids_from_google_ids(google_ids))
+
+    @api.model
+    @ormcache_context('google_ids', keys=('active_test',))
+    def _event_ids_from_google_ids(self, google_ids):
+        return self.search([('google_id', 'in', google_ids)]).ids
 
     def _sync_odoo2google(self, google_service: GoogleCalendarService):
         if not self:
-- 
GitLab