[MERGE] calendar: improve wording of calendar mail templates
Purpose of this merge is to make templates easier to preview and edit as weel as to improve their content. This is achieved notably by lessening use of custom rendering context and trying to fix as much error-prone jinja statements. In this commit we also make ``calendar_template_meeting_reminder`` template looking more like other templates. There were some rendering differences that do not seem really wanted. ``calendar_template_meeting_reminder`` was also using an old ``force_event_id`` key not replaced by recurrent_id field on attendee. This merge improves few strings of the invitation mail being sent while booking an online appointment. Online appointment is computed based on ``appointment_type_id`` field being defined. Some tweaks in wording made it necessary to know if recipient is the responsible, customer or an added attendee on the event, leading to some tooling code added on event model. The main changes includes * for customer, remove the CTAs to accept / decline event as attendee are automatically set as accepted; * depending on recipient, improve wording of the mail accordingly and mention appointment type in the mail; Some code reodering and cleaning is also performed in this merge to ease reading and understanding of calendar event and attendee models. LINKS Task ID-2199620 COM PR #64925 ENT PR odoo/enterprise#15914 UPG PR odoo/upgrade# Related: odoo/upgrade#2282 Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
|
||||
{
|
||||
'name': 'Calendar',
|
||||
'version': '1.0',
|
||||
'version': '1.1',
|
||||
'sequence': 165,
|
||||
'depends': ['base', 'mail'],
|
||||
'summary': "Schedule employees' meetings",
|
||||
|
||||
@@ -11,26 +11,46 @@
|
||||
<field name="lang">${object.partner_id.lang}</field>
|
||||
<field name="body_html" type="html">
|
||||
<div>
|
||||
% set colors = ctx.get('colors', {})
|
||||
% set recurrent = object.recurrence_id and not ctx['ignore_recurrence']
|
||||
% set colors = {'needsAction': 'grey', 'accepted': 'green', 'tentative': '#FFFF00', 'declined': 'red'}
|
||||
% set is_online = 'appointment_type_id' in object.event_id and object.event_id.appointment_type_id
|
||||
% set customer = object.event_id.find_partner_customer()
|
||||
% set target_responsible = object.partner_id == object.event_id.partner_id
|
||||
% set target_customer = object.partner_id == customer
|
||||
<p>
|
||||
Hello ${object.common_name},<br/><br/>
|
||||
${object.event_id.user_id.partner_id.name} invited you to the ${object.event_id.name} meeting of ${object.event_id.user_id.company_id.name}.
|
||||
|
||||
% if is_online and target_customer:
|
||||
Your appointment <strong>${object.event_id.appointment_type_id.name}</strong> with ${object.event_id.user_id.name} has been booked.
|
||||
|
||||
% elif is_online and target_responsible:
|
||||
% if customer
|
||||
${customer.name} scheduled the following appointment <strong>${object.event_id.appointment_type_id.name}</strong> with you.
|
||||
% else
|
||||
Your appointment <strong>${object.event_id.appointment_type_id.name}</strong> has been booked.
|
||||
% endif
|
||||
|
||||
% elif not target_responsible:
|
||||
${object.event_id.user_id.partner_id.name} invited you for the <strong>${object.event_id.name}</strong> meeting.
|
||||
|
||||
% else:
|
||||
Your meeting <strong>${object.event_id.name}</strong> has been booked.
|
||||
% endif
|
||||
</p>
|
||||
<div style="text-align: center; margin: 16px 0px 16px 0px;">
|
||||
% set target = 'recurrence' if recurrent else 'meeting'
|
||||
<a href="/calendar/${target}/accept?token=${object.access_token}&id=${object.event_id.id}"
|
||||
% if not is_online or object.state != 'accepted':
|
||||
<a href="/calendar/meeting/accept?token=${object.access_token}&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?token=${object.access_token}&id=${object.event_id.id}"
|
||||
<a href="/calendar/meeting/decline?token=${object.access_token}&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>
|
||||
% endif
|
||||
<a href="/calendar/meeting/view?token=${object.access_token}&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>
|
||||
${'Reschedule' if is_online and target_customer else 'View'}
|
||||
</a>
|
||||
</div>
|
||||
<table border="0" cellpadding="0" cellspacing="0"><tr>
|
||||
% if not recurrent:
|
||||
<td width="130px;">
|
||||
<div style="border-top-left-radius: 3px; border-top-right-radius: 3px; font-size: 12px; border-collapse: separate; text-align: center; font-weight: bold; color: #ffffff; min-height: 18px; background-color: #875A7B; border: 1px solid #875A7B;">
|
||||
${object.event_id.get_interval('dayname', tz=object.partner_id.tz if not object.event_id.allday else None)}
|
||||
@@ -46,24 +66,35 @@
|
||||
</div>
|
||||
</td>
|
||||
<td width="20px;"/>
|
||||
% endif
|
||||
<td style="padding-top: 5px;">
|
||||
<p><strong>Details of the event</strong></p>
|
||||
<ul>
|
||||
% if is_online:
|
||||
<li>Appointment Type: ${object.event_id.appointment_type_id.name}</li>
|
||||
% endif
|
||||
% if object.event_id.location:
|
||||
<li>Location: ${object.event_id.location}
|
||||
(<a target="_blank" href="http://maps.google.com/maps?oi=map&q=${object.event_id.location}">View Map</a>)
|
||||
</li>
|
||||
% endif
|
||||
% if object.event_id.description :
|
||||
<li>Description: ${object.event_id.description}</li>
|
||||
% endif
|
||||
% if recurrent:
|
||||
<li>When: ${object.recurrence_id.name}</li>
|
||||
% endif
|
||||
% if not object.event_id.allday and object.event_id.duration
|
||||
<li>Duration: ${('%dH%02d' % (object.event_id.duration,round(object.event_id.duration*60)%60))}</li>
|
||||
% endif
|
||||
% if not is_online and object.event_id.description :
|
||||
<li>Description: ${object.event_id.description}</li>
|
||||
% elif is_online and object.event_id.description:
|
||||
% set splitted_description = object.event_id.description_to_html_lines()
|
||||
<li>Description:
|
||||
<ul>
|
||||
% for description_line in splitted_description:
|
||||
<li>${description_line | safe}</li>
|
||||
% endfor
|
||||
</ul>
|
||||
</li>
|
||||
% endif
|
||||
<li>Attendees
|
||||
<ul>
|
||||
% for attendee in object.event_id.attendee_ids:
|
||||
@@ -105,18 +136,38 @@
|
||||
<field name="lang">${object.partner_id.lang}</field>
|
||||
<field name="body_html" type="html">
|
||||
<div>
|
||||
% set colors = ctx.get('colors', {})
|
||||
% set recurrent = object.recurrence_id and not ctx['ignore_recurrence']
|
||||
% set colors = {'needsAction': 'grey', 'accepted': 'green', 'tentative': '#FFFF00', 'declined': 'red'}
|
||||
% set is_online = 'appointment_type_id' in object.event_id and object.event_id.appointment_type_id
|
||||
% set customer = object.event_id.find_partner_customer()
|
||||
% set target_responsible = object.partner_id == object.event_id.partner_id
|
||||
% set target_customer = object.partner_id == customer
|
||||
<p>
|
||||
Hello ${object.common_name},<br/><br/>
|
||||
The date of the meeting has been updated. The meeting ${object.event_id.name} created by ${object.event_id.user_id.partner_id.name} is now scheduled for ${object.event_id.get_display_time_tz(tz=object.partner_id.tz)}.
|
||||
% if is_online and target_responsible:
|
||||
% if customer:
|
||||
The date of your appointment with ${customer.name} has been updated.
|
||||
% else
|
||||
Your appointment has been updated.
|
||||
% endif
|
||||
The appointment <strong>${object.event_id.appointment_type_id.name}</strong> is now scheduled for
|
||||
${object.event_id.get_display_time_tz(tz=object.partner_id.tz)}.
|
||||
|
||||
% elif is_online and target_customer:
|
||||
The date of your appointment with ${object.event_id.user_id.partner_id.name} has been updated.
|
||||
The appointment <strong>${object.event_id.appointment_type_id.name}</strong> is now scheduled for
|
||||
${object.event_id.get_display_time_tz(tz=object.partner_id.tz)}.
|
||||
|
||||
% else:
|
||||
The date of the meeting has been updated.
|
||||
The meeting <strong>${object.event_id.name}</strong> created by ${object.event_id.user_id.partner_id.name} is now scheduled for
|
||||
${object.event_id.get_display_time_tz(tz=object.partner_id.tz)}.
|
||||
% endif
|
||||
</p>
|
||||
<div style="text-align: center; margin: 16px 0px 16px 0px;">
|
||||
% set target = 'recurrence' if recurrent else 'meeting'
|
||||
<a href="/calendar/${target}/accept?token=${object.access_token}&id=${object.event_id.id}"
|
||||
<a href="/calendar/meeting/accept?token=${object.access_token}&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?token=${object.access_token}&id=${object.event_id.id}"
|
||||
<a href="/calendar/meeting/decline?token=${object.access_token}&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?token=${object.access_token}&id=${object.event_id.id}"
|
||||
@@ -124,7 +175,6 @@
|
||||
View</a>
|
||||
</div>
|
||||
<table border="0" cellpadding="0" cellspacing="0"><tr>
|
||||
% if not recurrent:
|
||||
<td width="130px;">
|
||||
<div style="border-top-left-radius: 3px; border-top-right-radius: 3px; font-size: 12px; border-collapse: separate; text-align: center; font-weight: bold; color: #ffffff; min-height: 18px; background-color: #875A7B; border: 1px solid #875A7B;">
|
||||
${object.event_id.get_interval('dayname', tz=object.partner_id.tz if not object.event_id.allday else None)}
|
||||
@@ -140,7 +190,6 @@
|
||||
</div>
|
||||
</td>
|
||||
<td width="20px;"/>
|
||||
% endif
|
||||
<td style="padding-top: 5px;">
|
||||
<p><strong>Details of the event</strong></p>
|
||||
<ul>
|
||||
@@ -149,15 +198,24 @@
|
||||
(<a target="_blank" href="http://maps.google.com/maps?oi=map&q=${object.event_id.location}">View Map</a>)
|
||||
</li>
|
||||
% endif
|
||||
% if object.event_id.description :
|
||||
<li>Description: ${object.event_id.description}</li>
|
||||
% endif
|
||||
% if recurrent:
|
||||
<li>When: ${object.recurrence_id.name}</li>
|
||||
% endif
|
||||
% if not object.event_id.allday and object.event_id.duration
|
||||
<li>Duration: ${('%dH%02d' % (object.event_id.duration,round(object.event_id.duration*60)%60))}</li>
|
||||
% endif
|
||||
% if not is_online and object.event_id.description :
|
||||
<li>Description: ${object.event_id.description}</li>
|
||||
% elif is_online and object.event_id.description:
|
||||
% set splitted_description = object.event_id.description_to_html_lines()
|
||||
<li>Description:
|
||||
<ul>
|
||||
% for description_line in splitted_description:
|
||||
<li>${description_line | safe}</li>
|
||||
% endfor
|
||||
</ul>
|
||||
</li>
|
||||
% endif
|
||||
<li>Attendees
|
||||
<ul>
|
||||
% for attendee in object.event_id.attendee_ids:
|
||||
@@ -199,21 +257,18 @@
|
||||
<field name="lang">${object.partner_id.lang}</field>
|
||||
<field name="body_html" type="html">
|
||||
<div>
|
||||
% set colors = {'needsAction': 'grey', 'accepted': 'green', 'tentative': '#FFFF00', 'declined': 'red'}
|
||||
<!--
|
||||
In a recurring event case, the object.event_id is always the first event
|
||||
This makes the event date (and a lot of other information) incorrect
|
||||
-->
|
||||
% set event_id = ctx.get('force_event_id') or object.event_id
|
||||
% set colors = {'needsAction': 'grey', 'accepted': 'green', 'tentative': '#FFFF00', 'declined': 'red'}
|
||||
% set is_online = 'appointment_type_id' in object.event_id and object.event_id.appointment_type_id
|
||||
% set recurrent = object.recurrence_id and not ctx.get('calendar_template_ignore_recurrence')
|
||||
<p>
|
||||
Hello ${object.common_name},<br/><br/>
|
||||
This is a reminder for the below event :
|
||||
</p>
|
||||
<div style="text-align: center; margin: 16px 0px 16px 0px;">
|
||||
<a href="/calendar/meeting/accept?token=${object.access_token}&id=${object.event_id.id}"
|
||||
<a href="/calendar/${'recurrence' if recurrent else 'meeting'}/accept?token=${object.access_token}&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?token=${object.access_token}&id=${object.event_id.id}"
|
||||
<a href="/calendar/${'recurrence' if recurrent else 'meeting'}/decline?token=${object.access_token}&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?token=${object.access_token}&id=${object.event_id.id}"
|
||||
@@ -223,16 +278,16 @@
|
||||
<table border="0" cellpadding="0" cellspacing="0"><tr>
|
||||
<td width="130px;">
|
||||
<div style="border-top-left-radius: 3px; border-top-right-radius: 3px; font-size: 12px; border-collapse: separate; text-align: center; font-weight: bold; color: #ffffff; min-height: 18px; background-color: #875A7B; border: 1px solid #875A7B;">
|
||||
${event_id.get_interval('dayname', tz=object.partner_id.tz if not event_id.allday else None)}
|
||||
${object.event_id.get_interval('dayname', tz=object.partner_id.tz if not object.event_id.allday else None)}
|
||||
</div>
|
||||
<div style="font-size: 48px; min-height: auto; font-weight: bold; text-align: center; color: #5F5F5F; background-color: #F8F8F8; border: 1px solid #875A7B;">
|
||||
${event_id.get_interval('day', tz=object.partner_id.tz if not event_id.allday else None)}
|
||||
${object.event_id.get_interval('day', tz=object.partner_id.tz if not object.event_id.allday else None)}
|
||||
</div>
|
||||
<div style='font-size: 12px; text-align: center; font-weight: bold; color: #ffffff; background-color: #875A7B;'>
|
||||
${event_id.get_interval('month', tz=object.partner_id.tz if not event_id.allday else None)}
|
||||
${object.event_id.get_interval('month', tz=object.partner_id.tz if not object.event_id.allday else None)}
|
||||
</div>
|
||||
<div style="border-collapse: separate; color: #5F5F5F; text-align: center; font-size: 12px; border-bottom-right-radius: 3px; font-weight: bold; border: 1px solid #875A7B; border-bottom-left-radius: 3px;">
|
||||
${not event_id.allday and event_id.get_interval('time', tz=object.partner_id.tz) or ''}
|
||||
${not object.event_id.allday and object.event_id.get_interval('time', tz=object.partner_id.tz) or ''}
|
||||
</div>
|
||||
</td>
|
||||
<td width="20px;"/>
|
||||
@@ -244,11 +299,23 @@
|
||||
(<a target="_blank" href="http://maps.google.com/maps?oi=map&q=${object.event_id.location}">View Map</a>)
|
||||
</li>
|
||||
% endif
|
||||
% if object.event_id.description :
|
||||
<li>Description: ${object.event_id.description}</li>
|
||||
% if recurrent:
|
||||
<li>When: ${object.recurrence_id.name}</li>
|
||||
% endif
|
||||
% if not object.event_id.allday and object.event_id.duration
|
||||
<li>Duration: ${('%dH%02d' % (object.event_id.duration,(object.event_id.duration*60)%60))}</li>
|
||||
<li>Duration: ${('%dH%02d' % (object.event_id.duration,round(object.event_id.duration*60)%60))}</li>
|
||||
% endif
|
||||
% if not is_online and object.event_id.description :
|
||||
<li>Description: ${object.event_id.description}</li>
|
||||
% elif is_online and object.event_id.description:
|
||||
% set splitted_description = object.event_id.description_to_html_lines()
|
||||
<li>Description:
|
||||
<ul>
|
||||
% for description_line in splitted_description:
|
||||
<li>${description_line | safe}</li>
|
||||
% endfor
|
||||
</ul>
|
||||
</li>
|
||||
% endif
|
||||
<li>Attendees
|
||||
<ul>
|
||||
|
||||
@@ -167,10 +167,9 @@ class AlarmManager(models.AbstractModel):
|
||||
# Executed via cron
|
||||
events = self._get_events_to_notify('email')
|
||||
attendees = events.attendee_ids.filtered(lambda a: a.state != 'declined')
|
||||
attendees._send_mail_to_attendees(
|
||||
attendees.with_context(calendar_template_ignore_recurrence=True)._send_mail_to_attendees(
|
||||
'calendar.calendar_template_meeting_reminder',
|
||||
force_send=True,
|
||||
ignore_recurrence=True,
|
||||
)
|
||||
|
||||
@api.model
|
||||
|
||||
@@ -15,6 +15,7 @@ class Attendee(models.Model):
|
||||
_name = 'calendar.attendee'
|
||||
_rec_name = 'common_name'
|
||||
_description = 'Calendar Attendee Information'
|
||||
_order = 'create_date ASC'
|
||||
|
||||
def _default_access_token(self):
|
||||
return uuid.uuid4().hex
|
||||
@@ -26,18 +27,20 @@ class Attendee(models.Model):
|
||||
('accepted', 'Accepted'),
|
||||
]
|
||||
|
||||
event_id = fields.Many2one(
|
||||
'calendar.event', 'Meeting linked', required=True, ondelete='cascade')
|
||||
# event
|
||||
event_id = fields.Many2one('calendar.event', 'Meeting linked', required=True, ondelete='cascade')
|
||||
recurrence_id = fields.Many2one('calendar.recurrence', related='event_id.recurrence_id')
|
||||
# attendee
|
||||
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")
|
||||
common_name = fields.Char('Common name', compute='_compute_common_name', store=True)
|
||||
access_token = fields.Char('Invitation Token', default=_default_access_token)
|
||||
# state
|
||||
state = fields.Selection(STATE_SELECTION, string='Status', readonly=True, default='needsAction',
|
||||
help="Status of the attendee's participation")
|
||||
availability = fields.Selection(
|
||||
[('free', 'Available'), ('busy', 'Busy')], 'Available/Busy', readonly=True)
|
||||
access_token = fields.Char('Invitation Token', default=_default_access_token)
|
||||
recurrence_id = fields.Many2one('calendar.recurrence', related='event_id.recurrence_id')
|
||||
|
||||
@api.depends('partner_id', 'partner_id.name', 'email')
|
||||
def _compute_common_name(self):
|
||||
@@ -62,6 +65,10 @@ class Attendee(models.Model):
|
||||
self._unsubscribe_partner()
|
||||
return super().unlink()
|
||||
|
||||
@api.returns('self', lambda value: value.id)
|
||||
def copy(self, default=None):
|
||||
raise UserError(_('You cannot duplicate a calendar attendee.'))
|
||||
|
||||
def _subscribe_partner(self):
|
||||
for event in self.event_id:
|
||||
partners = (event.attendee_ids & self).partner_id - event.message_partner_ids
|
||||
@@ -74,22 +81,16 @@ class Attendee(models.Model):
|
||||
partners = (event.attendee_ids & self).partner_id & event.message_partner_ids
|
||||
event.message_unsubscribe(partner_ids=partners.ids)
|
||||
|
||||
@api.returns('self', lambda value: value.id)
|
||||
def copy(self, default=None):
|
||||
raise UserError(_('You cannot duplicate a calendar attendee.'))
|
||||
|
||||
def _send_mail_to_attendees(self, template_xmlid, force_send=False, ignore_recurrence=False):
|
||||
def _send_mail_to_attendees(self, template_xmlid, force_send=False):
|
||||
""" Send mail for event invitation to event attendees.
|
||||
:param template_xmlid: xml id of the email template to use to send the invitation
|
||||
:param force_send: if set to True, the mail(s) will be sent immediately (instead of the next queue processing)
|
||||
:param ignore_recurrence: ignore event recurrence
|
||||
"""
|
||||
res = False
|
||||
|
||||
if self.env['ir.config_parameter'].sudo().get_param('calendar.block_mail') or self._context.get("no_mail_to_attendees"):
|
||||
return res
|
||||
|
||||
calendar_view = self.env.ref('calendar.view_calendar_event_calendar')
|
||||
invitation_template = self.env.ref(template_xmlid, raise_if_not_found=False)
|
||||
if not invitation_template:
|
||||
_logger.warning("Template %s could not be found. %s not notified." % (template_xmlid, self))
|
||||
@@ -97,25 +98,8 @@ class Attendee(models.Model):
|
||||
# get ics file for all meetings
|
||||
ics_files = self.mapped('event_id')._get_ics_file()
|
||||
|
||||
# prepare rendering context for mail template
|
||||
colors = {
|
||||
'needsAction': 'grey',
|
||||
'accepted': 'green',
|
||||
'tentative': '#FFFF00',
|
||||
'declined': 'red'
|
||||
}
|
||||
rendering_context = dict(self._context)
|
||||
rendering_context.update({
|
||||
'colors': colors,
|
||||
'ignore_recurrence': ignore_recurrence,
|
||||
'action_id': self.env['ir.actions.act_window'].sudo().search([('view_id', '=', calendar_view.id)], limit=1).id,
|
||||
'dbname': self._cr.dbname,
|
||||
'base_url': self.env['ir.config_parameter'].sudo().get_param('web.base.url', default='http://localhost:8069'),
|
||||
})
|
||||
|
||||
for attendee in self:
|
||||
if attendee.email and attendee.partner_id != self.env.user.partner_id:
|
||||
# FIXME: is ics_file text or bytes?
|
||||
event_id = attendee.event_id.id
|
||||
ics_file = ics_files.get(event_id)
|
||||
|
||||
@@ -126,7 +110,7 @@ class Attendee(models.Model):
|
||||
'mimetype': 'text/calendar',
|
||||
'datas': base64.b64encode(ics_file)})
|
||||
]
|
||||
body = invitation_template.with_context(rendering_context)._render_field(
|
||||
body = invitation_template._render_field(
|
||||
'body_html',
|
||||
attendee.ids,
|
||||
compute_lang=True,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,11 +9,11 @@ class Attendee(models.Model):
|
||||
_name = 'calendar.attendee'
|
||||
_inherit = 'calendar.attendee'
|
||||
|
||||
def _send_mail_to_attendees(self, template_xmlid, force_send=False, ignore_recurrence=False):
|
||||
def _send_mail_to_attendees(self, template_xmlid, force_send=False):
|
||||
""" Override
|
||||
If not synced with Google, let Odoo in charge of sending emails
|
||||
Otherwise, nothing to do: Google will send them
|
||||
"""
|
||||
with google_calendar_token(self.env.user.sudo()) as token:
|
||||
if not token:
|
||||
super()._send_mail_to_attendees(template_xmlid, force_send, ignore_recurrence)
|
||||
super()._send_mail_to_attendees(template_xmlid, force_send)
|
||||
|
||||
@@ -10,11 +10,11 @@ class Attendee(models.Model):
|
||||
_name = 'calendar.attendee'
|
||||
_inherit = 'calendar.attendee'
|
||||
|
||||
def _send_mail_to_attendees(self, template_xmlid, force_send=False, ignore_recurrence=False):
|
||||
def _send_mail_to_attendees(self, template_xmlid, force_send=False):
|
||||
""" Override the super method
|
||||
If not synced with Microsoft Outlook, let Odoo in charge of sending emails
|
||||
Otherwise, Microsoft Outlook will send them
|
||||
"""
|
||||
with microsoft_calendar_token(self.env.user.sudo()) as token:
|
||||
if not token:
|
||||
super()._send_mail_to_attendees(template_xmlid, force_send, ignore_recurrence)
|
||||
super()._send_mail_to_attendees(template_xmlid, force_send)
|
||||
|
||||
Reference in New Issue
Block a user