summaryrefslogtreecommitdiff
path: root/addons/calendar
diff options
context:
space:
mode:
Diffstat (limited to 'addons/calendar')
-rw-r--r--addons/calendar/controllers/main.py47
-rw-r--r--addons/calendar/data/mail_data.xml18
-rw-r--r--addons/calendar/models/calendar_alarm.py19
-rw-r--r--addons/calendar/models/calendar_alarm_manager.py14
-rw-r--r--addons/calendar/models/calendar_attendee.py24
-rw-r--r--addons/calendar/models/calendar_event.py92
-rw-r--r--addons/calendar/models/calendar_recurrence.py31
-rw-r--r--addons/calendar/models/ir_http.py4
-rw-r--r--addons/calendar/models/res_partner.py6
-rw-r--r--addons/calendar/models/res_users.py8
-rw-r--r--addons/calendar/security/calendar_security.xml6
-rw-r--r--addons/calendar/static/src/js/base_calendar.js1
-rw-r--r--addons/calendar/static/src/js/calendar_controller.js2
-rw-r--r--addons/calendar/static/src/js/calendar_model.js3
-rw-r--r--addons/calendar/tests/test_calendar.py18
15 files changed, 168 insertions, 125 deletions
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 @@
</p>
<div style="text-align: center; margin: 16px 0px 16px 0px;">
% set target = 'recurrence' if recurrent else 'meeting'
- <a href="/calendar/${target}/accept?db=${'dbname' in ctx and ctx['dbname'] or ''}&amp;token=${object.access_token}&amp;action=${'action_id' in ctx and ctx['action_id'] or ''}&amp;id=${object.event_id.id}"
+ <a href="/calendar/${target}/accept?token=${object.access_token}&amp;id=${object.event_id.id}"
style="padding: 5px 10px; color: #FFFFFF; text-decoration: none; background-color: #875A7B; border: 1px solid #875A7B; border-radius: 3px">
Accept</a>
- <a href="/calendar/${target}/decline?db=${'dbname' in ctx and ctx['dbname'] or '' }&amp;token=${object.access_token}&amp;action=${'action_id' in ctx and ctx['action_id'] or ''}&amp;id=${object.event_id.id}"
+ <a href="/calendar/${target}/decline?token=${object.access_token}&amp;id=${object.event_id.id}"
style="padding: 5px 10px; color: #FFFFFF; text-decoration: none; background-color: #875A7B; border: 1px solid #875A7B; border-radius: 3px">
Decline</a>
- <a href="/calendar/meeting/view?db=${'dbname' in ctx and ctx['dbname'] or ''}&amp;token=${object.access_token}&amp;action=${'action_id' in ctx and ctx['action_id'] or ''}&amp;id=${object.event_id.id}"
+ <a href="/calendar/meeting/view?token=${object.access_token}&amp;id=${object.event_id.id}"
style="padding: 5px 10px; color: #FFFFFF; text-decoration: none; background-color: #875A7B; border: 1px solid #875A7B; border-radius: 3px">
View</a>
</div>
@@ -110,13 +110,13 @@
</p>
<div style="text-align: center; margin: 16px 0px 16px 0px;">
% set target = 'recurrence' if recurrent else 'meeting'
- <a href="/calendar/${target}/accept?db=${'dbname' in ctx and ctx['dbname'] or ''}&amp;token=${object.access_token}&amp;action=${'action_id' in ctx and ctx['action_id'] or ''}&amp;id=${object.event_id.id}"
+ <a href="/calendar/${target}/accept?token=${object.access_token}&amp;id=${object.event_id.id}"
style="padding: 5px 10px; color: #FFFFFF; text-decoration: none; background-color: #875A7B; border: 1px solid #875A7B; border-radius: 3px">
Accept</a>
- <a href="/calendar/${target}/decline?db=${'dbname' in ctx and ctx['dbname'] or '' }&amp;token=${object.access_token}&amp;action=${'action_id' in ctx and ctx['action_id'] or ''}&amp;id=${object.event_id.id}"
+ <a href="/calendar/${target}/decline?token=${object.access_token}&amp;id=${object.event_id.id}"
style="padding: 5px 10px; color: #FFFFFF; text-decoration: none; background-color: #875A7B; border: 1px solid #875A7B; border-radius: 3px">
Decline</a>
- <a href="/calendar/meeting/view?db=${'dbname' in ctx and ctx['dbname'] or ''}&amp;token=${object.access_token}&amp;action=${'action_id' in ctx and ctx['action_id'] or ''}&amp;id=${object.event_id.id}"
+ <a href="/calendar/meeting/view?token=${object.access_token}&amp;id=${object.event_id.id}"
style="padding: 5px 10px; color: #FFFFFF; text-decoration: none; background-color: #875A7B; border: 1px solid #875A7B; border-radius: 3px">
View</a>
</div>
@@ -204,13 +204,13 @@
This is a reminder for the below event :
</p>
<div style="text-align: center; margin: 16px 0px 16px 0px;">
- <a href="/calendar/meeting/accept?db=${'dbname' in ctx and ctx['dbname'] or ''}&amp;token=${object.access_token}&amp;action=${'action_id' in ctx and ctx['action_id'] or ''}&amp;id=${object.event_id.id}"
+ <a href="/calendar/meeting/accept?token=${object.access_token}&amp;event_id=${object.event_id.id}"
style="padding: 5px 10px; color: #FFFFFF; text-decoration: none; background-color: #875A7B; border: 1px solid #875A7B; border-radius: 3px">
Accept</a>
- <a href="/calendar/meeting/decline?db=${'dbname' in ctx and ctx['dbname'] or '' }&amp;token=${object.access_token}&amp;action=${'action_id' in ctx and ctx['action_id'] or ''}&amp;id=${object.event_id.id}"
+ <a href="/calendar/meeting/decline?token=${object.access_token}&amp;id=${object.event_id.id}"
style="padding: 5px 10px; color: #FFFFFF; text-decoration: none; background-color: #875A7B; border: 1px solid #875A7B; border-radius: 3px">
Decline</a>
- <a href="/calendar/meeting/view?db=${'dbname' in ctx and ctx['dbname'] or ''}&amp;token=${object.access_token}&amp;action=${'action_id' in ctx and ctx['action_id'] or ''}&amp;id=${object.event_id.id}"
+ <a href="/calendar/meeting/view?token=${object.access_token}&amp;id=${object.event_id.id}"
style="padding: 5px 10px; color: #FFFFFF; text-decoration: none; background-color: #875A7B; border: 1px solid #875A7B; border-radius: 3px">
View</a>
</div>
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 @@
<record id="calendar_event_rule_my" model="ir.rule">
<field name="name">Own events</field>
<field ref="model_calendar_event" name="model_id"/>
- <field name="domain_force">[('partner_ids','in',user.partner_id.id)]</field>
+ <field name="domain_force">[('partner_ids', 'in', user.partner_id.id)]</field>
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
</record>
<record id="calendar_event_rule_employee" model="ir.rule">
<field ref="model_calendar_event" name="model_id"/>
<field name="name">All Calendar Event for employees</field>
- <field name="domain_force">[(1,'=',1)]</field>
+ <field name="domain_force">[(1, '=', 1)]</field>
<field eval="[(4,ref('base.group_user'))]" name="groups"/>
</record>
<record id="calendar_attendee_rule_my" model="ir.rule">
<field name="name">Own attendees</field>
<field ref="model_calendar_attendee" name="model_id"/>
- <field name="domain_force">[(1,'=',1)]</field>
+ <field name="domain_force">[(1, '=', 1)]</field>
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
</record>
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)