[IMP] calendar(_sms): add template selection on reminders
The purpose is to allow the user to have the opportunity to manage what is going to be send as reminders. He can now access to the template or create a new one when the type of reminder is email or sms. In case of a simple notification, a new text field is added to add custom content. Task ID-2191254 COM PR odoo/odoo#68443 UPG PR odoo/upgrade#2313 Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
committed by
Thibault Delavallée
parent
f87a0eb763
commit
4a616e1ab1
@@ -26,9 +26,9 @@ If you need to manage your meetings, you should install the CRM module.
|
||||
'security/ir.model.access.csv',
|
||||
'security/calendar_security.xml',
|
||||
'data/calendar_cron.xml',
|
||||
'data/mail_template_data.xml',
|
||||
'data/calendar_data.xml',
|
||||
'data/mail_data_various.xml',
|
||||
'data/mail_template_data.xml',
|
||||
'views/mail_activity_views.xml',
|
||||
'views/calendar_templates.xml',
|
||||
'views/calendar_views.xml',
|
||||
|
||||
@@ -36,12 +36,14 @@
|
||||
<field name="duration" eval="3" />
|
||||
<field name="interval">hours</field>
|
||||
<field name="alarm_type">email</field>
|
||||
<field name="mail_template_id" ref="calendar.calendar_template_meeting_reminder"/>
|
||||
</record>
|
||||
<record id="alarm_mail_2" model="calendar.alarm">
|
||||
<field name="name">Email - 6 Hours</field>
|
||||
<field name="duration" eval="6" />
|
||||
<field name="interval">hours</field>
|
||||
<field name="alarm_type">email</field>
|
||||
<field name="mail_template_id" ref="calendar.calendar_template_meeting_reminder"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
</odoo>
|
||||
|
||||
@@ -21,6 +21,12 @@ class Alarm(models.Model):
|
||||
'Duration in minutes', store=True,
|
||||
search='_search_duration_minutes', compute='_compute_duration_minutes',
|
||||
help="Duration in minutes")
|
||||
mail_template_id = fields.Many2one(
|
||||
'mail.template', string="Email Template",
|
||||
domain=[('model', 'in', ['calendar.attendee'])],
|
||||
compute='_compute_mail_template_id', readonly=False, store=True,
|
||||
help="Template used to render mail reminder content.")
|
||||
body = fields.Text("Additional Message", help="Additional message that would be sent with the notification for the reminder")
|
||||
|
||||
@api.depends('interval', 'duration')
|
||||
def _compute_duration_minutes(self):
|
||||
@@ -34,6 +40,14 @@ class Alarm(models.Model):
|
||||
else:
|
||||
alarm.duration_minutes = 0
|
||||
|
||||
@api.depends('alarm_type', 'mail_template_id')
|
||||
def _compute_mail_template_id(self):
|
||||
for alarm in self:
|
||||
if alarm.alarm_type == 'email' and not alarm.mail_template_id:
|
||||
alarm.mail_template_id = self.env['ir.model.data'].xmlid_to_res_id('calendar.calendar_template_meeting_reminder')
|
||||
elif alarm.alarm_type != 'email' or not alarm.mail_template_id:
|
||||
alarm.mail_template_id = False
|
||||
|
||||
def _search_duration_minutes(self, operator, value):
|
||||
return [
|
||||
'|', '|',
|
||||
|
||||
@@ -5,6 +5,7 @@ import logging
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.tools import plaintext2html
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -135,7 +136,7 @@ class AlarmManager(models.AbstractModel):
|
||||
})
|
||||
return result
|
||||
|
||||
def _get_events_to_notify(self, ttype):
|
||||
def _get_events_by_alarm_to_notify(self, alarm_type):
|
||||
"""
|
||||
Get the events with an alarm of the given type between the cron
|
||||
last call and now.
|
||||
@@ -146,7 +147,7 @@ class AlarmManager(models.AbstractModel):
|
||||
already.
|
||||
"""
|
||||
self.env.cr.execute('''
|
||||
SELECT "event"."id"
|
||||
SELECT "alarm"."id", "event"."id"
|
||||
FROM "calendar_event" AS "event"
|
||||
JOIN "calendar_alarm_calendar_event_rel" AS "event_alarm_rel"
|
||||
ON "event"."id" = "event_alarm_rel"."calendar_event_id"
|
||||
@@ -157,20 +158,33 @@ class AlarmManager(models.AbstractModel):
|
||||
AND "event"."active"
|
||||
AND "event"."start" - CAST("alarm"."duration" || ' ' || "alarm"."interval" AS Interval) >= %s
|
||||
AND "event"."start" - CAST("alarm"."duration" || ' ' || "alarm"."interval" AS Interval) < now() at time zone 'utc'
|
||||
)''', [ttype, self.env.context['lastcall']])
|
||||
)''', [alarm_type, self.env.context['lastcall']])
|
||||
|
||||
ids = [row[0] for row in self.env.cr.fetchall()]
|
||||
return self.env['calendar.event'].browse(ids)
|
||||
events_by_alarm = {}
|
||||
for alarm_id, event_id in self.env.cr.fetchall():
|
||||
events_by_alarm.setdefault(alarm_id, list()).append(event_id)
|
||||
return events_by_alarm
|
||||
|
||||
@api.model
|
||||
def _send_reminder(self):
|
||||
# Executed via cron
|
||||
events = self._get_events_to_notify('email')
|
||||
events_by_alarm = self._get_events_by_alarm_to_notify('email')
|
||||
if not events_by_alarm:
|
||||
return
|
||||
|
||||
event_ids = list(set(event_id for event_ids in events_by_alarm.values() for event_id in event_ids))
|
||||
events = self.env['calendar.event'].browse(event_ids)
|
||||
attendees = events.attendee_ids.filtered(lambda a: a.state != 'declined')
|
||||
attendees.with_context(calendar_template_ignore_recurrence=True)._send_mail_to_attendees(
|
||||
self.env.ref('calendar.calendar_template_meeting_reminder', raise_if_not_found=False),
|
||||
force_send=True,
|
||||
)
|
||||
alarms = self.env['calendar.alarm'].browse(events_by_alarm.keys())
|
||||
for alarm in alarms:
|
||||
alarm_attendees = attendees.filtered(lambda attendee: attendee.event_id.id in events_by_alarm[alarm.id])
|
||||
alarm_attendees.with_context(
|
||||
mail_notify_force_send=True,
|
||||
calendar_template_ignore_recurrence=True
|
||||
)._send_mail_to_attendees(
|
||||
alarm.mail_template_id,
|
||||
force_send=True
|
||||
)
|
||||
|
||||
@api.model
|
||||
def get_next_notif(self):
|
||||
@@ -198,6 +212,8 @@ class AlarmManager(models.AbstractModel):
|
||||
|
||||
if alarm.alarm_type == 'notification':
|
||||
message = meeting.display_time
|
||||
if alarm.body:
|
||||
message += '<p>%s</p>' % plaintext2html(alarm.body)
|
||||
|
||||
delta = alert['notify_at'] - fields.Datetime.now()
|
||||
delta = delta.seconds + delta.days * 3600 * 24
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<field name="name">calendar.alarm.tree</field>
|
||||
<field name="model">calendar.alarm</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Calendar Alarm" sample="1" editable="bottom">
|
||||
<tree string="Calendar Alarm" sample="1">
|
||||
<field name="name" invisible="1"/>
|
||||
<field name="alarm_type"/>
|
||||
<field name="duration"/>
|
||||
@@ -33,23 +33,32 @@
|
||||
</record>
|
||||
|
||||
<record id="calendar_alarm_view_form" model="ir.ui.view">
|
||||
<field name="name">calendar.alarm.form</field>
|
||||
<field name="model">calendar.alarm</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Calendar Alarm">
|
||||
<group>
|
||||
<field name="name">calendar.alarm.form</field>
|
||||
<field name="model">calendar.alarm</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Calendar Alarm">
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="name" invisible="1"/>
|
||||
<field name="alarm_type"/>
|
||||
<group>
|
||||
<field name="name" invisible="1"/>
|
||||
<field name="alarm_type"/>
|
||||
</group>
|
||||
<group>
|
||||
<label for="duration"/>
|
||||
<div class="o_row">
|
||||
<field name="duration"/>
|
||||
<field name="interval"/>
|
||||
</div>
|
||||
</group>
|
||||
<group attrs="{'invisible': [('alarm_type','=','notification')]}">
|
||||
<field name="mail_template_id" attrs="{'invisible': [('alarm_type','!=','email')], 'required': [('alarm_type', '=', 'email')]}"
|
||||
context="{'default_model': 'calendar.event'}"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<label for="duration"/>
|
||||
<div class="o_row">
|
||||
<field name="duration"/>
|
||||
<field name="interval"/>
|
||||
</div>
|
||||
<group attrs="{'invisible': [('alarm_type','!=','notification')]}">
|
||||
<field name="body"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
@@ -57,6 +66,7 @@
|
||||
<record id="action_calendar_alarm" model="ir.actions.act_window">
|
||||
<field name="name">Calendar Alarm</field>
|
||||
<field name="res_model">calendar.alarm</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_calendar_alarm_tree"/>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
{
|
||||
'name': "Calendar - SMS",
|
||||
'version': "1.1",
|
||||
'summary': 'Send text messages as event reminders',
|
||||
'description': "Send text messages as event reminders",
|
||||
'category': 'Hidden',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class CalendarAlarm(models.Model):
|
||||
@@ -10,3 +10,16 @@ class CalendarAlarm(models.Model):
|
||||
alarm_type = fields.Selection(selection_add=[
|
||||
('sms', 'SMS Text Message')
|
||||
], ondelete={'sms': 'set default'})
|
||||
sms_template_id = fields.Many2one(
|
||||
'sms.template', string="SMS Template",
|
||||
domain=[('model', 'in', ['calendar.event'])],
|
||||
compute='_compute_sms_template_id', readonly=False, store=True,
|
||||
help="Template used to render SMS reminder content.")
|
||||
|
||||
@api.depends('alarm_type', 'mail_template_id')
|
||||
def _compute_sms_template_id(self):
|
||||
for alarm in self:
|
||||
if alarm.alarm_type == 'sms' and not alarm.sms_template_id:
|
||||
alarm.sms_template_id = self.env['ir.model.data'].xmlid_to_res_id('calendar_sms.sms_template_data_calendar_reminder')
|
||||
elif alarm.alarm_type != 'sms' or not alarm.sms_template_id:
|
||||
alarm.sms_template_id = False
|
||||
|
||||
@@ -12,4 +12,13 @@ class AlarmManager(models.AbstractModel):
|
||||
""" Cron method, overridden here to send SMS reminders as well
|
||||
"""
|
||||
super()._send_reminder()
|
||||
self._get_events_to_notify(ttype='sms')._do_sms_reminder()
|
||||
alarms_by_event = self._get_events_by_alarm_to_notify(ttype='sms')
|
||||
if not alarms_by_event:
|
||||
return
|
||||
|
||||
events = self.env['calendar.event'].browse(list(alarms_by_event.keys()))
|
||||
attendees = events.attendee_ids.filtered(lambda a: a.state != 'declined')
|
||||
for event_id in alarms_by_event.keys():
|
||||
event_alarms = attendees.event_id.alarm_ids.filtered(lambda alarm: alarm.id in alarms_by_event.get(event_id, []))
|
||||
for alarm in event_alarms:
|
||||
events.browse(event_id)._do_sms_reminder(alarm)
|
||||
|
||||
@@ -13,11 +13,11 @@ class CalendarEvent(models.Model):
|
||||
"""
|
||||
return self.mapped('attendee_ids').filtered(lambda att: att.state != 'declined').mapped('partner_id')
|
||||
|
||||
def _do_sms_reminder(self):
|
||||
def _do_sms_reminder(self, alarm):
|
||||
""" Send an SMS text reminder to attendees that haven't declined the event """
|
||||
for event in self:
|
||||
event._message_sms_with_template(
|
||||
template_xmlid='calendar_sms.sms_template_data_calendar_reminder',
|
||||
template=alarm.sms_template_id,
|
||||
template_fallback=_("Event reminder: %(name)s, %(time)s.", name=event.name, time=event.display_time),
|
||||
partner_ids=self._sms_get_default_partners().ids,
|
||||
put_in_queue=False
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="calendar_alarm_view_form" model="ir.ui.view">
|
||||
<field name="name">calendar.alarm.view.form.inherit.calendar.sms</field>
|
||||
<field name="model">calendar.alarm</field>
|
||||
<field name="inherit_id" ref="calendar.calendar_alarm_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='mail_template_id']" position="after">
|
||||
<field name="sms_template_id" attrs="{'invisible': [('alarm_type','!=','sms')], 'required': [('alarm_type', '=', 'sms')]}"
|
||||
context="{'default_model': 'calendar.event'}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Add action entry in the Action Menu for Events -->
|
||||
<record id="calendar_event_act_window_sms_composer_single" model="ir.actions.act_window">
|
||||
<field name="name">Send SMS</field>
|
||||
|
||||
@@ -313,7 +313,7 @@ class TestCompanyLeave(TransactionCase):
|
||||
})
|
||||
company_leave._compute_date_from_to()
|
||||
|
||||
with self.assertQueryCount(__system__=737, admin=865):
|
||||
with self.assertQueryCount(__system__=739, admin=865):
|
||||
# Original query count: 1987
|
||||
# Without tracking/activity context keys: 5154
|
||||
company_leave.action_validate()
|
||||
|
||||
@@ -31,7 +31,7 @@ class TestWorkEntryHolidaysPerformance(TestWorkEntryHolidaysBase):
|
||||
self.richard_emp.generate_work_entries(date(2018, 1, 1), date(2018, 1, 2))
|
||||
leave = self.create_leave(datetime(2018, 1, 1, 7, 0), datetime(2018, 1, 1, 18, 0))
|
||||
|
||||
with self.assertQueryCount(__system__=91, admin=99):
|
||||
with self.assertQueryCount(__system__=92, admin=99):
|
||||
leave.action_validate()
|
||||
leave.action_refuse()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user