From 2f4a91c0ce5ab36fcb80004a45e89c9f9b02be98 Mon Sep 17 00:00:00 2001 From: Arnaud Joset Date: Fri, 5 Feb 2021 10:38:26 +0000 Subject: [PATCH] [IMP] calendar,calendar_sms,crm,google_calendar: Improve calendars This commit improves multiple small details in the calendar application. UI, UX mostly: * some labels were confusing * the invisible attribute were not set in popover view * the sample data were missing * ... taskid: 2342252 --- addons/calendar/models/calendar_attendee.py | 3 +- addons/calendar/models/calendar_event.py | 44 +++++++-- addons/calendar/models/calendar_event_type.py | 6 ++ .../static/src/js/calendar_controller.js | 29 ++++-- addons/calendar/static/src/scss/calendar.scss | 4 + .../calendar/static/src/xml/base_calendar.xml | 6 ++ addons/calendar/views/calendar_views.xml | 91 ++++++++++++++----- addons/calendar_sms/models/calendar.py | 13 +++ addons/calendar_sms/views/calendar_views.xml | 23 +++-- addons/crm/views/calendar_views.xml | 2 +- .../views/res_config_settings_views.xml | 1 - 11 files changed, 173 insertions(+), 49 deletions(-) diff --git a/addons/calendar/models/calendar_attendee.py b/addons/calendar/models/calendar_attendee.py index f7240803c2d..ebcb8511de4 100644 --- a/addons/calendar/models/calendar_attendee.py +++ b/addons/calendar/models/calendar_attendee.py @@ -28,11 +28,12 @@ class Attendee(models.Model): event_id = fields.Many2one( 'calendar.event', 'Meeting linked', required=True, ondelete='cascade') - partner_id = fields.Many2one('res.partner', 'Contact', required=True, readonly=True) + partner_id = fields.Many2one('res.partner', 'Attendee', 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") + phone = fields.Char('Phone', related='partner_id.phone', help="Phone number of Invited Person") availability = fields.Selection( [('free', 'Available'), ('busy', 'Busy')], 'Available/Busy', readonly=True) access_token = fields.Char('Invitation Token', default=_default_access_token) diff --git a/addons/calendar/models/calendar_event.py b/addons/calendar/models/calendar_event.py index 703fb6a4e94..adf3fc95934 100644 --- a/addons/calendar/models/calendar_event.py +++ b/addons/calendar/models/calendar_event.py @@ -127,7 +127,7 @@ class Meeting(models.Model): return self._get_recurrent_fields() | self._get_time_fields() | self._get_custom_fields() | { 'id', 'active', 'allday', 'duration', 'user_id', 'interval', - 'count', 'rrule', 'recurrence_id', 'show_as'} + 'count', 'rrule', 'recurrence_id', 'show_as', 'privacy'} @api.model def _get_display_time(self, start, stop, zduration, zallday): @@ -217,15 +217,21 @@ class Meeting(models.Model): duration = fields.Float('Duration', compute='_compute_duration', store=True, readonly=False) description = fields.Text('Description') privacy = fields.Selection( - [('public', 'Everyone'), - ('private', 'Only me'), + [('public', 'Public'), + ('private', 'Private'), ('confidential', 'Only internal users')], - 'Privacy', default='public', required=True) + 'Privacy', default='public', required=True, + help="People to whom this event will be visible.") location = fields.Char('Location', tracking=True, help="Location of Event") videocall_location = fields.Char('Join Video Call', default=_default_videocall_location) show_as = fields.Selection( [('free', 'Available'), - ('busy', 'Busy')], 'Show Time as', default='busy', required=True) + ('busy', 'Busy')], 'Show as', default='busy', required=True, + help="If the time is shown as 'busy', this event will be visible to other people with either the full \ + information or simply 'busy' written depending on its privacy. Use this option to let other people know \ + that you are unavailable during that period of time. \n If the time is shown as 'free', this event won't \ + be visible to other people at all. Use this option to let other people know that you are available during \ + that period of time.") # linked document # LUL TODO use fields.Reference ? @@ -253,12 +259,13 @@ class Meeting(models.Model): string='Attendees', default=_default_partners) alarm_ids = fields.Many2many( 'calendar.alarm', 'calendar_alarm_calendar_event_rel', - string='Reminders', ondelete="restrict") + string='Reminders', ondelete="restrict", + help="Notifications sent to all attendees to remind of the meeting.") is_highlighted = fields.Boolean( compute='_compute_is_highlighted', string='Is the Event Highlighted') # RECURRENCE FIELD - recurrency = fields.Boolean('Recurrent', help="Recurrent Event") + recurrency = fields.Boolean('Recurrent') recurrence_id = fields.Many2one( 'calendar.recurrence', string="Recurrence Rule", index=True) follow_recurrence = fields.Boolean(default=False) # Indicates if an event follows the recurrence, i.e. is not an exception @@ -556,6 +563,29 @@ class Meeting(models.Model): meeting.attendee_ids._send_mail_to_attendees('calendar.calendar_template_meeting_invitation') return True + def action_mass_mailing(self): + partners_ids = self.mapped('partner_ids') + if not partners_ids: + raise UserError(_("There are no attendees on these events")) + compose_form = self.env.ref('mail.email_compose_message_wizard_form', False) + default_partners = partners_ids and partners_ids.ids + compose_ctx = dict( + default_use_template=False, + default_composition_mode='mass_mail', + default_partner_ids=default_partners, + default_subject=_("Event update") + ) + return { + 'name': _('Contact Attendees'), + 'type': 'ir.actions.act_window', + 'view_mode': 'form', + 'res_model': 'mail.compose.message', + 'views': [(compose_form.id, 'form')], + 'view_id': compose_form.id, + 'target': 'new', + 'context': compose_ctx, + } + def _apply_recurrence_values(self, values, future=True): """Apply the new recurrence rules in `values`. Create a recurrence if it does not exist and create all missing events according to the rrule. diff --git a/addons/calendar/models/calendar_event_type.py b/addons/calendar/models/calendar_event_type.py index 14d92ebca38..c1c2b2513a5 100644 --- a/addons/calendar/models/calendar_event_type.py +++ b/addons/calendar/models/calendar_event_type.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from random import randint + from odoo import fields, models @@ -9,7 +11,11 @@ class MeetingType(models.Model): _name = 'calendar.event.type' _description = 'Event Meeting Type' + def _default_color(self): + return randint(1, 11) + name = fields.Char('Name', required=True) + color = fields.Integer('Color', default=_default_color) _sql_constraints = [ ('name_uniq', 'unique (name)', "Tag name already exists !"), diff --git a/addons/calendar/static/src/js/calendar_controller.js b/addons/calendar/static/src/js/calendar_controller.js index 190125ac722..1263e4c1993 100644 --- a/addons/calendar/static/src/js/calendar_controller.js +++ b/addons/calendar/static/src/js/calendar_controller.js @@ -4,9 +4,22 @@ odoo.define('calendar.CalendarController', function (require) { const Controller = require('web.CalendarController'); const Dialog = require('web.Dialog'); const { qweb, _t } = require('web.core'); + const core = require('web.core'); + const QWeb = core.qweb; const CalendarController = Controller.extend({ + renderButtons: function ($node) { + this._super.apply(this, arguments); + const $addButton = $(QWeb.render('Calendar.calendar_add_buttons')); + this.$buttons.prepend($addButton) + const self = this; + // When clicking on "Add", create a new record in form view + this.$buttons.on('click', 'button.o-calendar-button-new', () => { + return self.do_action('calendar.action_calendar_event_notify'); + }); + }, + _askRecurrenceUpdatePolicy() { return new Promise((resolve, reject) => { new Dialog(this, { @@ -25,7 +38,6 @@ odoo.define('calendar.CalendarController', function (require) { }); }, - // TODO factorize duplicated code /** * @override * @private @@ -33,12 +45,7 @@ odoo.define('calendar.CalendarController', function (require) { */ async _onDropRecord(event) { const _super = this._super; // reference to this._super is lost after async call - if (event.data.record.recurrency) { - const recurrenceUpdate = await this._askRecurrenceUpdatePolicy(); - event.data = _.extend({}, event.data, { - 'recurrenceUpdate': recurrenceUpdate, - }); - } + await this._dropdUpdateRecord(event); _super.apply(this, arguments); }, @@ -49,14 +56,18 @@ odoo.define('calendar.CalendarController', function (require) { */ async _onUpdateRecord(event) { const _super = this._super; // reference to this._super is lost after async call + await this._dropdUpdateRecord(event); + _super.apply(this, arguments); + }, + + async _dropdUpdateRecord(event) { if (event.data.record.recurrency) { const recurrenceUpdate = await this._askRecurrenceUpdatePolicy(); event.data = _.extend({}, event.data, { 'recurrenceUpdate': recurrenceUpdate, }); } - _super.apply(this, arguments); - }, + } }); diff --git a/addons/calendar/static/src/scss/calendar.scss b/addons/calendar/static/src/scss/calendar.scss index 63cb48353aa..aafb36e2626 100644 --- a/addons/calendar/static/src/scss/calendar.scss +++ b/addons/calendar/static/src/scss/calendar.scss @@ -77,3 +77,7 @@ .o_cw_body .o_clipboard_button { padding-top: 0px !important; } + +.o_calendar_attendees { + max-width:80% !important; +} diff --git a/addons/calendar/static/src/xml/base_calendar.xml b/addons/calendar/static/src/xml/base_calendar.xml index f2f30f361f6..3f2b083477e 100644 --- a/addons/calendar/static/src/xml/base_calendar.xml +++ b/addons/calendar/static/src/xml/base_calendar.xml @@ -56,4 +56,10 @@ + + + + + + diff --git a/addons/calendar/views/calendar_views.xml b/addons/calendar/views/calendar_views.xml index 3c707f03d8d..00754652788 100644 --- a/addons/calendar/views/calendar_views.xml +++ b/addons/calendar/views/calendar_views.xml @@ -6,7 +6,7 @@ calendar.event.type calendar.event.type - + @@ -23,7 +23,7 @@ calendar.alarm.tree calendar.alarm - + @@ -65,14 +65,25 @@ calendar.event.tree calendar.event - - - - - - - + +
+
+ + + + + + + + + + + + +
@@ -104,12 +115,16 @@

-

+
-

+ class="oe_inline o_calendar_attendees" + /> +
+
+ @@ -125,20 +140,19 @@ - + - - + - + @@ -200,12 +214,13 @@ -