diff --git a/addons/calendar/controllers/main.py b/addons/calendar/controllers/main.py index 2512b1e5999..e3f43f87bd0 100644 --- a/addons/calendar/controllers/main.py +++ b/addons/calendar/controllers/main.py @@ -11,15 +11,20 @@ from odoo.tools.misc import get_lang class CalendarController(http.Controller): + # YTI Note: Keep id and kwargs only for retrocompatibility purpose @http.route('/calendar/meeting/accept', type='http', auth="calendar") - def accept(self, token, action, id, **kwargs): - attendee = request.env['calendar.attendee'].search([('access_token', '=', token), ('state', '!=', 'accepted')]) + def accept_meeting(self, token, id, **kwargs): + attendee = request.env['calendar.attendee'].search([ + ('access_token', '=', token), + ('state', '!=', 'accepted')]) attendee.do_accept() - return self.view(token, action, id, view='form') + return self.view_meeting(token, id) @http.route('/calendar/recurrence/accept', type='http', auth="calendar") - def accept_recurrence(self, token, action, id, **kwargs): - attendee = request.env['calendar.attendee'].sudo().search([('access_token', '=', token), ('state', '!=', 'accepted')]) + def accept_recurrence(self, token, id, **kwargs): + attendee = request.env['calendar.attendee'].sudo().search([ + ('access_token', '=', token), + ('state', '!=', 'accepted')]) if attendee: attendees = request.env['calendar.attendee'].sudo().search([ ('event_id', 'in', attendee.event_id.recurrence_id.calendar_event_ids.ids), @@ -27,11 +32,21 @@ class CalendarController(http.Controller): ('state', '!=', 'accepted'), ]) attendees.do_accept() - return self.view(token, action, id, view='form') + return self.view_meeting(token, id) + + @http.route('/calendar/meeting/decline', type='http', auth="calendar") + def decline_meeting(self, token, id, **kwargs): + attendee = request.env['calendar.attendee'].search([ + ('access_token', '=', token), + ('state', '!=', 'declined')]) + attendee.do_decline() + return self.view_meeting(token, id) @http.route('/calendar/recurrence/decline', type='http', auth="calendar") - def decline_recurrence(self, token, action, id, **kwargs): - attendee = request.env['calendar.attendee'].sudo().search([('access_token', '=', token), ('state', '!=', 'declined')]) + def decline_recurrence(self, token, id, **kwargs): + attendee = request.env['calendar.attendee'].sudo().search([ + ('access_token', '=', token), + ('state', '!=', 'declined')]) if attendee: attendees = request.env['calendar.attendee'].sudo().search([ ('event_id', 'in', attendee.event_id.recurrence_id.calendar_event_ids.ids), @@ -39,17 +54,13 @@ class CalendarController(http.Controller): ('state', '!=', 'declined'), ]) attendees.do_decline() - return self.view(token, action, id, view='form') - - @http.route('/calendar/meeting/decline', type='http', auth="calendar") - def decline(self, token, action, id, **kwargs): - attendee = request.env['calendar.attendee'].search([('access_token', '=', token), ('state', '!=', 'declined')]) - attendee.do_decline() - return self.view(token, action, id, view='form') + return self.view_meeting(token, id) @http.route('/calendar/meeting/view', type='http', auth="calendar") - def view(self, token, action, id, view='calendar'): - attendee = request.env['calendar.attendee'].search([('access_token', '=', token), ('event_id', '=', int(id))]) + def view_meeting(self, token, id, **kwargs): + attendee = request.env['calendar.attendee'].search([ + ('access_token', '=', token), + ('event_id', '=', int(id))]) if not attendee: return request.not_found() timezone = attendee.partner_id.tz @@ -78,5 +89,5 @@ class CalendarController(http.Controller): return request.env['calendar.alarm_manager'].get_next_notif() @http.route('/calendar/notify_ack', type='json', auth="user") - def notify_ack(self, type=''): + def notify_ack(self): return request.env['res.partner'].sudo()._set_calendar_last_notif_ack() diff --git a/addons/calendar/data/mail_data.xml b/addons/calendar/data/mail_data.xml index 5c056eea138..91e5fc1f195 100644 --- a/addons/calendar/data/mail_data.xml +++ b/addons/calendar/data/mail_data.xml @@ -19,13 +19,13 @@

% set target = 'recurrence' if recurrent else 'meeting' - Accept - Decline - View
@@ -110,13 +110,13 @@

% set target = 'recurrence' if recurrent else 'meeting' - Accept - Decline - View
@@ -204,13 +204,13 @@ This is a reminder for the below event :

- Accept - Decline - View
diff --git a/addons/calendar/models/calendar_alarm.py b/addons/calendar/models/calendar_alarm.py index 392cb25ac63..970e59f4bf4 100644 --- a/addons/calendar/models/calendar_alarm.py +++ b/addons/calendar/models/calendar_alarm.py @@ -23,13 +23,20 @@ class Alarm(models.Model): _interval_selection = {'minutes': 'Minutes', 'hours': 'Hours', 'days': 'Days'} name = fields.Char('Name', translate=True, required=True) - alarm_type = fields.Selection([('notification', 'Notification'), ('email', 'Email')], string='Type', required=True, default='email') + alarm_type = fields.Selection( + [('notification', 'Notification'), ('email', 'Email')], + string='Type', required=True, default='email') duration = fields.Integer('Remind Before', required=True, default=1) - interval = fields.Selection(list(_interval_selection.items()), 'Unit', required=True, default='hours') - duration_minutes = fields.Integer('Duration in minutes', search='_search_duration_minutes', compute='_compute_duration_minutes', store=True, help="Duration in minutes") + interval = fields.Selection( + list(_interval_selection.items()), 'Unit', required=True, default='hours') + duration_minutes = fields.Integer( + 'Duration in minutes', store=True, + search='_search_duration_minutes', compute='_compute_duration_minutes', + help="Duration in minutes") def _search_duration_minutes(self, operator, value): - return ['|', '|', + return [ + '|', '|', '&', ('interval', '=', 'minutes'), ('duration', operator, value), '&', ('interval', '=', 'hours'), ('duration', operator, value / 60), '&', ('interval', '=', 'days'), ('duration', operator, value / 60 / 24), @@ -38,7 +45,9 @@ class Alarm(models.Model): @api.onchange('duration', 'interval', 'alarm_type') def _onchange_duration_interval(self): display_interval = self._interval_selection.get(self.interval, '') - display_alarm_type = {key: value for key, value in self._fields['alarm_type']._description_selection(self.env)}[self.alarm_type] + display_alarm_type = { + key: value for key, value in self._fields['alarm_type']._description_selection(self.env) + }[self.alarm_type] self.name = "%s - %s %s" % (display_alarm_type, self.duration, display_interval) def _update_cron(self): diff --git a/addons/calendar/models/calendar_alarm_manager.py b/addons/calendar/models/calendar_alarm_manager.py index 98fe461b7cd..2fb8ca1d099 100644 --- a/addons/calendar/models/calendar_alarm_manager.py +++ b/addons/calendar/models/calendar_alarm_manager.py @@ -2,7 +2,6 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import logging -import datetime from datetime import timedelta from odoo import api, fields, models @@ -11,7 +10,6 @@ _logger = logging.getLogger(__name__) class AlarmManager(models.AbstractModel): - _name = 'calendar.alarm_manager' _description = 'Event Alarm Manager' @@ -77,12 +75,12 @@ class AlarmManager(models.AbstractModel): tuple_params += (seconds,) self._cr.execute(""" - WITH calcul_delta AS (%s) - SELECT * - FROM ( %s WHERE cal.active = True ) AS ALL_EVENTS - WHERE ALL_EVENTS.first_alarm < %s - AND ALL_EVENTS.last_event_date > (now() at time zone 'utc') - """ % (delta_request, base_request, first_alarm_max_value), tuple_params) + WITH calcul_delta AS (%s) + SELECT * + FROM ( %s WHERE cal.active = True ) AS ALL_EVENTS + WHERE ALL_EVENTS.first_alarm < %s + AND ALL_EVENTS.last_event_date > (now() at time zone 'utc') + """ % (delta_request, base_request, first_alarm_max_value), tuple_params) for event_id, first_alarm, last_alarm, first_meeting, last_meeting, min_duration, max_duration, rule in self._cr.fetchall(): result[event_id] = { diff --git a/addons/calendar/models/calendar_attendee.py b/addons/calendar/models/calendar_attendee.py index 375a18a1057..0a5366b15b6 100644 --- a/addons/calendar/models/calendar_attendee.py +++ b/addons/calendar/models/calendar_attendee.py @@ -3,7 +3,6 @@ import uuid import base64 import logging -from collections import defaultdict from odoo import api, fields, models, _ from odoo.exceptions import UserError @@ -13,7 +12,6 @@ _logger = logging.getLogger(__name__) class Attendee(models.Model): """ Calendar Attendee Information """ - _name = 'calendar.attendee' _rec_name = 'common_name' _description = 'Calendar Attendee Information' @@ -28,13 +26,15 @@ class Attendee(models.Model): ('accepted', 'Accepted'), ] - event_id = fields.Many2one('calendar.event', 'Meeting linked', required=True, ondelete='cascade') + event_id = fields.Many2one( + 'calendar.event', 'Meeting linked', required=True, ondelete='cascade') partner_id = fields.Many2one('res.partner', 'Contact', required=True, readonly=True) state = fields.Selection(STATE_SELECTION, string='Status', readonly=True, default='needsAction', help="Status of the attendee's participation") common_name = fields.Char('Common name', compute='_compute_common_name', store=True) email = fields.Char('Email', related='partner_id.email', help="Email of Invited Person") - availability = fields.Selection([('free', 'Free'), ('busy', 'Busy')], 'Free/Busy', readonly=True) + availability = fields.Selection( + [('free', 'Free'), ('busy', 'Busy')], 'Free/Busy', readonly=True) access_token = fields.Char('Invitation Token', default=_default_access_token) recurrence_id = fields.Many2one('calendar.recurrence', related='event_id.recurrence_id') @@ -50,8 +50,8 @@ class Attendee(models.Model): values['state'] = 'accepted' if not values.get("email") and values.get("common_name"): common_nameval = values.get("common_name").split(':') - email = [x for x in common_nameval if '@' in x] # TODO JEM : should be refactored - values['email'] = email and email[0] or '' + email = [x for x in common_nameval if '@' in x] + values['email'] = email[0] if email else '' values['common_name'] = values.get("common_name") attendees = super().create(vals_list) attendees._subscribe_partner() @@ -64,7 +64,8 @@ class Attendee(models.Model): def _subscribe_partner(self): for event in self.event_id: partners = (event.attendee_ids & self).partner_id - event.message_partner_ids - partners -= self.env.user.partner_id # current user is automatically added as followers, don't add it twice. + # current user is automatically added as followers, don't add it twice. + partners -= self.env.user.partner_id event.message_subscribe(partner_ids=partners.ids) def _unsubscribe_partner(self): @@ -147,12 +148,15 @@ class Attendee(models.Model): def do_accept(self): """ Marks event invitation as Accepted. """ for attendee in self: - attendee.event_id.message_post(body=_("%s has accepted invitation") % (attendee.common_name), subtype_xmlid="calendar.subtype_invitation") + attendee.event_id.message_post( + body=_("%s has accepted invitation") % (attendee.common_name), + subtype_xmlid="calendar.subtype_invitation") return self.write({'state': 'accepted'}) def do_decline(self): """ Marks event invitation as Declined. """ for attendee in self: - attendee.event_id.message_post(body=_("%s has declined invitation") % (attendee.common_name), subtype_xmlid="calendar.subtype_invitation") + attendee.event_id.message_post( + body=_("%s has declined invitation") % (attendee.common_name), + subtype_xmlid="calendar.subtype_invitation") return self.write({'state': 'declined'}) - diff --git a/addons/calendar/models/calendar_event.py b/addons/calendar/models/calendar_event.py index c823b17cdb1..5148e02bf1c 100644 --- a/addons/calendar/models/calendar_event.py +++ b/addons/calendar/models/calendar_event.py @@ -1,11 +1,9 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import babel.dates -import datetime -import math from datetime import timedelta -from dateutil.relativedelta import relativedelta +import math +import babel.dates import logging import pytz @@ -19,10 +17,8 @@ from odoo.tools.misc import get_lang from odoo.tools import pycompat from odoo.exceptions import UserError, ValidationError - _logger = logging.getLogger(__name__) - SORT_ALIASES = { 'start': 'sort_start', 'start_date': 'sort_start', @@ -45,12 +41,6 @@ def get_weekday_occurence(date): class Meeting(models.Model): - """ Model for Calendar Event - - Special context keys : - - `no_mail_to_attendees` : disabled sending email to attendees when creating/editing a meeting - """ - _name = 'calendar.event' _description = "Calendar Event" _order = "start desc" @@ -188,27 +178,45 @@ class Meeting(models.Model): name = fields.Char('Meeting Subject', required=True) - attendee_status = fields.Selection(Attendee.STATE_SELECTION, string='Attendee Status', compute='_compute_attendee') + attendee_status = fields.Selection( + Attendee.STATE_SELECTION, string='Attendee Status', compute='_compute_attendee') display_time = fields.Char('Event Time', compute='_compute_display_time') - start = fields.Datetime('Start', required=True, tracking=True, default=fields.Date.today, help="Start date of an event, without time for full days events") - stop = fields.Datetime('Stop', required=True, tracking=True, default=fields.Date.today, compute='_compute_stop', readonly=False, store=True, - help="Stop date of an event, without time for full days events") + start = fields.Datetime( + 'Start', required=True, tracking=True, default=fields.Date.today, + help="Start date of an event, without time for full days events") + stop = fields.Datetime( + 'Stop', required=True, tracking=True, default=fields.Date.today, + compute='_compute_stop', readonly=False, store=True, + help="Stop date of an event, without time for full days events") allday = fields.Boolean('All Day', default=False) - start_date = fields.Date('Start Date', compute='_compute_dates', inverse='_inverse_dates', store=True, tracking=True) - stop_date = fields.Date('End Date', compute='_compute_dates', inverse='_inverse_dates', store=True, tracking=True) - event_tz = fields.Selection('_event_tz_get', string='Timezone', default=lambda self: self.env.context.get('tz') or self.user_id.tz) + start_date = fields.Date( + 'Start Date', store=True, tracking=True, + compute='_compute_dates', inverse='_inverse_dates') + stop_date = fields.Date( + 'End Date', store=True, tracking=True, + compute='_compute_dates', inverse='_inverse_dates') + event_tz = fields.Selection( + '_event_tz_get', string='Timezone', + default=lambda self: self.env.context.get('tz') or self.user_id.tz) duration = fields.Float('Duration', compute='_compute_duration', store=True, readonly=False) description = fields.Text('Description') - privacy = fields.Selection([('public', 'Everyone'), ('private', 'Only me'), ('confidential', 'Only internal users')], 'Privacy', default='public', required=True) + privacy = fields.Selection( + [('public', 'Everyone'), + ('private', 'Only me'), + ('confidential', 'Only internal users')], + 'Privacy', default='public', required=True) location = fields.Char('Location', tracking=True, help="Location of Event") - show_as = fields.Selection([('free', 'Free'), ('busy', 'Busy')], 'Show Time as', default='busy', required=True) + show_as = fields.Selection( + [('free', 'Free'), + ('busy', 'Busy')], 'Show Time as', default='busy', required=True) # linked document # LUL TODO use fields.Reference ? res_id = fields.Integer('Document ID') res_model_id = fields.Many2one('ir.model', 'Document Model', ondelete='cascade') - res_model = fields.Char('Document Model Name', related='res_model_id.model', readonly=True, store=True) + res_model = fields.Char( + 'Document Model Name', related='res_model_id.model', readonly=True, store=True) activity_ids = fields.One2many('mail.activity', 'calendar_event_id', string='Activities') #redifine message_ids to remove autojoin to avoid search to crash in get_recurrent_ids @@ -235,7 +243,8 @@ class Meeting(models.Model): # RECURRENCE FIELD recurrency = fields.Boolean('Recurrent', help="Recurrent Event") - recurrence_id = fields.Many2one('calendar.recurrence', string="Recurrence Rule", index=True) + recurrence_id = fields.Many2one( + 'calendar.recurrence', string="Recurrence Rule", index=True) recurrence_update = fields.Selection([ ('self_only', "This event"), ('future_events', "This and following events"), @@ -246,16 +255,22 @@ class Meeting(models.Model): # Those field are pseudo-related fields of recurrence_id. # They can't be "real" related fields because it should work at record creation # when recurrence_id is not created yet. - # If some of these fields are set and recurrence_id does not exists, a `calendar.recurrence.rule` - # will be dynamically created. + # If some of these fields are set and recurrence_id does not exists, + # a `calendar.recurrence.rule` will be dynamically created. rrule = fields.Char('Recurrent Rule', compute='_compute_recurrence', readonly=False) rrule_type = fields.Selection(RRULE_TYPE_SELECTION, string='Recurrence', help="Let the event automatically repeat at that interval", compute='_compute_recurrence', readonly=False) - event_tz = fields.Selection(_tz_get, string='Timezone', compute='_compute_recurrence', readonly=False) - end_type = fields.Selection(END_TYPE_SELECTION, string='Recurrence Termination', compute='_compute_recurrence', readonly=False) - interval = fields.Integer(string='Repeat Every', help="Repeat every (Days/Week/Month/Year)", compute='_compute_recurrence', readonly=False) - count = fields.Integer(string='Repeat', help="Repeat x times", compute='_compute_recurrence', readonly=False) + event_tz = fields.Selection( + _tz_get, string='Timezone', compute='_compute_recurrence', readonly=False) + end_type = fields.Selection( + END_TYPE_SELECTION, string='Recurrence Termination', + compute='_compute_recurrence', readonly=False) + interval = fields.Integer( + string='Repeat Every', compute='_compute_recurrence', readonly=False, + help="Repeat every (Days/Week/Month/Year)") + count = fields.Integer( + string='Repeat', help="Repeat x times", compute='_compute_recurrence', readonly=False) mo = fields.Boolean('Mon', compute='_compute_recurrence', readonly=False) tu = fields.Boolean('Tue', compute='_compute_recurrence', readonly=False) we = fields.Boolean('Wed', compute='_compute_recurrence', readonly=False) @@ -263,7 +278,8 @@ class Meeting(models.Model): fr = fields.Boolean('Fri', compute='_compute_recurrence', readonly=False) sa = fields.Boolean('Sat', compute='_compute_recurrence', readonly=False) su = fields.Boolean('Sun', compute='_compute_recurrence', readonly=False) - month_by = fields.Selection(MONTH_BY_SELECTION, string='Option', compute='_compute_recurrence', readonly=False) + month_by = fields.Selection( + MONTH_BY_SELECTION, string='Option', compute='_compute_recurrence', readonly=False) day = fields.Integer('Date of month', compute='_compute_recurrence', readonly=False) weekday = fields.Selection(WEEKDAY_SELECTION, compute='_compute_recurrence', readonly=False) byday = fields.Selection(BYDAY_SELECTION, compute='_compute_recurrence', readonly=False) @@ -280,8 +296,10 @@ class Meeting(models.Model): @api.depends('allday', 'start', 'stop') def _compute_dates(self): - """ Adapt the value of start_date(time)/stop_date(time) according to start/stop fields and allday. Also, compute - the duration for not allday meeting ; otherwise the duration is set to zero, since the meeting last all the day. + """ Adapt the value of start_date(time)/stop_date(time) + according to start/stop fields and allday. Also, compute + the duration for not allday meeting ; otherwise the + duration is set to zero, since the meeting last all the day. """ for meeting in self: if meeting.allday and meeting.start and meeting.stop: @@ -380,8 +398,7 @@ class Meeting(models.Model): if idate: if allday: return idate - else: - return idate.replace(tzinfo=pytz.timezone('UTC')) + return idate.replace(tzinfo=pytz.timezone('UTC')) return False try: @@ -749,8 +766,6 @@ class Meeting(models.Model): private_fields = set(groupby) - self._get_public_fields() if not self.env.su and private_fields: raise UserError(_("Grouping by %s is not allowed." % ', '.join([self._fields[field_name].string for field_name in private_fields]))) - if 'date' in groupby: - raise UserError(_('Group by date is not supported, use the calendar view instead.')) return super(Meeting, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) def unlink(self): @@ -797,7 +812,6 @@ class Meeting(models.Model): attendee = self.attendee_ids.filtered(lambda x: x.partner_id == self.env.user.partner_id) if status == 'accepted': return attendee.do_accept() - elif status == 'declined': + if status == 'declined': return attendee.do_decline() - else: - return attendee.do_tentative() + return attendee.do_tentative() diff --git a/addons/calendar/models/calendar_recurrence.py b/addons/calendar/models/calendar_recurrence.py index 0e50ea9ea32..9ae8c4fc3de 100644 --- a/addons/calendar/models/calendar_recurrence.py +++ b/addons/calendar/models/calendar_recurrence.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from datetime import datetime, time import pytz -from datetime import datetime, time from dateutil import rrule -from dateutil.relativedelta import relativedelta, MO +from dateutil.relativedelta import relativedelta from odoo import api, fields, models, _ from odoo.exceptions import UserError @@ -91,9 +91,12 @@ class RecurrenceRule(models.Model): _description = 'Event Recurrence Rule' name = fields.Char(compute='_compute_name', store=True) - base_event_id = fields.Many2one('calendar.event', ondelete='set null', copy=False) + base_event_id = fields.Many2one( + 'calendar.event', ondelete='set null', copy=False) # store=False ? calendar_event_ids = fields.One2many('calendar.event', 'recurrence_id') - event_tz = fields.Selection(_tz_get, string='Timezone', default=lambda self: self.env.context.get('tz') or self.env.user.tz) + event_tz = fields.Selection( + _tz_get, string='Timezone', + default=lambda self: self.env.context.get('tz') or self.env.user.tz) rrule = fields.Char(compute='_compute_rrule', inverse='_inverse_rrule', store=True) dtstart = fields.Datetime(compute='_compute_dtstart') rrule_type = fields.Selection(RRULE_TYPE_SELECTION, default='weekly') @@ -132,8 +135,8 @@ class RecurrenceRule(models.Model): if recurrence.rrule_type == 'weeky': weekdays = recurrence._get_week_days() - fields = (self._fields[weekday_to_field(w)] for w in weekdays) - on = _("on %s,") % ", ".join([field.string for field in fields]) + weekday_fields = (self._fields[weekday_to_field(w)] for w in weekdays) + on = _("on %s,") % ", ".join([field.string for field in weekday_fields]) elif recurrence.rrule_type == 'monthly': if recurrence.month_by == 'day': weekday_label = dict(BYDAY_SELECTION)[recurrence.byday] @@ -154,7 +157,9 @@ class RecurrenceRule(models.Model): for recurrence in self: recurrence.dtstart = start_mapping.get(recurrence.id) - @api.depends('byday', 'until', 'rrule_type', 'month_by', 'interval', 'count', 'end_type', 'mo', 'tu', 'we', 'th', 'fr', 'sa', 'su', 'day', 'weekday') + @api.depends( + 'byday', 'until', 'rrule_type', 'month_by', 'interval', 'count', 'end_type', + 'mo', 'tu', 'we', 'th', 'fr', 'sa', 'su', 'day', 'weekday') def _compute_rrule(self): for recurrence in self: recurrence.rrule = recurrence._rrule_serialize() @@ -168,7 +173,8 @@ class RecurrenceRule(models.Model): def _reconcile_events(self, ranges): """ :param ranges: iterable of tuples (datetime_start, datetime_stop) - :return: tuple (events of the recurrence already in sync with ranges, and ranges not covered by any events) + :return: tuple (events of the recurrence already in sync with ranges, + and ranges not covered by any events) """ ranges = set(ranges) @@ -328,16 +334,17 @@ class RecurrenceRule(models.Model): def _get_start_of_period(self, dt): if self.rrule_type == 'daily': - return dt + start = dt elif self.rrule_type == 'weekly': lang = self.env['res.lang']._lang_get(self.env.user.lang) week_start = int(lang.week_start) # lang.week_start ranges from '1' to '7' week_start = rrule.weekday(week_start - 1) # expects an int from 0 to 6 - return dt + relativedelta(weekday=week_start(-1)) + start = dt + relativedelta(weekday=week_start(-1)) elif self.rrule_type == 'monthly': - return dt + relativedelta(day=1) + start = dt + relativedelta(day=1) elif self.rrule_type == 'yearly': - return dt + start = dt + return start def _get_first_event(self, include_outliers=False): if not self.calendar_event_ids: diff --git a/addons/calendar/models/ir_http.py b/addons/calendar/models/ir_http.py index 224cd0f0de3..08acd868cd4 100644 --- a/addons/calendar/models/ir_http.py +++ b/addons/calendar/models/ir_http.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from werkzeug.exceptions import BadRequest + from odoo import models from odoo.http import request -from werkzeug.exceptions import BadRequest - class IrHttp(models.AbstractModel): _inherit = 'ir.http' diff --git a/addons/calendar/models/res_partner.py b/addons/calendar/models/res_partner.py index b8a25a295b8..ec4f5ea7555 100644 --- a/addons/calendar/models/res_partner.py +++ b/addons/calendar/models/res_partner.py @@ -9,7 +9,8 @@ from odoo import api, fields, models class Partner(models.Model): _inherit = 'res.partner' - calendar_last_notif_ack = fields.Datetime('Last notification marked as read from base Calendar', default=fields.Datetime.now) + calendar_last_notif_ack = fields.Datetime( + 'Last notification marked as read from base Calendar', default=fields.Datetime.now) def get_attendee_detail(self, meeting_id): """ Return a list of tuple (id, name, status) @@ -32,6 +33,5 @@ class Partner(models.Model): @api.model def _set_calendar_last_notif_ack(self): - partner = self.env['res.users'].browse(self.env.context.get('uid',self.env.uid)).partner_id + partner = self.env['res.users'].browse(self.env.context.get('uid', self.env.uid)).partner_id partner.write({'calendar_last_notif_ack': datetime.now()}) - return diff --git a/addons/calendar/models/res_users.py b/addons/calendar/models/res_users.py index 12301d12094..bdb25f7567a 100644 --- a/addons/calendar/models/res_users.py +++ b/addons/calendar/models/res_users.py @@ -23,9 +23,13 @@ class Users(models.Model): return ['&', '|', '&', - '|', ['start', '>=', fields.Datetime.to_string(start_dt)], ['stop', '>=', fields.Datetime.to_string(start_dt)], + '|', + ['start', '>=', fields.Datetime.to_string(start_dt)], + ['stop', '>=', fields.Datetime.to_string(start_dt)], ['start', '<=', fields.Datetime.to_string(end_dt)], - '&', ['allday', '=', True], ['start_date', '=', fields.Date.to_string(start_date)], + '&', + ['allday', '=', True], + ['start_date', '=', fields.Date.to_string(start_date)], ('attendee_ids.partner_id', '=', self.env.user.partner_id.id)] @api.model diff --git a/addons/calendar/security/calendar_security.xml b/addons/calendar/security/calendar_security.xml index 8b5385e3cdf..f8cf8f7cd31 100644 --- a/addons/calendar/security/calendar_security.xml +++ b/addons/calendar/security/calendar_security.xml @@ -5,21 +5,21 @@ Own events - [('partner_ids','in',user.partner_id.id)] + [('partner_ids', 'in', user.partner_id.id)] All Calendar Event for employees - [(1,'=',1)] + [(1, '=', 1)] Own attendees - [(1,'=',1)] + [(1, '=', 1)] diff --git a/addons/calendar/static/src/js/base_calendar.js b/addons/calendar/static/src/js/base_calendar.js index 600ebd4b01a..f2c1e56b298 100644 --- a/addons/calendar/static/src/js/base_calendar.js +++ b/addons/calendar/static/src/js/base_calendar.js @@ -10,7 +10,6 @@ var WebClient = require('web.WebClient'); var FieldMany2ManyTags = relationalFields.FieldMany2ManyTags; - var CalendarNotification = Notification.extend({ template: "CalendarNotification", xmlDependencies: (Notification.prototype.xmlDependencies || []) diff --git a/addons/calendar/static/src/js/calendar_controller.js b/addons/calendar/static/src/js/calendar_controller.js index 388b4a33061..190125ac722 100644 --- a/addons/calendar/static/src/js/calendar_controller.js +++ b/addons/calendar/static/src/js/calendar_controller.js @@ -22,7 +22,7 @@ odoo.define('calendar.CalendarController', function (require) { }, }], }).open(); - }) + }); }, // TODO factorize duplicated code diff --git a/addons/calendar/static/src/js/calendar_model.js b/addons/calendar/static/src/js/calendar_model.js index 4d5a2b49b44..8d90b543d0b 100644 --- a/addons/calendar/static/src/js/calendar_model.js +++ b/addons/calendar/static/src/js/calendar_model.js @@ -15,10 +15,7 @@ odoo.define('calendar.CalendarModel', function (require) { 'recurrence_update': event.recurrenceUpdate, }); } - - }); return CalendarModel; - }); diff --git a/addons/calendar/tests/test_calendar.py b/addons/calendar/tests/test_calendar.py index 6bcda2bd007..36e9404c424 100644 --- a/addons/calendar/tests/test_calendar.py +++ b/addons/calendar/tests/test_calendar.py @@ -251,7 +251,7 @@ class TestCalendar(SavepointCaseWithUserDemo): Check that mail are NOT sent to the attendees when detaching a recurring event """ - def _test_one_mail_per_attendee(self, m, partners): + def _test_one_mail_per_attendee(self, partners): # check that every attendee receive a (single) mail for the event for partner in partners: mail = self.env['mail.message'].sudo().search([ @@ -260,9 +260,9 @@ class TestCalendar(SavepointCaseWithUserDemo): self.assertEqual(len(mail), 1) partners = [ - self.env['res.partner'].create({'name':'testuser0','email': u'bob@example.com'}), - self.env['res.partner'].create({'name':'testuser1','email': u'alice@example.com'}), - ] + self.env['res.partner'].create({'name': 'testuser0', 'email': u'bob@example.com'}), + self.env['res.partner'].create({'name': 'testuser1', 'email': u'alice@example.com'}), + ] partner_ids = [(6, False, [p.id for p in partners]),] now = fields.Datetime.now() m = self.CalendarEvent.create({ @@ -276,13 +276,13 @@ class TestCalendar(SavepointCaseWithUserDemo): }) # every partner should have 1 mail sent - _test_one_mail_per_attendee(self, m, partners) + _test_one_mail_per_attendee(self, partners) # adding more partners to the event partners.extend([ - self.env['res.partner'].create({'name':'testuser2','email': u'marc@example.com'}), - self.env['res.partner'].create({'name':'testuser3','email': u'carl@example.com'}), - self.env['res.partner'].create({'name':'testuser4','email': u'alain@example.com'}), + self.env['res.partner'].create({'name': 'testuser2', 'email': u'marc@example.com'}), + self.env['res.partner'].create({'name': 'testuser3', 'email': u'carl@example.com'}), + self.env['res.partner'].create({'name': 'testuser4', 'email': u'alain@example.com'}), ]) partner_ids = [(6, False, [p.id for p in partners]),] m.write({ @@ -291,4 +291,4 @@ class TestCalendar(SavepointCaseWithUserDemo): }) # more email should be sent - _test_one_mail_per_attendee(self, m, partners) + _test_one_mail_per_attendee(self, partners) diff --git a/addons/google_account/__init__.py b/addons/google_account/__init__.py index 314d8d4bff4..9afb106a80f 100644 --- a/addons/google_account/__init__.py +++ b/addons/google_account/__init__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. + from . import models from . import controllers diff --git a/addons/google_account/models/google_service.py b/addons/google_account/models/google_service.py index 86d099eb745..5a69f35bd2f 100644 --- a/addons/google_account/models/google_service.py +++ b/addons/google_account/models/google_service.py @@ -8,10 +8,7 @@ import logging import requests from werkzeug import urls -from odoo import api, fields, models, registry, _ -from odoo.exceptions import UserError -from odoo.http import request - +from odoo import api, fields, models, _ _logger = logging.getLogger(__name__) @@ -113,7 +110,7 @@ class GoogleService(models.AbstractModel): 'redirect_uri': base_url + '/google_account/authentication' } try: - dummy, response, dummy = self._do_request(GOOGLE_TOKEN_ENDPOINT, params=data, headers=headers, type='POST', preuri='') + dummy, response, dummy = self._do_request(GOOGLE_TOKEN_ENDPOINT, params=data, headers=headers, method='POST', preuri='') access_token = response.get('access_token') refresh_token = response.get('refresh_token') ttl = response.get('expires_in') @@ -122,14 +119,13 @@ class GoogleService(models.AbstractModel): error_msg = _("Something went wrong during your token generation. Maybe your Authorization Code is invalid") raise self.env['res.config.settings'].get_config_warning(error_msg) - # TODO JEM : remove preuri param, and rename type into method @api.model - def _do_request(self, uri, params=None, headers=None, type='POST', preuri="https://www.googleapis.com", timeout=TIMEOUT): + def _do_request(self, uri, params=None, headers=None, method='POST', preuri="https://www.googleapis.com", timeout=TIMEOUT): """ Execute the request to Google API. Return a tuple ('HTTP_CODE', 'HTTP_RESPONSE') :param uri : the url to contact :param params : dict or already encoded parameters for the request to make :param headers : headers of request - :param type : the method to use to make the request + :param method : the method to use to make the request :param preuri : pre url to prepend to param uri. """ if params is None: @@ -137,16 +133,16 @@ class GoogleService(models.AbstractModel): if headers is None: headers = {} - _logger.debug("Uri: %s - Type : %s - Headers: %s - Params : %s !", (uri, type, headers, params)) + _logger.debug("Uri: %s - Type : %s - Headers: %s - Params : %s !", (uri, method, headers, params)) ask_time = fields.Datetime.now() try: - if type.upper() in ('GET', 'DELETE'): - res = requests.request(type.lower(), preuri + uri, params=params, timeout=timeout) - elif type.upper() in ('POST', 'PATCH', 'PUT'): - res = requests.request(type.lower(), preuri + uri, data=params, headers=headers, timeout=timeout) + if method.upper() in ('GET', 'DELETE'): + res = requests.request(method.lower(), preuri + uri, params=params, timeout=timeout) + elif method.upper() in ('POST', 'PATCH', 'PUT'): + res = requests.request(method.lower(), preuri + uri, data=params, headers=headers, timeout=timeout) else: - raise Exception(_('Method not supported [%s] not in [GET, POST, PUT, PATCH or DELETE]!') % (type)) + raise Exception(_('Method not supported [%s] not in [GET, POST, PUT, PATCH or DELETE]!') % (method)) res.raise_for_status() status = res.status_code @@ -160,8 +156,6 @@ class GoogleService(models.AbstractModel): except: pass except requests.HTTPError as error: - # if error.response.status_code == 401: - # raise InvalidToken if error.response.status_code in (204, 404): status = error.response.status_code response = "" diff --git a/addons/google_calendar/README.md b/addons/google_calendar/README.md deleted file mode 100644 index 2473da7b922..00000000000 --- a/addons/google_calendar/README.md +++ /dev/null @@ -1,52 +0,0 @@ -Google Calendar ---------------- - -Get your meetings, your leaves... Get your calendar anywhere and never -forget an event, fully synchronized with the Odoo Open Source CRM. - -Keep an eye on your events --------------------------- - -See easily the purpose of the meeting, the start time and also the -attendee(s)... All that without click on anything... - -Create so easily an event -------------------------- - -In just one click you can create an event... You can drag and drop your event -if you want moved it to another timing. You can shrink or extend the event if -you need to change the start's hours or the duration of your meeting. - -Create recurrent event ----------------------- - -You can also create recurrent events with only one event. You need to create -an event each monday of the week ? With only one it's possible, you could -specify the recurrence and if one of this event is moved, or deleted, it's not -a problem, you can untie your event from the others recurrences. - -See all events you wants ------------------------- - -See in your calendar, the event from others peoples where your are attendee, -but also their events by simply adding your favorites coworkers. Every -coworker will have their own color in your calendar, and every attendee will -have their avatar in the event... - -Get an email ------------- - -You will receive an email at creation of an event where you are attendee, but -also when this event is updated for some fields as date start, ... - -Be notified ------------ - -You can ask to have a alarm of type 'notification' in your Odoo. You will have -a notification in you Odoo which ever the page you are. - -Google Calendar ---------------- - -With this plugin, you can synchronize your Odoo calendar with Google Calendar. - diff --git a/addons/google_calendar/controllers/main.py b/addons/google_calendar/controllers/main.py index 465b0fa48b0..76326eb9d85 100644 --- a/addons/google_calendar/controllers/main.py +++ b/addons/google_calendar/controllers/main.py @@ -10,9 +10,12 @@ class GoogleCalendarController(http.Controller): @http.route('/google_calendar/sync_data', type='json', auth='user') def sync_data(self, model, **kw): - """ This route/function is called when we want to synchronize Odoo calendar with Google Calendar - Function return a dictionary with the status : need_config_from_admin, need_auth, need_refresh, success if not calendar_event - The dictionary may contains an url, to allow Odoo Client to redirect user on this URL for authorization for example + """ This route/function is called when we want to synchronize Odoo + calendar with Google Calendar. + Function return a dictionary with the status : need_config_from_admin, need_auth, + need_refresh, success if not calendar_event + The dictionary may contains an url, to allow Odoo Client to redirect user on + this URL for authorization for example """ if model == 'calendar.event': GoogleCal = GoogleCalendarService(request.env['google.service']) diff --git a/addons/google_calendar/models/calendar.py b/addons/google_calendar/models/calendar.py index 943e8efe820..161ca5d352f 100644 --- a/addons/google_calendar/models/calendar.py +++ b/addons/google_calendar/models/calendar.py @@ -12,7 +12,8 @@ class Meeting(models.Model): _name = 'calendar.event' _inherit = ['calendar.event', 'google.calendar.sync'] - google_id = fields.Char('Google Calendar Event Id', compute='_compute_google_id', store=True, readonly=False) + google_id = fields.Char( + 'Google Calendar Event Id', compute='_compute_google_id', store=True, readonly=False) @api.depends('recurrence_id.google_id') def _compute_google_id(self): @@ -65,9 +66,6 @@ class Meeting(models.Model): 'recurrency': google_event.is_recurrent() } - if google_event.reminders and google_event.reminders.get('useDefault'): - values - if not google_event.is_recurrence(): values['google_id'] = google_event.id if google_event.start.get('dateTime'): @@ -91,7 +89,9 @@ class Meeting(models.Model): emails = [a.get('email') for a in google_event.attendees] existing_attendees = self.env['calendar.attendee'] if google_event.exists(self.env): - existing_attendees = self.env['calendar.attendee'].search([('event_id', '=', google_event.odoo_id(self.env)), ('email', 'in', emails)]) + existing_attendees = self.env['calendar.attendee'].search([ + ('event_id', '=', google_event.odoo_id(self.env)), + ('email', 'in', emails)]) attendees_by_emails = {a.email: a for a in existing_attendees} for attendee in google_event.attendees: email = attendee.get('email') diff --git a/addons/google_calendar/models/calendar_recurrence_rule.py b/addons/google_calendar/models/calendar_recurrence_rule.py index 0462bb013f8..c09caef4be1 100644 --- a/addons/google_calendar/models/calendar_recurrence_rule.py +++ b/addons/google_calendar/models/calendar_recurrence_rule.py @@ -8,7 +8,6 @@ from odoo import api, fields, models from addons.google_calendar.utils.google_calendar import GoogleCalendarService - class RecurrenceRule(models.Model): _name = 'calendar.recurrence' _inherit = ['calendar.recurrence', 'google.calendar.sync'] @@ -121,4 +120,4 @@ class RecurrenceRule(models.Model): '%s_odoo_id' % self.env.cr.dbname: self.id, }, } - return values \ No newline at end of file + return values diff --git a/addons/google_calendar/models/google_sync.py b/addons/google_calendar/models/google_sync.py index bf8ab27e454..377aaac6a61 100644 --- a/addons/google_calendar/models/google_sync.py +++ b/addons/google_calendar/models/google_sync.py @@ -1,11 +1,12 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. + import logging +from contextlib import contextmanager +from functools import wraps import requests import pytz -from functools import wraps from dateutil.parser import parse -from contextlib import contextmanager from odoo import api, fields, models, registry, _ from odoo.tools import ormcache_context @@ -52,7 +53,7 @@ def google_calendar_token(user): # Rollback manually first to avoid concurrent access errors/deadlocks. user.env.cr.rollback() with user.pool.cursor() as cr: - env= user.env(cr=cr) + env = user.env(cr=cr) user.with_env(env)._set_auth_tokens(False, False, 0) raise e @@ -155,7 +156,7 @@ class GoogleSync(models.AbstractModel): cancelled_odoo._cancel() synced_records = new_odoo + cancelled_odoo - for gevent in existing - cancelled : + for gevent in existing - cancelled: # Last updated wins. # This could be dangerous if google server time and odoo server time are different updated = parse(gevent.updated) @@ -169,7 +170,6 @@ class GoogleSync(models.AbstractModel): @after_commit def _google_delete(self, google_service: GoogleCalendarService, google_id, timeout=TIMEOUT): - print('DELETE', google_id) with google_calendar_token(self.env.user.sudo()) as token: if token: google_service.delete(google_id, token=token, timeout=timeout) @@ -177,7 +177,6 @@ class GoogleSync(models.AbstractModel): @after_commit def _google_patch(self, google_service: GoogleCalendarService, google_id, values, timeout=TIMEOUT): - print('Patch', google_id) with google_calendar_token(self.env.user.sudo()) as token: if token: google_service.patch(google_id, values, token=token, timeout=timeout) @@ -185,7 +184,6 @@ class GoogleSync(models.AbstractModel): @after_commit def _google_insert(self, google_service: GoogleCalendarService, values, timeout=TIMEOUT): - print('insert') if not values: return with google_calendar_token(self.env.user.sudo()) as token: diff --git a/addons/google_calendar/models/res_users.py b/addons/google_calendar/models/res_users.py index 28a08f69558..70c2079184b 100644 --- a/addons/google_calendar/models/res_users.py +++ b/addons/google_calendar/models/res_users.py @@ -62,7 +62,7 @@ class User(models.Model): } try: - dummy, response, dummy = self.env['google.service']._do_request(GOOGLE_TOKEN_ENDPOINT, params=data, headers=headers, type='POST', preuri='') + dummy, response, dummy = self.env['google.service']._do_request(GOOGLE_TOKEN_ENDPOINT, params=data, headers=headers, method='POST', preuri='') ttl = response.get('expires_in') self.write({ 'google_calendar_token': response.get('access_token'), diff --git a/addons/google_calendar/tests/test_sync_google2odoo.py b/addons/google_calendar/tests/test_sync_google2odoo.py index 8194584439b..1ada7e88157 100644 --- a/addons/google_calendar/tests/test_sync_google2odoo.py +++ b/addons/google_calendar/tests/test_sync_google2odoo.py @@ -262,7 +262,7 @@ class TestSyncGoogle2Odoo(SavepointCase): 'reminders': {'useDefault': True}, 'updated': self.now, }, - { # Third event has been moved + { # Third event has been moved 'id': '%s_20200113' % recurrence_id, 'summary': 'Pricing new update', 'start': {'date': '2020-01-18'}, @@ -308,4 +308,3 @@ class TestSyncGoogle2Odoo(SavepointCase): self.assertEqual(events[1].start_date, date(2020, 1, 15)) self.assertEqual(events[0].google_id, '%s_20200108' % recurrence_id) self.assertEqual(events[1].google_id, '%s_20200115' % recurrence_id) - diff --git a/addons/google_calendar/tests/test_sync_odoo2google.py b/addons/google_calendar/tests/test_sync_odoo2google.py index 6cc4ff72e71..ae40fe9c57a 100644 --- a/addons/google_calendar/tests/test_sync_odoo2google.py +++ b/addons/google_calendar/tests/test_sync_odoo2google.py @@ -184,7 +184,6 @@ class TestSyncOdoo2Google(SavepointCase): 'recurrency': True, 'rrule': 'FREQ=WEEKLY;COUNT=2;BYDAY=WE', }) - event.recurrence_id to_delete = self.env['calendar.event'].with_context(active_test=False).search([('google_id', '=', google_id)]) self.assertTrue(to_delete) self.assertFalse(to_delete.active) diff --git a/addons/google_calendar/utils/google_calendar.py b/addons/google_calendar/utils/google_calendar.py index 4532ce1b708..20032241362 100644 --- a/addons/google_calendar/utils/google_calendar.py +++ b/addons/google_calendar/utils/google_calendar.py @@ -37,25 +37,20 @@ class GoogleCalendarService(): if sync_token: params['syncToken'] = sync_token try: - status, data, time = self.google_service._do_request(url, params, headers, type='GET', timeout=timeout) + status, data, time = self.google_service._do_request(url, params, headers, method='GET', timeout=timeout) except requests.HTTPError as e: if e.response.status_code == 410 and 'fullSyncRequired' in str(e.response.content): raise InvalidSyncToken("Invalid sync token. Full sync required") raise e - import pprint - pprint.pprint(data) - events = data.get('items', []) next_page_token = data.get('nextPageToken') while next_page_token: params = {'access_token': token, 'pageToken': next_page_token} - status, data, time = self.google_service._do_request(url, params, headers, type='GET', timeout=timeout) + status, data, time = self.google_service._do_request(url, params, headers, method='GET', timeout=timeout) next_page_token = data.get('nextPageToken') events += data.get('items', []) - pprint.pprint(data) - next_sync_token = data.get('nextSyncToken') default_reminders = data.get('defaultReminders') @@ -63,31 +58,26 @@ class GoogleCalendarService(): @requires_auth_token def insert(self, values, token=None, timeout=TIMEOUT): - print("INSERT") url = "/calendar/v3/calendars/primary/events" headers = {'Content-type': 'application/json', 'Authorization': 'Bearer %s' % token} if not values.get('id'): values['id'] = uuid4().hex - import pprint - pprint.pprint(values) - self.google_service._do_request(url, json.dumps(values), headers, type='POST', timeout=timeout) + self.google_service._do_request(url, json.dumps(values), headers, method='POST', timeout=timeout) return values['id'] @requires_auth_token def patch(self, event_id, values, token=None, timeout=TIMEOUT): - print("PATCH") url = "/calendar/v3/calendars/primary/events/%s" % event_id headers = {'Content-type': 'application/json', 'Authorization': 'Bearer %s' % token} - self.google_service._do_request(url, json.dumps(values), headers, type='PUT', timeout=timeout) + self.google_service._do_request(url, json.dumps(values), headers, method='PUT', timeout=timeout) @requires_auth_token def delete(self, event_id, token=None, timeout=TIMEOUT): - print("DELETE") url = "/calendar/v3/calendars/primary/events/%s" % event_id headers = {'Content-type': 'application/json'} params = {'access_token': token} try: - self.google_service._do_request(url, params, headers=headers, type='DELETE', timeout=timeout) + self.google_service._do_request(url, params, headers=headers, method='DELETE', timeout=timeout) except requests.HTTPError as e: # For some unknown reason Google can also return a 403 response when the event is already cancelled. if e.response.status_code not in (410, 403): diff --git a/addons/google_calendar/utils/google_event.py b/addons/google_calendar/utils/google_event.py index a1274049224..fc962a1d073 100644 --- a/addons/google_calendar/utils/google_event.py +++ b/addons/google_calendar/utils/google_event.py @@ -169,6 +169,6 @@ class GoogleEvent(abc.Set): def _get_model(self, env): if all([e.is_recurrence() for e in self]): return env['calendar.recurrence'] - elif all([not e.is_recurrence() for e in self]): + if all([not e.is_recurrence() for e in self]): return env['calendar.event'] - raise TypeError("Mixing Google events and Google recurrences") \ No newline at end of file + raise TypeError("Mixing Google events and Google recurrences") diff --git a/addons/google_calendar/wizard/__init__.py b/addons/google_calendar/wizard/__init__.py index 4c3bcce28a6..6e2f3e5df4e 100644 --- a/addons/google_calendar/wizard/__init__.py +++ b/addons/google_calendar/wizard/__init__.py @@ -1 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + from . import reset_account diff --git a/addons/google_calendar/wizard/reset_account.py b/addons/google_calendar/wizard/reset_account.py index 8d2b992aa23..e942ecba34c 100644 --- a/addons/google_calendar/wizard/reset_account.py +++ b/addons/google_calendar/wizard/reset_account.py @@ -12,13 +12,13 @@ class ResetGoogleAccount(models.TransientModel): _description = 'Google Calendar Account Reset' user_id = fields.Many2one('res.users', required=True) - delete_policy = fields.Selection([ - ('dont_delete', "Leave them untouched"), - ('delete_google', "Delete from the current Google Calendar account"), - ('delete_odoo', "Delete from Odoo"), - ('delete_both', "Delete from both"), - ], string="User's Existing Events", required=True, default='dont_delete', - help="This will only affect events for which the user is the owner") + delete_policy = fields.Selection( + [('dont_delete', "Leave them untouched"), + ('delete_google', "Delete from the current Google Calendar account"), + ('delete_odoo', "Delete from Odoo"), + ('delete_both', "Delete from both"), + ], string="User's Existing Events", required=True, default='dont_delete', + help="This will only affect events for which the user is the owner") sync_policy = fields.Selection([ ('new', "Synchronize only new events"), ('all', "Synchronize all existing events"), @@ -27,13 +27,15 @@ class ResetGoogleAccount(models.TransientModel): def reset_account(self): google = GoogleCalendarService(self.env['google.service']) - events = self.env['calendar.event'].search([('user_id', '=', self.user_id.id), ('google_id', '!=', False)]) - if self.delete_policy in ('delete_google' , 'delete_both'): + events = self.env['calendar.event'].search([ + ('user_id', '=', self.user_id.id), + ('google_id', '!=', False)]) + if self.delete_policy in ('delete_google', 'delete_both'): with google_calendar_token(self.user_id) as token: for event in events: google.delete(event.google_id, token=token) - if self.delete_policy in ('delete_odoo' , 'delete_both'): + if self.delete_policy in ('delete_odoo', 'delete_both'): events.google_id = False events.unlink()