diff --git a/addons/calendar/controllers/__init__.py b/addons/calendar/controllers/__init__.py
index 4c1edfdff5d..8a1f0bd545d 100644
--- a/addons/calendar/controllers/__init__.py
+++ b/addons/calendar/controllers/__init__.py
@@ -1,2 +1,5 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
import main
import bus
diff --git a/addons/calendar/controllers/main.py b/addons/calendar/controllers/main.py
index 0a8fa25bd78..7a51ea7b372 100644
--- a/addons/calendar/controllers/main.py
+++ b/addons/calendar/controllers/main.py
@@ -1,42 +1,44 @@
-import json
-import openerp
-import openerp.http as http
-from openerp.http import request
-import openerp.addons.web.controllers.main as webmain
-import json
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
import werkzeug
from odoo.api import Environment
+import odoo.http as http
+
+from odoo.http import request
+from odoo import SUPERUSER_ID
+from odoo import registry as registry_get
-class meeting_invitation(http.Controller):
+class CalendarController(http.Controller):
@http.route('/calendar/meeting/accept', type='http', auth="calendar")
def accept(self, db, token, action, id, **kwargs):
- registry = openerp.modules.registry.RegistryManager.get(db)
- attendee_pool = registry.get('calendar.attendee')
+ registry = registry_get(db)
with registry.cursor() as cr:
- attendee_id = attendee_pool.search(cr, openerp.SUPERUSER_ID, [('access_token', '=', token), ('state', '!=', 'accepted')])
- if attendee_id:
- attendee_pool.do_accept(cr, openerp.SUPERUSER_ID, attendee_id)
+ env = Environment(cr, SUPERUSER_ID, {})
+ attendee = env['calendar.attendee'].search([('access_token', '=', token), ('state', '!=', 'accepted')])
+ if attendee:
+ attendee.do_accept()
return self.view(db, token, action, id, view='form')
@http.route('/calendar/meeting/decline', type='http', auth="calendar")
def declined(self, db, token, action, id):
- registry = openerp.modules.registry.RegistryManager.get(db)
- attendee_pool = registry.get('calendar.attendee')
+ registry = registry_get(db)
with registry.cursor() as cr:
- attendee_id = attendee_pool.search(cr, openerp.SUPERUSER_ID, [('access_token', '=', token), ('state', '!=', 'declined')])
- if attendee_id:
- attendee_pool.do_decline(cr, openerp.SUPERUSER_ID, attendee_id)
+ env = Environment(cr, SUPERUSER_ID, {})
+ attendee = env['calendar.attendee'].search([('access_token', '=', token), ('state', '!=', 'declined')])
+ if attendee:
+ attendee.do_decline()
return self.view(db, token, action, id, view='form')
@http.route('/calendar/meeting/view', type='http', auth="calendar")
def view(self, db, token, action, id, view='calendar'):
- registry = openerp.modules.registry.RegistryManager.get(db)
+ registry = registry_get(db)
with registry.cursor() as cr:
# Since we are in auth=none, create an env with SUPERUSER_ID
- env = Environment(cr, openerp.SUPERUSER_ID, {})
+ env = Environment(cr, SUPERUSER_ID, {})
attendee = env['calendar.attendee'].search([('access_token', '=', token)])
timezone = attendee.partner_id.tz
event = env['calendar.event'].with_context(tz=timezone).browse(int(id))
diff --git a/addons/calendar/data/calendar_cron.xml b/addons/calendar/data/calendar_cron.xml
index 313a0211fa4..09cda419a54 100644
--- a/addons/calendar/data/calendar_cron.xml
+++ b/addons/calendar/data/calendar_cron.xml
@@ -1,5 +1,5 @@
-
+
@@ -15,4 +15,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/addons/calendar/data/calendar_data.xml b/addons/calendar/data/calendar_data.xml
index d02c1028745..31ac6432015 100644
--- a/addons/calendar/data/calendar_data.xml
+++ b/addons/calendar/data/calendar_data.xml
@@ -1,7 +1,7 @@
-
+
-
+
Invitation
@@ -9,66 +9,66 @@
-
+ 15 Minute(s)minutes
- notification
-
-
+ notification
+
+ 30 Minute(s)minutes
- notification
-
-
+ notification
+
+ 1 Hour(s)hours
- notification
-
-
+ notification
+
+ 2 Hour(s)hours
- notification
-
-
+ notification
+
+ 1 Day(s)days
- notification
-
-
+ notification
+
+ 2~3 Hour(s) mailhours
- email
-
-
+ email
+
+ 5~6 Hour(s) mailhours
- email
-
-
-
+ email
+
+
+ Customer Meeting
-
+ Internal Meeting
-
+ Off-site Meeting
-
+ Open Discussion
-
+ Feedback Meeting
@@ -114,7 +114,7 @@
Invitation to ${object.event_id.name}
Dear ${object.cn},
- ${object.event_id.user_id.partner_id.name} invited you for the ${object.event_id.name} meeting of ${object.event_id.user_id.company_id.name}.
+ ${object.event_id.user_id.partner_id.name} invited you for the ${object.event_id.name} meeting of ${object.event_id.user_id.company_id.name}.
@@ -162,7 +162,7 @@
]]>
-
+
Calendar: Date updated${object.event_id.user_id.email or ''}
@@ -206,7 +206,7 @@
Dear ${object.cn},
The date of the meeting has been upated. 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)}.
-
+
@@ -298,7 +298,7 @@
Dear ${object.cn},
This is a reminder for the below event :
-
+
@@ -347,4 +347,4 @@
]]>
-
+
diff --git a/addons/calendar/data/calendar_demo.xml b/addons/calendar/data/calendar_demo.xml
index ac91e7e7680..08ca1ec137e 100644
--- a/addons/calendar/data/calendar_demo.xml
+++ b/addons/calendar/data/calendar_demo.xml
@@ -1,113 +1,110 @@
-
+
-
-
-
-
+
+
-
+
+
-
+
-
+
-
+ Follow-up for Project proposalMeeting to discuss project plan and hash out the details of implementation.
-
+
-
-
-
+
+
+ open
-
+ Initial discussionDiscussion with partner for product.
-
-
-
-
+
+
+
+ draft
-
+ Pricing DiscussionInternal meeting for discussion for new pricing for product and services.
-
-
-
-
+
+
+
+ open
-
+ Requirements review
-
-
-
-
+
+
+
+ open
-
+ Changes in Designing
-
-
-
+
+
+ open
-
-
+
+ Presentation for new Services
-
-
-
-
+
+
+
+ draft
-
-
+
+ Presentation of the new Calendar
-
-
-
-
+
+
+
+ draft
-
+
diff --git a/addons/calendar/models/calendar.py b/addons/calendar/models/calendar.py
index 42ff3251871..5443b551006 100644
--- a/addons/calendar/models/calendar.py
+++ b/addons/calendar/models/calendar.py
@@ -1,38 +1,35 @@
# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
-import pytz
-import re
-import time
-import openerp
-import openerp.service.report
-import uuid
-import collections
import babel.dates
-from werkzeug.exceptions import BadRequest
+import collections
from datetime import datetime, timedelta
from dateutil import parser
from dateutil import rrule
from dateutil.relativedelta import relativedelta
-from openerp import api
-from openerp import tools, SUPERUSER_ID
-from openerp.osv import fields, osv
-from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
-from openerp.tools.translate import _
-from openerp.http import request
-from operator import itemgetter
-from openerp.exceptions import UserError
-
import logging
+from operator import itemgetter
+import pytz
+import re
+import time
+import uuid
+
+from odoo import api, fields, models
+from odoo import tools
+from odoo.tools.translate import _
+from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
+from odoo.exceptions import UserError, ValidationError
+
+
_logger = logging.getLogger(__name__)
def calendar_id2real_id(calendar_id=None, with_date=False):
- """
- Convert a "virtual/recurring event id" (type string) into a real event id (type int).
- E.g. virtual/recurring event id is 4-20091201100000, so it will return 4.
- @param calendar_id: id of calendar
- @param with_date: if a value is passed to this param it will return dates based on value of withdate + calendar_id
- @return: real event id
+ """ Convert a "virtual/recurring event id" (type string) into a real event id (type int).
+ E.g. virtual/recurring event id is 4-20091201100000, so it will return 4.
+ :param calendar_id: id of calendar
+ :param with_date: if a value is passed to this param it will return dates based on value of withdate + calendar_id
+ :return: real event id
"""
if calendar_id and isinstance(calendar_id, (basestring)):
res = filter(None, calendar_id.split('-'))
@@ -52,53 +49,30 @@ def get_real_ids(ids):
return calendar_id2real_id(ids)
if isinstance(ids, (list, tuple)):
- return [calendar_id2real_id(id) for id in ids]
+ return [calendar_id2real_id(_id) for _id in ids]
-class calendar_contacts(osv.osv):
+class Contacts(models.Model):
_name = 'calendar.contacts'
- _columns = {
- 'user_id': fields.many2one('res.users', 'Me'),
- 'partner_id': fields.many2one('res.partner', 'Employee', required=True, domain=[]),
- 'active': fields.boolean('active'),
- }
+ user_id = fields.Many2one('res.users', 'Me', default=lambda self: self.env.user)
+ partner_id = fields.Many2one('res.partner', 'Employee', required=True)
+ active = fields.Boolean('Active', default=True)
- _defaults = {
- 'user_id': lambda self, cr, uid, ctx: uid,
- 'active': True,
- }
-
- def unlink_from_partner_id(self, cr, uid, partner_id, context=None):
- self.unlink(cr, uid, self.search(cr, uid, [('partner_id', '=', partner_id)]), context)
+ @api.model
+ def unlink_from_partner_id(self, partner_id):
+ return self.search([('partner_id', '=', partner_id)]).unlink()
-class calendar_attendee(osv.Model):
- """
- Calendar Attendee Information
- """
+class Attendee(models.Model):
+ """ Calendar Attendee Information """
+
_name = 'calendar.attendee'
_rec_name = 'cn'
_description = 'Attendee information'
- def _compute_data(self, cr, uid, ids, name, arg, context=None):
- """
- Compute data on function fields for attendee values.
- @param ids: list of calendar attendee's IDs
- @param name: name of field
- @return: dictionary of form {id: {'field Name': value'}}
- """
- name = name[0]
- result = {}
- for attdata in self.browse(cr, uid, ids, context=context):
- id = attdata.id
- result[id] = {}
- if name == 'cn':
- if attdata.partner_id:
- result[id][name] = attdata.partner_id.name or False
- else:
- result[id][name] = attdata.email or ''
- return result
+ def _default_access_token(self):
+ return uuid.uuid4().hex
STATE_SELECTION = [
('needsAction', 'Needs Action'),
@@ -107,46 +81,53 @@ class calendar_attendee(osv.Model):
('accepted', 'Accepted'),
]
- _columns = {
- 'state': fields.selection(STATE_SELECTION, 'Status', readonly=True, help="Status of the attendee's participation"),
- 'cn': fields.function(_compute_data, string='Common name', type="char", multi='cn', store=True),
- 'partner_id': fields.many2one('res.partner', 'Contact', readonly="True"),
- 'email': fields.char('Email', help="Email of Invited Person"),
- 'availability': fields.selection([('free', 'Free'), ('busy', 'Busy')], 'Free/Busy', readonly="True"),
- 'access_token': fields.char('Invitation Token'),
- 'event_id': fields.many2one('calendar.event', 'Meeting linked', ondelete='cascade'),
- }
- _defaults = {
- 'state': 'needsAction',
- }
+ state = fields.Selection(STATE_SELECTION, string='Status', readonly=True, default='needsAction',
+ help="Status of the attendee's participation")
+ cn = fields.Char('Common name', compute='_compute_common_name', store=True)
+ partner_id = fields.Many2one('res.partner', 'Contact', readonly="True")
+ email = fields.Char('Email', help="Email of Invited Person")
+ availability = fields.Selection([('free', 'Free'), ('busy', 'Busy')], 'Free/Busy', readonly="True")
+ access_token = fields.Char('Invitation Token', default=_default_access_token)
+ event_id = fields.Many2one('calendar.event', 'Meeting linked', ondelete='cascade')
- def copy(self, cr, uid, id, default=None, context=None):
+ @api.depends('partner_id', 'partner_id.name', 'email')
+ def _compute_common_name(self):
+ for attendee in self:
+ attendee.cn = attendee.partner_id.name or attendee.email
+
+ @api.onchange('partner_id')
+ def _onchange_partner_id(self):
+ """ Make entry on email and availability on change of partner_id field. """
+ self.email = self.partner_id.email
+
+ @api.model
+ def create(self, values):
+ if not values.get("email") and values.get("cn"):
+ cnval = values.get("cn").split(':')
+ email = filter(lambda x: x.__contains__('@'), cnval) # TODO JEM : should be refactored
+ values['email'] = email and email[0] or ''
+ values['cn'] = values.get("cn")
+ return super(Attendee, self).create(values)
+
+ @api.multi
+ def copy(self, default=None):
raise UserError(_('You cannot duplicate a calendar attendee.'))
- def onchange_partner_id(self, cr, uid, ids, partner_id, context=None):
- """
- Make entry on email and availability on change of partner_id field.
- @param partner_id: changed value of partner id
- """
- if not partner_id:
- return {'value': {'email': ''}}
- partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context)
- return {'value': {'email': partner.email}}
-
- def get_ics_file(self, cr, uid, event_obj, context=None):
- """
- Returns iCalendar file for the event invitation.
- @param event_obj: event object (browse record)
- @return: .ics file content
+ # TODO JEM : should be moved on calendar.event ?
+ @api.model
+ def get_ics_file(self, event_record):
+ """ Returns iCalendar file for the event invitation.
+ :param event: record of calendar.event
+ :returns the .ics file content
"""
res = None
def ics_datetime(idate, allday=False):
if idate:
if allday:
- return openerp.fields.Date.from_string(idate)
+ return fields.Date.from_string(idate)
else:
- return openerp.fields.Datetime.from_string(idate).replace(tzinfo=pytz.timezone('UTC'))
+ return fields.Datetime.from_string(idate).replace(tzinfo=pytz.timezone('UTC'))
return False
try:
@@ -157,21 +138,22 @@ class calendar_attendee(osv.Model):
cal = vobject.iCalendar()
event = cal.add('vevent')
- if not event_obj.start or not event_obj.stop:
+
+ if not event_record.start or not event_record.stop:
raise UserError(_("First you have to specify the date of the invitation."))
event.add('created').value = ics_datetime(time.strftime(DEFAULT_SERVER_DATETIME_FORMAT))
- event.add('dtstart').value = ics_datetime(event_obj.start, event_obj.allday)
- event.add('dtend').value = ics_datetime(event_obj.stop, event_obj.allday)
- event.add('summary').value = event_obj.name
- if event_obj.description:
- event.add('description').value = event_obj.description
- if event_obj.location:
- event.add('location').value = event_obj.location
- if event_obj.rrule:
- event.add('rrule').value = event_obj.rrule
+ event.add('dtstart').value = ics_datetime(event_record.start, event_record.allday)
+ event.add('dtend').value = ics_datetime(event_record.stop, event_record.allday)
+ event.add('summary').value = event_record.name
+ if event_record.description:
+ event.add('description').value = event_record.description
+ if event_record.location:
+ event.add('location').value = event_record.location
+ if event_record.rrule:
+ event.add('rrule').value = event_record.rrule
- if event_obj.alarm_ids:
- for alarm in event_obj.alarm_ids:
+ if event_record.alarm_ids:
+ for alarm in event_record.alarm_ids:
valarm = event.add('valarm')
interval = alarm.interval
duration = alarm.duration
@@ -185,53 +167,55 @@ class calendar_attendee(osv.Model):
delta = timedelta(minutes=duration)
trigger.value = delta
valarm.add('DESCRIPTION').value = alarm.name or 'Odoo'
- for attendee in event_obj.attendee_ids:
+ for attendee in event_record.attendee_ids:
attendee_add = event.add('attendee')
attendee_add.value = 'MAILTO:' + (attendee.email or '')
res = cal.serialize()
return res
- def _send_mail_to_attendees(self, cr, uid, ids, email_from=tools.config.get('email_from', False),
- template_xmlid='calendar_template_meeting_invitation', force=False, context=None):
- """
- Send mail for event invitation to event attendees.
- @param email_from: email address for user sending the mail
- @param force: If set to True, email will be sent to user himself. Usefull for example for alert, ...
+ @api.multi
+ def _send_mail_to_attendees(self, email_from=False, template_xmlid=False, force=False):
+ """ Send mail for event invitation to event attendees.
+ :param email_from: email address for user sending the mail
+ :param template_xmlid: xml id of the email template to use to send the invitation
+ :param force: If set to True, email will be sent to user himself. Usefull for alert, ...
"""
+ # default values
+ if not email_from:
+ email_from = tools.config.get('email_from', False)
+ if not template_xmlid:
+ template_xmlid = 'calendar_template_meeting_invitation'
+
res = False
- if self.pool['ir.config_parameter'].get_param(cr, uid, 'calendar.block_mail', default=False) or context.get("no_mail_to_attendees"):
+ if self.env['ir.config_parameter'].get_param('calendar.block_mail', self._context.get("no_mail_to_attendees")):
return res
- mail_ids = []
- data_pool = self.pool['ir.model.data']
- mailmess_pool = self.pool['mail.message']
- mail_pool = self.pool['mail.mail']
- template_pool = self.pool['mail.template']
- local_context = context.copy()
- color = {
+ calendar_view = self.env.ref('calendar.view_calendar_event_calendar')
+ invitation_template = self.env.ref('calendar.%s' % (template_xmlid,))
+
+ # prepare rendering context for mail template
+ colors = {
'needsAction': 'grey',
'accepted': 'green',
'tentative': '#FFFF00',
'declined': 'red'
}
-
- if not isinstance(ids, (tuple, list)):
- ids = [ids]
-
- dummy, template_id = data_pool.get_object_reference(cr, uid, 'calendar', template_xmlid)
- dummy, act_id = data_pool.get_object_reference(cr, uid, 'calendar', "view_calendar_event_calendar")
- local_context.update({
- 'color': color,
- 'action_id': self.pool['ir.actions.act_window'].search(cr, uid, [('view_id', '=', act_id)], context=context)[0],
- 'dbname': cr.dbname,
- 'base_url': self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url', default='http://localhost:8069', context=context)
+ rendering_context = dict(self._context)
+ rendering_context.update({
+ 'color': colors,
+ 'action_id': self.env['ir.actions.act_window'].search([('view_id', '=', calendar_view.id)], limit=1).id,
+ 'dbname': self._cr.dbname,
+ 'base_url': self.env['ir.config_parameter'].get_param('web.base.url', default='http://localhost:8069')
})
+ invitation_template = invitation_template.with_context(rendering_context)
- for attendee in self.browse(cr, uid, ids, context=context):
+ # send email with attachments
+ mails_to_send = self.env['mail.mail']
+ for attendee in self:
if attendee.email and email_from and (attendee.email != email_from or force):
- ics_file = self.get_ics_file(cr, uid, attendee.event_id, context=context)
- mail_id = template_pool.send_mail(cr, uid, template_id, attendee.id, context=local_context)
+ ics_file = self.get_ics_file(attendee.event_id)
+ mail_id = invitation_template.send_mail(attendee.id)
vals = {}
if ics_file:
@@ -239,80 +223,43 @@ class calendar_attendee(osv.Model):
'datas_fname': 'invitation.ics',
'datas': str(ics_file).encode('base64')})]
vals['model'] = None # We don't want to have the mail in the tchatter while in queue!
- the_mailmess = mail_pool.browse(cr, uid, mail_id, context=context).mail_message_id
- mailmess_pool.write(cr, uid, [the_mailmess.id], vals, context=context)
- mail_ids.append(mail_id)
+ current_mail = self.env['mail.mail'].browse(mail_id)
+ current_mail.mail_message_id.write(vals)
+ mails_to_send |= current_mail
- if mail_ids:
- res = mail_pool.send(cr, uid, mail_ids, context=context)
+ if mails_to_send:
+ res = mails_to_send.send()
return res
- def onchange_user_id(self, cr, uid, ids, user_id, *args, **argv):
- """
- Make entry on email and availability on change of user_id field.
- @param ids: list of attendee's IDs
- @param user_id: changed value of User id
- @return: dictionary of values which put value in email and availability fields
- """
- if not user_id:
- return {'value': {'email': ''}}
+ @api.multi
+ def do_tentative(self):
+ """ Makes event invitation as Tentative. """
+ return self.write({'state': 'tentative'})
- user = self.pool['res.users'].browse(cr, uid, user_id, *args)
- return {'value': {'email': user.email, 'availability': user.availability}}
+ @api.multi
+ def do_accept(self):
+ """ Marks event invitation as Accepted. """
+ result = self.write({'state': 'accepted'})
+ for attendee in self:
+ attendee.event_id.message_post(body=_("%s has accepted invitation") % (attendee.cn), subtype="calendar.subtype_invitation")
+ return result
- def do_tentative(self, cr, uid, ids, context=None, *args):
- """
- Makes event invitation as Tentative.
- @param ids: list of attendee's IDs
- """
- return self.write(cr, uid, ids, {'state': 'tentative'}, context)
-
- def do_accept(self, cr, uid, ids, context=None, *args):
- """
- Marks event invitation as Accepted.
- @param ids: list of attendee's IDs
- """
- if context is None:
- context = {}
- meeting_obj = self.pool['calendar.event']
- res = self.write(cr, uid, ids, {'state': 'accepted'}, context)
- for attendee in self.browse(cr, uid, ids, context=context):
- meeting_obj.message_post(cr, uid, attendee.event_id.id, body=_("%s has accepted invitation") % (attendee.cn),
- subtype="calendar.subtype_invitation", context=context)
-
- return res
-
- def do_decline(self, cr, uid, ids, context=None, *args):
- """
- Marks event invitation as Declined.
- @param ids: list of calendar attendee's IDs
- """
- if context is None:
- context = {}
- meeting_obj = self.pool['calendar.event']
- res = self.write(cr, uid, ids, {'state': 'declined'}, context)
- for attendee in self.browse(cr, uid, ids, context=context):
- meeting_obj.message_post(cr, uid, attendee.event_id.id, body=_("%s has declined invitation") % (attendee.cn), subtype="calendar.subtype_invitation", context=context)
- return res
-
- def create(self, cr, uid, vals, context=None):
- if context is None:
- context = {}
- if not vals.get("email") and vals.get("cn"):
- cnval = vals.get("cn").split(':')
- email = filter(lambda x: x.__contains__('@'), cnval)
- vals['email'] = email and email[0] or ''
- vals['cn'] = vals.get("cn")
- res = super(calendar_attendee, self).create(cr, uid, vals, context=context)
+ @api.multi
+ def do_decline(self):
+ """ Marks event invitation as Declined. """
+ res = self.write({'state': 'declined'})
+ for attendee in self:
+ attendee.event_id.message_post(body=_("%s has declined invitation") % (attendee.cn), subtype="calendar.subtype_invitation")
return res
-class calendar_alarm_manager(osv.AbstractModel):
+class AlarmManager(models.AbstractModel):
+
_name = 'calendar.alarm_manager'
- def get_next_potential_limit_alarm(self, cr, uid, alarm_type, seconds=None, partner_id=None, context=None):
- res = {}
+ def get_next_potential_limit_alarm(self, alarm_type, seconds=None, partner_id=None):
+ result = {}
delta_request = """
SELECT
rel.calendar_event_id, max(alarm.duration_minutes) AS max_delta,min(alarm.duration_minutes) AS min_delta
@@ -371,7 +318,7 @@ class calendar_alarm_manager(osv.AbstractModel):
first_alarm_max_value = "(now() at time zone 'utc' + interval '%s' second )"
tuple_params += (seconds,)
- cr.execute("""
+ self._cr.execute("""
WITH calcul_delta AS (%s)
SELECT *
FROM ( %s WHERE cal.active = True ) AS ALL_EVENTS
@@ -379,8 +326,8 @@ class calendar_alarm_manager(osv.AbstractModel):
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 cr.fetchall():
- res[event_id] = {
+ for event_id, first_alarm, last_alarm, first_meeting, last_meeting, min_duration, max_duration, rule in self._cr.fetchall():
+ result[event_id] = {
'event_id': event_id,
'first_alarm': first_alarm,
'last_alarm': last_alarm,
@@ -391,40 +338,41 @@ class calendar_alarm_manager(osv.AbstractModel):
'rrule': rule
}
- return res
+ return result
- def do_check_alarm_for_one_date(self, cr, uid, one_date, event, event_maxdelta, in_the_next_X_seconds, alarm_type, after=False, missing=False, context=None):
- # one_date: date of the event to check (not the same that in the event browse if recurrent)
- # event: Event browse record
- # event_maxdelta: biggest duration from alarms for this event
- # in_the_next_X_seconds: looking in the future (in seconds)
- # alarm_type: the type of alarm we are looking for ('notification' or 'email')
- # after: if not False: will return alert if after this date (date as string - todo: change in master)
- # missing: if not False: will return alert even if we are too late
-
- res = []
+ def do_check_alarm_for_one_date(self, one_date, event, event_maxdelta, in_the_next_X_seconds, alarm_type, after=False, missing=False):
+ """ Search for some alarms in the interval of time determined by some parameters (after, in_the_next_X_seconds, ...)
+ :param one_date: date of the event to check (not the same that in the event browse if recurrent)
+ :param event: Event browse record
+ :param event_maxdelta: biggest duration from alarms for this event
+ :param in_the_next_X_seconds: looking in the future (in seconds)
+ :param after: if not False: will return alert if after this date (date as string - todo: change in master)
+ :param missing: if not False: will return alert even if we are too late
+ :param notif: Looking for type notification
+ :param mail: looking for type email
+ """
+ result = []
# TODO: remove event_maxdelta and if using it
if one_date - timedelta(minutes=(missing and 0 or event_maxdelta)) < datetime.now() + timedelta(seconds=in_the_next_X_seconds): # if an alarm is possible for this date
for alarm in event.alarm_ids:
if alarm.type == alarm_type and \
one_date - timedelta(minutes=(missing and 0 or alarm.duration_minutes)) < datetime.now() + timedelta(seconds=in_the_next_X_seconds) and \
- (not after or one_date - timedelta(minutes=alarm.duration_minutes) > openerp.fields.Datetime.from_string(after)):
+ (not after or one_date - timedelta(minutes=alarm.duration_minutes) > fields.Datetime.from_string(after)):
alert = {
'alarm_id': alarm.id,
'event_id': event.id,
'notify_at': one_date - timedelta(minutes=alarm.duration_minutes),
}
- res.append(alert)
- return res
+ result.append(alert)
+ return result
- def get_next_mail(self, cr, uid, context=None):
- now = openerp.fields.Datetime.to_string(datetime.now())
-
- icp = self.pool['ir.config_parameter']
- last_notif_mail = icp.get_param(cr, SUPERUSER_ID, 'calendar.last_notif_mail', default=False) or now
+ @api.model
+ def get_next_mail(self):
+ now = fields.Datetime.now()
+ last_notif_mail = self.env['ir.config_parameter'].sudo().get_param('calendar.last_notif_mail', default=now)
try:
- cron = self.pool['ir.model.data'].get_object(cr, SUPERUSER_ID, 'calendar', 'ir_cron_scheduler_alarm', context=context)
+ cron = self.env['ir.model.data'].sudo().get_object('calendar', 'ir_cron_scheduler_alarm')
except ValueError:
_logger.error("Cron for " + self._name + " can not be identified !")
return False
@@ -437,207 +385,202 @@ class calendar_alarm_manager(osv.AbstractModel):
"seconds": 1
}
- if cron.interval_type not in interval_to_second.keys():
+ if cron.interval_type not in interval_to_second:
_logger.error("Cron delay can not be computed !")
return False
cron_interval = cron.interval_number * interval_to_second[cron.interval_type]
- all_events = self.get_next_potential_limit_alarm(cr, uid, 'email', seconds=cron_interval, context=context)
+ all_meetings = self.get_next_potential_limit_alarm('email', seconds=cron_interval)
- for curEvent in self.pool.get('calendar.event').browse(cr, uid, all_events.keys(), context=context):
- max_delta = all_events[curEvent.id]['max_duration']
+ for meeting in self.env['calendar.event'].browse(all_meetings.keys()):
+ max_delta = all_meetings[meeting.id]['max_duration']
- if curEvent.recurrency:
+ if meeting.recurrency:
at_least_one = False
last_found = False
- for one_date in self.pool.get('calendar.event').get_recurrent_date_by_event(cr, uid, curEvent, context=context):
+ for one_date in self.env['calendar.event'].get_recurrent_date_by_event(current_event):
in_date_format = one_date.replace(tzinfo=None)
- last_found = self.do_check_alarm_for_one_date(cr, uid, in_date_format, curEvent, max_delta, 0, 'email', after=last_notif_mail, missing=True, context=context)
+ last_found = self.do_check_alarm_for_one_date(in_date_format, meeting, max_delta, 0, 'email', after=last_notif_mail, missing=True)
for alert in last_found:
- self.do_mail_reminder(cr, uid, alert, context=context)
+ self.do_mail_reminder(alert)
at_least_one = True # if it's the first alarm for this recurrent event
if at_least_one and not last_found: # if the precedent event had an alarm but not this one, we can stop the search for this event
break
else:
- in_date_format = datetime.strptime(curEvent.start, DEFAULT_SERVER_DATETIME_FORMAT)
- last_found = self.do_check_alarm_for_one_date(cr, uid, in_date_format, curEvent, max_delta, 0, 'email', after=last_notif_mail, missing=True, context=context)
+ in_date_format = datetime.strptime(meeting.start, DEFAULT_SERVER_DATETIME_FORMAT)
+ last_found = self.do_check_alarm_for_one_date(in_date_format, meeting, max_delta, 0, 'email', after=last_notif_mail, missing=True)
for alert in last_found:
- self.do_mail_reminder(cr, uid, alert, context=context)
- icp.set_param(cr, SUPERUSER_ID, 'calendar.last_notif_mail', now)
+ self.do_mail_reminder(alert)
+ self.env['ir.config_parameter'].sudo().set_param('calendar.last_notif_mail', now)
- def get_next_notif(self, cr, uid, context=None):
- partner = self.pool['res.users'].read(cr, SUPERUSER_ID, uid, ['partner_id', 'calendar_last_notif_ack'], context=context)
+ @api.model
+ def get_next_notif(self):
+ partner = self.env.user.partner_id
all_notif = []
if not partner:
return []
- all_events = self.get_next_potential_limit_alarm(cr, uid, 'notification', partner_id=partner['partner_id'][0], context=context)
+ all_meetings = self.get_next_potential_limit_alarm('notification', partner_id=partner.id)
time_limit = 3600 * 24 # return alarms of the next 24 hours
- for event in all_events: # .values()
- max_delta = all_events[event]['max_duration']
- curEvent = self.pool.get('calendar.event').browse(cr, uid, event, context=context)
- if curEvent.recurrency:
- bFound = False
- LastFound = False
- for one_date in self.pool.get("calendar.event").get_recurrent_date_by_event(cr, uid, curEvent, context=context):
+ for event_id in all_meetings:
+ max_delta = all_meetings[event_id]['max_duration']
+ meeting = self.env['calendar.event'].browse(event_id)
+ if meeting.recurrency:
+ b_found = False
+ last_found = False
+ for one_date in self.env["calendar.event"].get_recurrent_date_by_event(current_event):
in_date_format = one_date.replace(tzinfo=None)
- LastFound = self.do_check_alarm_for_one_date(cr, uid, in_date_format, curEvent, max_delta, time_limit, 'notification', after=partner['calendar_last_notif_ack'], context=context)
- if LastFound:
- for alert in LastFound:
- all_notif.append(self.do_notif_reminder(cr, uid, alert, context=context))
- if not bFound: # if it's the first alarm for this recurrent event
- bFound = True
- if bFound and not LastFound: # if the precedent event had alarm but not this one, we can stop the search fot this event
+ last_found = self.do_check_alarm_for_one_date(in_date_format, meeting, max_delta, time_limit, 'notification', after=partner.calendar_last_notif_ack)
+ if last_found:
+ for alert in last_found:
+ all_notif.append(self.do_notif_reminder(alert))
+ if not b_found: # if it's the first alarm for this recurrent event
+ b_found = True
+ if b_found and not last_found: # if the precedent event had alarm but not this one, we can stop the search fot this event
break
else:
- in_date_format = datetime.strptime(curEvent.start, DEFAULT_SERVER_DATETIME_FORMAT)
- LastFound = self.do_check_alarm_for_one_date(cr, uid, in_date_format, curEvent, max_delta, time_limit, 'notification', after=partner['calendar_last_notif_ack'], context=context)
- if LastFound:
- for alert in LastFound:
- all_notif.append(self.do_notif_reminder(cr, uid, alert, context=context))
+ in_date_format = fields.Datetime.from_string(meeting.start)
+ last_found = self.do_check_alarm_for_one_date(in_date_format, meeting, max_delta, time_limit, 'notification', after=partner.calendar_last_notif_ack)
+ if last_found:
+ for alert in last_found:
+ all_notif.append(self.do_notif_reminder(alert))
return all_notif
- def do_mail_reminder(self, cr, uid, alert, context=None):
- if context is None:
- context = {}
- res = False
-
- event = self.pool['calendar.event'].browse(cr, uid, alert['event_id'], context=context)
- alarm = self.pool['calendar.alarm'].browse(cr, uid, alert['alarm_id'], context=context)
+ def do_mail_reminder(self, alert):
+ meeting = self.env['calendar.event'].browse(alert['event_id'])
+ alarm = self.env['calendar.alarm'].browse(alert['alarm_id'])
+ result = False
if alarm.type == 'email':
- res = self.pool['calendar.attendee']._send_mail_to_attendees(
- cr,
- uid,
- [att.id for att in event.attendee_ids],
+ result = event.attendee_ids._send_mail_to_attendees(
email_from=event.user_id.partner_id.email,
template_xmlid='calendar_template_meeting_reminder',
force=True,
- context=context
)
+ result = meeting.attendee_ids._send_mail_to_attendees('calendar_template_meeting_reminder', force_send=True)
+ return result
- return res
+ def do_notif_reminder(self, alert):
+ alarm = self.env['calendar.alarm'].browse(alert['alarm_id'])
+ meeting = self.env['calendar.event'].browse(alert['event_id'])
- def do_notif_reminder(self, cr, uid, alert, context=None):
- alarm = self.pool['calendar.alarm'].browse(cr, uid, alert['alarm_id'], context=context)
if alarm.type == 'notification':
- event = self.pool['calendar.event'].browse(cr, uid, alert['event_id'], context=context)
- message = event.display_time
+ message = meeting.display_time
delta = alert['notify_at'] - datetime.now()
delta = delta.seconds + delta.days * 3600 * 24
return {
- 'event_id': event.id,
- 'title': event.name,
+ 'event_id': meeting.id,
+ 'title': meeting.name,
'message': message,
'timer': delta,
- 'notify_at': alert['notify_at'].strftime(DEFAULT_SERVER_DATETIME_FORMAT),
+ 'notify_at': fields.Datetime.to_string(alert['notify_at']),
}
- def notify_next_alarm(self, cr, uid, partner_ids, context=None):
+ def notify_next_alarm(self, partner_ids):
""" Sends through the bus the next alarm of given partners """
notifications = []
- user_obj = self.pool['res.users']
- user_ids = user_obj.search(cr, uid, [('partner_id', 'in', tuple(partner_ids))], context=context)
- users = user_obj.browse(cr, uid, user_ids, context=context)
+ users = self.env['res.users'].search([('partner_id', 'in', tuple(partner_ids))])
for user in users:
- notif = self.get_next_notif(cr, user.id, context=context)
- notifications.append([(cr.dbname, 'calendar.alarm', user.partner_id.id), notif])
+ notif = self.sudo(user.id).get_next_notif()
+ notifications.append([(self._cr.dbname, 'calendar.alarm', user.partner_id.id), notif])
if len(notifications) > 0:
- self.pool['bus.bus'].sendmany(cr, uid, notifications)
+ self.env['bus.bus'].sendmany(notifications)
-class calendar_alarm(osv.Model):
+class Alarm(models.Model):
_name = 'calendar.alarm'
_description = 'Event alarm'
- def _get_duration(self, cr, uid, ids, field_name, arg, context=None):
- res = {}
- for alarm in self.browse(cr, uid, ids, context=context):
+ @api.depends('interval', 'duration')
+ def _compute_duration_minutes(self):
+ for alarm in self:
if alarm.interval == "minutes":
- res[alarm.id] = alarm.duration
+ alarm.duration_minutes = alarm.duration
elif alarm.interval == "hours":
- res[alarm.id] = alarm.duration * 60
+ alarm.duration_minutes = alarm.duration * 60
elif alarm.interval == "days":
- res[alarm.id] = alarm.duration * 60 * 24
+ alarm.duration_minutes = alarm.duration * 60 * 24
else:
- res[alarm.id] = 0
- return res
+ alarm.duration_minutes = 0
_interval_selection = {'minutes': 'Minute(s)', 'hours': 'Hour(s)', 'days': 'Day(s)'}
- _columns = {
- 'name': fields.char('Name', required=True),
- 'type': fields.selection([('notification', 'Notification'), ('email', 'Email')], 'Type', required=True),
- 'duration': fields.integer('Amount', required=True),
- 'interval': fields.selection(list(_interval_selection.iteritems()), 'Unit', required=True),
- 'duration_minutes': fields.function(_get_duration, type='integer', string='Duration in minutes', store=True, help="Duration in minutes"),
- }
- _defaults = {
- 'type': 'email',
- 'duration': 1,
- 'interval': 'hours',
- }
+ name = fields.Char('Name', required=True)
+ type = fields.Selection([('notification', 'Notification'), ('email', 'Email')], 'Type', required=True, default='email')
+ duration = fields.Integer('Amount', required=True, default=1)
+ interval = fields.Selection(list(_interval_selection.iteritems()), 'Unit', required=True, default='hours')
+ duration_minutes = fields.Integer('Duration in minutes', compute='_compute_duration_minutes', store=True, help="Duration in minutes")
- def onchange_duration_interval(self, cr, uid, ids, duration, interval, context=None):
- display_interval = self._interval_selection.get(interval, '')
- return {'value': {'name': str(duration) + ' ' + display_interval}}
+ @api.onchange('duration', 'interval')
+ def _onchange_duration_interval(self):
+ display_interval = self._interval_selection.get(self.interval, '')
+ self.name = str(self.duration) + ' ' + display_interval
- def _update_cron(self, cr, uid, context=None):
+ def _update_cron(self):
try:
- cron = self.pool['ir.model.data'].get_object(
- cr, SUPERUSER_ID, 'calendar', 'ir_cron_scheduler_alarm', context=context)
+ cron = self.env['ir.model.data'].sudo().get_object('calendar', 'ir_cron_scheduler_alarm')
except ValueError:
return False
return cron.toggle(model=self._name, domain=[('type', '=', 'email')])
- def create(self, cr, uid, values, context=None):
- res = super(calendar_alarm, self).create(cr, uid, values, context=context)
+ @api.model
+ def create(self, values):
+ result = super(Alarm, self).create(values)
+ self._update_cron()
+ return result
- self._update_cron(cr, uid, context=context)
+ @api.multi
+ def write(self, values):
+ result = super(Alarm, self).write(values)
+ self._update_cron()
+ return result
- return res
-
- def write(self, cr, uid, ids, values, context=None):
- res = super(calendar_alarm, self).write(cr, uid, ids, values, context=context)
-
- self._update_cron(cr, uid, context=context)
-
- return res
-
- def unlink(self, cr, uid, ids, context=None):
- res = super(calendar_alarm, self).unlink(cr, uid, ids, context=context)
-
- self._update_cron(cr, uid, context=context)
-
- return res
+ @api.multi
+ def unlink(self):
+ result = super(Alarm, self).unlink()
+ self._update_cron()
+ return result
-class calendar_event_type(osv.Model):
+class MeetingType(models.Model):
+
_name = 'calendar.event.type'
_description = 'Meeting Type'
- _columns = {
- 'name': fields.char('Name', required=True),
- }
+
+ name = fields.Char('Name', required=True)
+
_sql_constraints = [
- ('name_uniq', 'unique (name)', "Tag name already exists !"),
+ ('name_uniq', 'unique (name)', "Tag name already exists !"),
]
-class calendar_event(osv.Model):
+
+class Meeting(models.Model):
""" Model for Calendar Event """
+
_name = 'calendar.event'
_description = "Event"
_order = "id desc"
_inherit = ["mail.thread", "ir.needaction_mixin"]
- def do_run_scheduler(self, cr, uid, id, context=None):
- self.pool['calendar.alarm_manager'].get_next_mail(cr, uid, context=context)
+ @api.model
+ def _default_partners(self):
+ """ When active_model is res.partner, the current partners should be attendees """
+ partners = self.env.user.partner_id
+ active_id = self._context.get('active_id')
+ if self._context.get('active_model') == 'res.partner' and active_id:
+ if active_id not in partners.ids:
+ partners |= self.env['res.partner'].browse(active_id)
+ return partners
- def get_recurrent_date_by_event(self, cr, uid, event, context=None):
- """Get recurrent dates based on Rule string and all event where recurrent_id is child
+ # TODO JEM : make it api.multi and remove args
+ @api.model
+ def get_recurrent_date_by_event(self, event):
+ """ Get recurrent dates based on Rule string and all event where recurrent_id is child
+ :param event : calendar.event record
"""
def todate(date):
val = parser.parse(''.join((re.compile('\d')).findall(date)))
@@ -646,26 +589,26 @@ class calendar_event(osv.Model):
val = pytz.UTC.localize(val)
return val.astimezone(timezone)
- if context is None:
- context = {}
-
- timezone = pytz.timezone(context.get('tz') or 'UTC')
- startdate = pytz.UTC.localize(datetime.strptime(event.start, DEFAULT_SERVER_DATETIME_FORMAT)) # Add "+hh:mm" timezone
+ timezone = pytz.timezone(self._context.get('tz') or 'UTC')
+ startdate = pytz.UTC.localize(fields.Datetime.from_string(event.start)) # Add "+hh:mm" timezone
if not startdate:
startdate = datetime.now()
- ## Convert the start date to saved timezone (or context tz) as it'll
- ## define the correct hour/day asked by the user to repeat for recurrence.
+ # Convert the start date to saved timezone (or context tz) as it'll
+ # define the correct hour/day asked by the user to repeat for recurrence.
startdate = startdate.astimezone(timezone) # transform "+hh:mm" timezone
rset1 = rrule.rrulestr(str(event.rrule), dtstart=startdate, forceset=True)
- ids_depending = self.search(cr, uid, [('recurrent_id', '=', event.id), '|', ('active', '=', False), ('active', '=', True)], context=context)
- all_events = self.browse(cr, uid, ids_depending, context=context)
- for ev in all_events:
- rset1._exdate.append(todate(ev.recurrent_id_date))
+ recurring_meetings = self.search([('recurrent_id', '=', event.id), '|', ('active', '=', False), ('active', '=', True)])
+
+ for meeting in recurring_meetings:
+ rset1._exdate.append(todate(meeting.recurrent_id_date))
return [d.astimezone(pytz.UTC) for d in rset1]
- def _get_recurrency_end_date(self, cr, uid, id, context=None):
- data = self.read(cr, uid, id, ['final_date', 'recurrency', 'rrule_type', 'count', 'end_type', 'stop'], context=context)
+ @api.multi
+ def _get_recurrency_end_date(self):
+ """ Return the last date a recurring event happens, according to its end_type. """
+ self.ensure_one()
+ data = self.read(['final_date', 'recurrency', 'rrule_type', 'count', 'end_type', 'stop'])[0]
if not data.get('recurrency'):
return False
@@ -681,146 +624,140 @@ class calendar_event(osv.Model):
'yearly': ('years', 1),
}[data['rrule_type']]
- deadline = datetime.strptime(data['stop'], tools.DEFAULT_SERVER_DATETIME_FORMAT)
+ deadline = fields.Datetime.from_string(data['stop'])
return deadline + relativedelta(**{delay: count * mult})
return final_date
- def _find_my_attendee(self, cr, uid, meeting_ids, context=None):
+ @api.multi
+ def _find_my_attendee(self):
+ """ Return the first attendee where the user connected has been invited
+ from all the meeting_ids in parameters.
"""
- Return the first attendee where the user connected has been invited from all the meeting_ids in parameters
- """
- user = self.pool['res.users'].browse(cr, uid, uid, context=context)
- for meeting_id in meeting_ids:
- for attendee in self.browse(cr, uid, meeting_id, context).attendee_ids:
- if user.partner_id.id == attendee.partner_id.id:
- return attendee
+ self.ensure_one()
+ for attendee in self.attendee_ids:
+ if self.env.user.partner_id == attendee.partner_id:
+ return attendee
return False
- def get_date_formats(self, cr, uid, context):
- lang = context.get("lang")
- res_lang = self.pool.get('res.lang')
+ @api.model
+ def get_date_formats(self):
+ """ get current date and time format, according to the context lang
+ :return: a tuple with (format date, format time)
+ """
+ lang = self._context.get("lang")
lang_params = {}
if lang:
- ids = res_lang.search(request.cr, uid, [("code", "=", lang)])
- if ids:
- lang_params = res_lang.read(request.cr, uid, ids[0], ["date_format", "time_format"])
+ record_lang = self.env['res.lang'].search([("code", "=", lang)], limit=1)
+ lang_params = {
+ 'date_format': record_lang.date_format,
+ 'time_format': record_lang.time_format
+ }
# formats will be used for str{f,p}time() which do not support unicode in Python 2, coerce to str
format_date = lang_params.get("date_format", '%B-%d-%Y').encode('utf-8')
format_time = lang_params.get("time_format", '%I-%M %p').encode('utf-8')
return (format_date, format_time)
- def get_display_time_tz(self, cr, uid, ids, tz=False, context=None):
- context = dict(context or {})
+ @api.multi
+ def get_display_time_tz(self, tz=False):
+ """ get the display_time of the meeting, forcing the timezone. This method is called from email template, to not use sudo(). """
+ self.ensure_one()
if tz:
- context["tz"] = tz
- ev = self.browse(cr, uid, ids, context=context)[0]
- return self._get_display_time(cr, uid, ev.start, ev.stop, ev.duration, ev.allday, context=context)
+ self = self.with_context(tz=tz)
+ return self._get_display_time(self.start, self.stop, self.duration, self.allday)
- def _get_display_time(self, cr, uid, start, stop, zduration, zallday, context=None):
+ @api.model
+ def _get_display_time(self, start, stop, zduration, zallday):
+ """ Return date and time (from to from) based on duration with timezone in string. Eg :
+ 1) if user add duration for 2 hours, return : August-23-2013 at (04-30 To 06-30) (Europe/Brussels)
+ 2) if event all day ,return : AllDay, July-31-2013
"""
- Return date and time (from to from) based on duration with timezone in string :
- eg.
- 1) if user add duration for 2 hours, return : August-23-2013 at (04-30 To 06-30) (Europe/Brussels)
- 2) if event all day ,return : AllDay, July-31-2013
- """
- context = dict(context or {})
+ timezone = self._context.get('tz')
+ if not timezone:
+ timezone = self.env.user.partner_id.tz
+ timezone = tools.ustr(timezone).encode('utf-8') # make safe for str{p,f}time()
- tz = context.get('tz', False)
- if not tz: # tz can have a value False, so dont do it in the default value of get !
- context['tz'] = self.pool.get('res.users').read(cr, SUPERUSER_ID, uid, ['tz'])['tz']
- tz = context['tz']
- tz = tools.ustr(tz).encode('utf-8') # make safe for str{p,f}time()
+ # get date/time format according to context
+ format_date, format_time = self.with_context(tz=timezone).get_date_formats()
- format_date, format_time = self.get_date_formats(cr, uid, context=context)
- date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(start, tools.DEFAULT_SERVER_DATETIME_FORMAT), context=context)
- date_deadline = fields.datetime.context_timestamp(cr, uid, datetime.strptime(stop, tools.DEFAULT_SERVER_DATETIME_FORMAT), context=context)
- event_date = date.strftime(format_date)
- display_time = date.strftime(format_time)
+ # convert date and time into user timezone
+ date = fields.Datetime.context_timestamp(self.with_context(tz=timezone), fields.Datetime.from_string(start))
+ date_deadline = fields.Datetime.context_timestamp(self.with_context(tz=timezone), fields.Datetime.from_string(stop))
+
+ # convert into string the date and time, using user formats
+ date_str = date.strftime(format_date)
+ time_str = date.strftime(format_time)
if zallday:
- time = _("AllDay , %s") % (event_date)
+ display_time = _("AllDay , %s") % (date_str)
elif zduration < 24:
duration = date + timedelta(hours=zduration)
- time = _("%s at (%s To %s) (%s)") % (event_date, display_time, duration.strftime(format_time), tz)
+ display_time = _("%s at (%s To %s) (%s)") % (date_str, time_str, duration.strftime(format_time), timezone)
else:
- time = _("%s at %s To\n %s at %s (%s)") % (event_date, display_time, date_deadline.strftime(format_date), date_deadline.strftime(format_time), tz)
- return time
+ display_time = _("%s at %s To\n %s at %s (%s)") % (date_str, time_str, date_deadline.strftime(format_date), date_deadline.strftime(format_time), timezone)
+ return display_time
- def _compute(self, cr, uid, ids, fields, arg, context=None):
- res = {}
- if not isinstance(fields, list):
- fields = [fields]
- for meeting in self.browse(cr, uid, ids, context=context):
- meeting_data = {}
- res[meeting.id] = meeting_data
- attendee = self._find_my_attendee(cr, uid, [meeting.id], context)
- for field in fields:
- if field == 'is_attendee':
- meeting_data[field] = bool(attendee)
- elif field == 'attendee_status':
- meeting_data[field] = attendee.state if attendee else 'needsAction'
- elif field == 'display_time':
- meeting_data[field] = self._get_display_time(cr, uid, meeting.start, meeting.stop, meeting.duration, meeting.allday, context=context)
- elif field == "display_start":
- meeting_data[field] = meeting.start_date if meeting.allday else meeting.start_datetime
- elif field == 'start':
- meeting_data[field] = meeting.start_date if meeting.allday else meeting.start_datetime
- elif field == 'stop':
- meeting_data[field] = meeting.stop_date if meeting.allday else meeting.stop_datetime
- return res
+ @api.multi
+ def _compute_attendee(self):
+ for meeting in self:
+ attendee = meeting._find_my_attendee()
+ meeting.is_attendee = bool(attendee)
+ meeting.attendee_status = attendee.state if attendee else 'needsAction'
- def _get_recurrent_fields(self, cr, uid, context=None):
+ @api.multi
+ def _compute_display_time(self):
+ for meeting in self:
+ meeting.display_time = self._get_display_time(meeting.start, meeting.stop, meeting.duration, meeting.allday)
+
+ # TODO JEM : this is strange, if we add depends, then it erase default value
+ @api.multi
+ def _compute_dates(self):
+ for meeting in self:
+ meeting.display_start = meeting.start_date if meeting.allday else meeting.start_datetime
+ meeting.start = meeting.start_date if meeting.allday else meeting.start_datetime
+ meeting.stop = meeting.stop_date if meeting.allday else meeting.stop_datetime
+
+ @api.model
+ def _get_recurrent_fields(self):
return ['byday', 'recurrency', 'final_date', 'rrule_type', 'month_by',
'interval', 'count', 'end_type', 'mo', 'tu', 'we', 'th', 'fr', 'sa',
'su', 'day', 'week_list']
- def _get_rulestring(self, cr, uid, ids, name, arg, context=None):
+ @api.depends('byday', 'recurrency', 'final_date', 'rrule_type', 'month_by', 'interval', 'count', 'end_type', 'mo', 'tu', 'we', 'th', 'fr', 'sa', 'su', 'day', 'week_list')
+ def _compute_rrule(self):
+ """ Gets Recurrence rule string according to value type RECUR of iCalendar from the values given.
+ :return dictionary of rrule value.
"""
- Gets Recurrence rule string according to value type RECUR of iCalendar from the values given.
- @return: dictionary of rrule value.
- """
- result = {}
- if not isinstance(ids, list):
- ids = [ids]
-
#read these fields as SUPERUSER because if the record is private a normal search could raise an error
- recurrent_fields = self._get_recurrent_fields(cr, uid, context=context)
- events = self.read(cr, SUPERUSER_ID, ids, recurrent_fields, context=context)
- for event in events:
- if event['recurrency']:
- result[event['id']] = self.compute_rule_string(event)
+ recurrent_fields = self._get_recurrent_fields()
+ data = self.sudo().read(recurrent_fields)
+
+ for meeting in self:
+ if meeting.recurrency:
+ meeting.rrule = meeting.compute_rule_string()
else:
- result[event['id']] = ''
+ meeting.rrule = ''
- return result
+ @api.multi
+ def _inverse_rrule(self):
+ for meeting in self:
+ if meeting.rrule:
+ data = self._get_empty_rrule_data()
+ data['recurrency'] = True
+ data.update(self._parse_rrule(meeting.rrule, data, meeting.start))
+ meeting.update(data)
- # retro compatibility function
- def _rrule_write(self, cr, uid, ids, field_name, field_value, args, context=None):
- return self._set_rulestring(self, cr, uid, ids, field_name, field_value, args, context=context)
-
- def _set_rulestring(self, cr, uid, ids, field_name, field_value, args, context=None):
- if not isinstance(ids, list):
- ids = [ids]
- data = self._get_empty_rrule_data()
- if field_value:
- data['recurrency'] = True
- for event in self.browse(cr, uid, ids, context=context):
- rdate = event.start
- update_data = self._parse_rrule(field_value, dict(data), rdate)
- data.update(update_data)
- self.write(cr, uid, ids, data, context=context)
- return True
-
- def _set_date(self, cr, uid, values, id=False, context=None):
-
- if context is None:
- context = {}
+ @api.multi
+ def _compute_color_partner(self):
+ for meeting in self:
+ meeting.color_partner_id = meeting.user_id.partner_id.id
+ @api.model
+ def _set_date(self, values, id=False):
if values.get('start_datetime') or values.get('start_date') or values.get('start') \
or values.get('stop_datetime') or values.get('stop_date') or values.get('stop'):
allday = values.get("allday", None)
- event = self.browse(cr, uid, id, context=context)
+ event = self.browse(id)
if allday is None:
if id:
@@ -845,277 +782,257 @@ class calendar_event(osv.Model):
stop_date = values.get('stop_date') or event.stop_date
start_date = values.get('start_date') or event.start_date
if stop_date and start_date:
- diff = openerp.fields.Date.from_string(stop_date) - openerp.fields.Date.from_string(start_date)
+ diff = fields.Date.from_string(stop_date) - fields.Date.from_string(start_date)
elif values.get('stop_datetime') or values.get('start_datetime'):
stop_datetime = values.get('stop_datetime') or event.stop_datetime
start_datetime = values.get('start_datetime') or event.start_datetime
if stop_datetime and start_datetime:
- diff = openerp.fields.Datetime.from_string(stop_datetime) - openerp.fields.Datetime.from_string(start_datetime)
+ diff = fields.Datetime.from_string(stop_datetime) - fields.Datetime.from_string(start_datetime)
if diff:
duration = float(diff.days) * 24 + (float(diff.seconds) / 3600)
values['duration'] = round(duration, 2)
- _columns = {
- 'id': fields.integer('ID', readonly=True),
- 'state': fields.selection([('draft', 'Unconfirmed'), ('open', 'Confirmed')], string='Status', readonly=True, track_visibility='onchange'),
- 'name': fields.char('Meeting Subject', required=True, states={'done': [('readonly', True)]}),
- 'is_attendee': fields.function(_compute, string='Attendee', type="boolean", multi='attendee'),
- 'attendee_status': fields.function(_compute, string='Attendee Status', type="selection", selection=calendar_attendee.STATE_SELECTION, multi='attendee'),
- 'display_time': fields.function(_compute, string='Event Time', type="char", multi='attendee'),
- 'display_start': fields.function(_compute, string='Date', type="char", multi='attendee', store=True),
- 'allday': fields.boolean('All Day', states={'done': [('readonly', True)]}),
- 'start': fields.function(_compute, fnct_inv=lambda *args: None, string='Start', type="datetime", multi='attendee', store=True, required=True, help="Start date of an event, without time for full days events"),
- 'stop': fields.function(_compute, string='Stop', type="datetime", multi='attendee', store=True, required=True, help="Stop date of an event, without time for full days events"),
- 'start_date': fields.date('Start Date', states={'done': [('readonly', True)]}, track_visibility='onchange'),
- 'start_datetime': fields.datetime('Start DateTime', states={'done': [('readonly', True)]}, track_visibility='onchange'),
- 'stop_date': fields.date('End Date', states={'done': [('readonly', True)]}, track_visibility='onchange'),
- 'stop_datetime': fields.datetime('End Datetime', states={'done': [('readonly', True)]}, track_visibility='onchange'), # old date_deadline
- 'duration': fields.float('Duration', states={'done': [('readonly', True)]}),
- 'description': fields.text('Description', states={'done': [('readonly', True)]}),
- 'privacy': fields.selection([('public', 'Everyone'), ('private', 'Only me'), ('confidential', 'Only internal users')], 'Privacy', states={'done': [('readonly', True)]}, oldname='class'),
- 'location': fields.char('Location', help="Location of Event", track_visibility='onchange', states={'done': [('readonly', True)]}),
- 'show_as': fields.selection([('free', 'Free'), ('busy', 'Busy')], 'Show Time as', states={'done': [('readonly', True)]}),
+ name = fields.Char('Meeting Subject', required=True, states={'done': [('readonly', True)]})
+ state = fields.Selection([('draft', 'Unconfirmed'), ('open', 'Confirmed')], string='Status', readonly=True, track_visibility='onchange', default='draft')
- # RECURRENCE FIELD
- 'rrule': fields.function(_get_rulestring, type='char', fnct_inv=_set_rulestring, store=True, string='Recurrent Rule'),
- 'rrule_type': fields.selection([('daily', 'Day(s)'), ('weekly', 'Week(s)'), ('monthly', 'Month(s)'), ('yearly', 'Year(s)')], 'Recurrency', states={'done': [('readonly', True)]}, help="Let the event automatically repeat at that interval"),
- 'recurrency': fields.boolean('Recurrent', help="Recurrent Meeting"),
- 'recurrent_id': fields.integer('Recurrent ID'),
- 'recurrent_id_date': fields.datetime('Recurrent ID date'),
- 'end_type': fields.selection([('count', 'Number of repetitions'), ('end_date', 'End date')], 'Recurrence Termination'),
- 'interval': fields.integer('Repeat Every', help="Repeat every (Days/Week/Month/Year)"),
- 'count': fields.integer('Repeat', help="Repeat x times"),
- 'mo': fields.boolean('Mon'),
- 'tu': fields.boolean('Tue'),
- 'we': fields.boolean('Wed'),
- 'th': fields.boolean('Thu'),
- 'fr': fields.boolean('Fri'),
- 'sa': fields.boolean('Sat'),
- 'su': fields.boolean('Sun'),
- 'month_by': fields.selection([('date', 'Date of month'), ('day', 'Day of month')], 'Option', oldname='select1'),
- 'day': fields.integer('Date of month'),
- 'week_list': fields.selection([('MO', 'Monday'), ('TU', 'Tuesday'), ('WE', 'Wednesday'), ('TH', 'Thursday'), ('FR', 'Friday'), ('SA', 'Saturday'), ('SU', 'Sunday')], 'Weekday'),
- 'byday': fields.selection([('1', 'First'), ('2', 'Second'), ('3', 'Third'), ('4', 'Fourth'), ('5', 'Fifth'), ('-1', 'Last')], 'By day'),
- 'final_date': fields.date('Repeat Until'), # The last event of a recurrence
+ is_attendee = fields.Boolean('Attendee', 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')
+ display_start = fields.Date('Date', compute='_compute_dates', store=True)
+ start = fields.Datetime('Start', compute='_compute_dates', store=True, required=True, help="Start date of an event, without time for full days events")
+ stop = fields.Datetime('Stop', compute='_compute_dates', store=True, required=True, help="Stop date of an event, without time for full days events")
- 'user_id': fields.many2one('res.users', 'Responsible', states={'done': [('readonly', True)]}),
- 'color_partner_id': fields.related('user_id', 'partner_id', 'id', type="integer", string="Color index of creator", store=False), # Color of creator
- 'active': fields.boolean('Active', help="If the active field is set to false, it will allow you to hide the event alarm information without removing it."),
- 'categ_ids': fields.many2many('calendar.event.type', 'meeting_category_rel', 'event_id', 'type_id', 'Tags'),
- 'attendee_ids': fields.one2many('calendar.attendee', 'event_id', 'Participant', ondelete='cascade'),
- 'partner_ids': fields.many2many('res.partner', 'calendar_event_res_partner_rel', string='Attendees', states={'done': [('readonly', True)]}),
- 'alarm_ids': fields.many2many('calendar.alarm', 'calendar_alarm_calendar_event_rel', string='Reminders', ondelete="restrict", copy=False),
- }
+ allday = fields.Boolean('All Day', states={'done': [('readonly', True)]}, default=False)
+ start_date = fields.Date('Start Date', states={'done': [('readonly', True)]}, track_visibility='onchange')
+ start_datetime = fields.Datetime('Start DateTime', states={'done': [('readonly', True)]}, track_visibility='onchange')
+ stop_date = fields.Date('End Date', states={'done': [('readonly', True)]}, track_visibility='onchange')
+ stop_datetime = fields.Datetime('End Datetime', states={'done': [('readonly', True)]}, track_visibility='onchange') # old date_deadline
+ duration = fields.Float('Duration', states={'done': [('readonly', True)]})
+ description = fields.Text('Description', states={'done': [('readonly', True)]})
+ privacy = fields.Selection([('public', 'Everyone'), ('private', 'Only me'), ('confidential', 'Only internal users')], 'Privacy', default='public', states={'done': [('readonly', True)]}, oldname="class")
+ location = fields.Char('Location', states={'done': [('readonly', True)]}, track_visibility='onchange', help="Location of Event")
+ show_as = fields.Selection([('free', 'Free'), ('busy', 'Busy')], 'Show Time as', states={'done': [('readonly', True)]}, default='busy')
- def _get_default_partners(self, cr, uid, ctx=None):
- ret = [self.pool['res.users'].browse(cr, uid, uid, context=ctx).partner_id.id]
- active_id = ctx.get('active_id')
- if ctx.get('active_model') == 'res.partner' and active_id:
- if active_id not in ret:
- ret.append(active_id)
- return ret
+ # RECURRENCE FIELD
+ rrule = fields.Char('Recurrent Rule', compute='_compute_rrule', inverse='_inverse_rrule', store=True)
+ rrule_type = fields.Selection([
+ ('daily', 'Day(s)'),
+ ('weekly', 'Week(s)'),
+ ('monthly', 'Month(s)'),
+ ('yearly', 'Year(s)')
+ ], string='Recurrency', states={'done': [('readonly', True)]}, help="Let the event automatically repeat at that interval")
+ recurrency = fields.Boolean('Recurrent', help="Recurrent Meeting")
+ recurrent_id = fields.Integer('Recurrent ID')
+ recurrent_id_date = fields.Datetime('Recurrent ID date')
+ end_type = fields.Selection([
+ ('count', 'Number of repetitions'),
+ ('end_date', 'End date')
+ ], string='Recurrence Termination', default='count')
+ interval = fields.Integer(string='Repeat Every', default=1, help="Repeat every (Days/Week/Month/Year)")
+ count = fields.Integer(string='Repeat', help="Repeat x times", default=1)
+ mo = fields.Boolean('Mon')
+ tu = fields.Boolean('Tue')
+ we = fields.Boolean('Wed')
+ th = fields.Boolean('Thu')
+ fr = fields.Boolean('Fri')
+ sa = fields.Boolean('Sat')
+ su = fields.Boolean('Sun')
+ month_by = fields.Selection([
+ ('date', 'Date of month'),
+ ('day', 'Day of month')
+ ], string='Option', default='date', oldname='select1')
+ day = fields.Integer('Date of month', default=1)
+ week_list = fields.Selection([
+ ('MO', 'Monday'),
+ ('TU', 'Tuesday'),
+ ('WE', 'Wednesday'),
+ ('TH', 'Thursday'),
+ ('FR', 'Friday'),
+ ('SA', 'Saturday'),
+ ('SU', 'Sunday')
+ ], string='Weekday')
+ byday = fields.Selection([
+ ('1', 'First'),
+ ('2', 'Second'),
+ ('3', 'Third'),
+ ('4', 'Fourth'),
+ ('5', 'Fifth'),
+ ('-1', 'Last')
+ ], string='By day')
+ final_date = fields.Date('Repeat Until')
- _defaults = {
- 'end_type': 'count',
- 'count': 1,
- 'rrule_type': False,
- 'allday': False,
- 'state': 'draft',
- 'privacy': 'public',
- 'show_as': 'busy',
- 'month_by': 'date',
- 'interval': 1,
- 'active': 1,
- 'user_id': lambda self, cr, uid, ctx: uid,
- 'partner_ids': _get_default_partners,
- }
+ user_id = fields.Many2one('res.users', 'Responsible', states={'done': [('readonly', True)]}, default=lambda self: self.env.user)
+ color_partner_id = fields.Integer("Color index of creator", compute='_compute_color_partner', store=False)
- def _check_closing_date(self, cr, uid, ids, context=None):
- for event in self.browse(cr, uid, ids, context=context):
- if event.start_datetime and event.stop_datetime and event.stop_datetime < event.start_datetime:
- return False
- if event.start_date and event.stop_date and event.stop_date < event.start_date:
- return False
- return True
+ active = fields.Boolean('Active', default=True, help="If the active field is set to false, it will allow you to hide the event alarm information without removing it.")
+ categ_ids = fields.Many2many('calendar.event.type', 'meeting_category_rel', 'event_id', 'type_id', 'Tags')
+ attendee_ids = fields.One2many('calendar.attendee', 'event_id', 'Participant', ondelete='cascade')
+ partner_ids = fields.Many2many('res.partner', 'calendar_event_res_partner_rel', string='Attendees', states={'done': [('readonly', True)]}, default=_default_partners)
+ alarm_ids = fields.Many2many('calendar.alarm', 'calendar_alarm_calendar_event_rel', string='Reminders', ondelete="restrict", copy=False)
- _constraints = [
- (_check_closing_date, 'Error ! End date cannot be set before start date.', ['start_datetime', 'stop_datetime', 'start_date', 'stop_date'])
- ]
+ @api.constrains('start_datetime', 'stop_datetime', 'start_date', 'stop_date')
+ def _check_closing_date(self):
+ for meeting in self:
+ if meeting.start_datetime and meeting.stop_datetime and meeting.stop_datetime < meeting.start_datetime:
+ raise ValidationError(_('Ending datetime cannot be set before starting datetime.'))
+ if meeting.start_date and meeting.stop_date and meeting.stop_date < meeting.start_date:
+ raise ValidationError(_('Ending date cannot be set before starting date.'))
- def onchange_allday(self, cr, uid, ids, start=False, end=False, starttime=False, endtime=False, startdatetime=False, enddatetime=False, checkallday=False, context=None):
+ @api.onchange('allday')
+ def _onchange_allday(self):
+ # TODO JEM : it is still requried ?
+ if not ((self.start_date and self.stop_date) or (self.start and self.stop)): # At first intialize, we have not datetime
+ return
- value = {}
-
- if not ((starttime and endtime) or (start and end)): # At first intialize, we have not datetime
- return value
-
- if checkallday: # from datetime to date
- startdatetime = startdatetime or start
+ if self.allday: # from datetime to date
+ startdatetime = self.start_datetime or self.start
if startdatetime:
- start = datetime.strptime(startdatetime, DEFAULT_SERVER_DATETIME_FORMAT)
- value['start_date'] = datetime.strftime(start, DEFAULT_SERVER_DATE_FORMAT)
+ start_datetime = fields.Datetime.from_string(startdatetime)
+ self.start_date = fields.Date.to_string(start_datetime)
- enddatetime = enddatetime or end
+ enddatetime = self.stop_datetime or self.stop
if enddatetime:
- end = datetime.strptime(enddatetime, DEFAULT_SERVER_DATETIME_FORMAT)
- value['stop_date'] = datetime.strftime(end, DEFAULT_SERVER_DATE_FORMAT)
- else: # from date to datetime
- user = self.pool['res.users'].browse(cr, uid, uid, context)
- tz = pytz.timezone(user.tz) if user.tz else pytz.utc
+ stop_datetime = fields.Datetime.from_string(enddatetime)
+ self.stop_date = fields.Date.to_string(stop_datetime)
- if starttime:
- start = openerp.fields.Datetime.from_string(starttime)
+ else: # from date to datetime
+ tz = pytz.timezone(self.env.user.tz) if self.env.user.tz else pytz.utc
+
+ if self.start_date:
+ start = fields.Datetime.from_string(self.start_date)
startdate = tz.localize(start) # Add "+hh:mm" timezone
startdate = startdate.replace(hour=8) # Set 8 AM in localtime
startdate = startdate.astimezone(pytz.utc) # Convert to UTC
- value['start_datetime'] = datetime.strftime(startdate, DEFAULT_SERVER_DATETIME_FORMAT)
- elif start:
- value['start_datetime'] = start
+ self.start_datetime = fields.Datetime.to_string(startdate)
+ elif self.start:
+ self.start_datetime = self.start
- if endtime:
- end = datetime.strptime(endtime.split(' ')[0], DEFAULT_SERVER_DATE_FORMAT)
+ if self.stop_date:
+ end = fields.Datetime.from_string(self.stop_date)
enddate = tz.localize(end).replace(hour=18).astimezone(pytz.utc)
+ self.stop_datetime = fields.Datetime.to_string(enddate)
+ elif self.stop:
+ self.stop_datetime = self.stop
- value['stop_datetime'] = datetime.strftime(enddate, DEFAULT_SERVER_DATETIME_FORMAT)
- elif end:
- value['stop_datetime'] = end
+ @api.onchange('start_datetime', 'duration')
+ def _onchange_duration(self):
+ if not (self.start_datetime and self.duration):
+ return
- return {'value': value}
+ duration = self.duration
+ start_dt = fields.Datetime.from_string(self.start_datetime)
- def onchange_duration(self, cr, uid, ids, start=False, duration=False, context=None):
- value = {}
- if not (start and duration):
- return value
- start = datetime.strptime(start, DEFAULT_SERVER_DATETIME_FORMAT)
- value['stop_date'] = (start + timedelta(hours=duration)).strftime(DEFAULT_SERVER_DATE_FORMAT)
- value['stop'] = (start + timedelta(hours=duration)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
- value['stop_datetime'] = (start + timedelta(hours=duration)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
- value['start_date'] = start.strftime(DEFAULT_SERVER_DATE_FORMAT)
- value['start'] = start.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
- return {'value': value}
+ self.start = fields.Datetime.to_string(start_dt)
+ self.stop = fields.Datetime.to_string(start_dt + timedelta(hours=duration))
+ self.start_date = fields.Date.to_string(start_dt)
+ self.stop_date = fields.Date.to_string(start_dt + timedelta(hours=duration))
+ self.stop_datetime = fields.Datetime.to_string(start_dt + timedelta(hours=duration))
- def onchange_dates(self, cr, uid, ids, fromtype, start=False, end=False, checkallday=False, allday=False, context=None):
+ @api.onchange('start_date')
+ def _onchange_start_date(self):
+ if self.allday:
+ #TODO JEM : is it still required ?
+ self.allday = True # Force to be rewrited
- """Returns duration and end date based on values passed
- @param ids: List of calendar event's IDs.
- """
- value = {}
+ if self.start_date:
+ start = fields.Date.from_string(self.start_date)
+ self.start_datetime = fields.Datetime.from_string(self.start)
+ self.start = fields.Datetime.to_string(start)
- if checkallday != allday:
- return value
+ @api.onchange('stop_date')
+ def _onchange_stop_date(self):
+ if self.allday:
+ #TODO JEM : is it still required ?
+ self.allday = True # Force to be rewrited
- value['allday'] = checkallday # Force to be rewrited
+ if self.stop_date:
+ end = fields.Date.from_string(self.stop_date)
+ self.stop_datetime = fields.Datetime.to_string(end)
+ self.stop = fields.Datetime.to_string(end)
- if allday:
- if fromtype == 'start' and start:
- start = datetime.strptime(start, DEFAULT_SERVER_DATE_FORMAT)
- value['start_datetime'] = datetime.strftime(start, DEFAULT_SERVER_DATETIME_FORMAT)
- value['start'] = datetime.strftime(start, DEFAULT_SERVER_DATETIME_FORMAT)
-
- if fromtype == 'stop' and end:
- end = datetime.strptime(end, DEFAULT_SERVER_DATE_FORMAT)
- value['stop_datetime'] = datetime.strftime(end, DEFAULT_SERVER_DATETIME_FORMAT)
- value['stop'] = datetime.strftime(end, DEFAULT_SERVER_DATETIME_FORMAT)
-
- return {'value': value}
-
- def new_invitation_token(self, cr, uid, record, partner_id):
- return uuid.uuid4().hex
-
- def create_attendees(self, cr, uid, ids, context=None):
- if context is None:
- context = {}
- user_obj = self.pool['res.users']
- current_user = user_obj.browse(cr, uid, uid, context=context)
- res = {}
- for event in self.browse(cr, uid, ids, context):
- attendees = {}
- for att in event.attendee_ids:
- attendees[att.partner_id.id] = True
- new_attendees = []
- new_att_partner_ids = []
- for partner in event.partner_ids:
- if partner.id in attendees:
- continue
- access_token = self.new_invitation_token(cr, uid, event, partner.id)
+ # TODO JEM : change return value, use recordset instead of ids
+ @api.multi
+ def create_attendees(self):
+ current_user = self.env.user
+ result = {}
+ for meeting in self:
+ alreay_meeting_partners = meeting.attendee_ids.mapped('partner_id')
+ meeting_attendees = self.env['calendar.attendee']
+ meeting_partners = self.env['res.partner']
+ for partner in meeting.partner_ids.filtered(lambda partner: partner not in alreay_meeting_partners):
values = {
'partner_id': partner.id,
- 'event_id': event.id,
- 'access_token': access_token,
'email': partner.email,
+ 'event_id': meeting.id,
}
- if partner.id == current_user.partner_id.id:
+ # current user don't have to accept his own meeting
+ if partner == self.env.user.partner_id:
values['state'] = 'accepted'
- att_id = self.pool['calendar.attendee'].create(cr, uid, values, context=context)
- new_attendees.append(att_id)
- new_att_partner_ids.append(partner.id)
+ attendee = self.env['calendar.attendee'].create(values)
- if not current_user.email or current_user.email != partner.email:
+ meeting_attendees |= attendee
+ meeting_partners |= partner
+
+ if current_user.email != partner.email:
mail_from = current_user.email or tools.config.get('email_from', False)
- if not context.get('no_email'):
- self.pool['calendar.attendee']._send_mail_to_attendees(cr, uid, att_id, email_from=mail_from, context=context)
+ if not self._context.get('no_email'):
+ attendee._send_mail_to_attendees(email_from=mail_from)
- if new_attendees:
- self.write(cr, uid, [event.id], {'attendee_ids': [(4, att) for att in new_attendees]}, context=context)
- if new_att_partner_ids:
- self.message_subscribe(cr, uid, [event.id], new_att_partner_ids, context=context)
+ if meeting_attendees:
+ meeting.write({'attendee_ids': [(4, attendee.id) for attendee in meeting_attendees]})
+ if meeting_partners:
+ meeting.message_subscribe(partner_ids=meeting_partners.ids)
# We remove old attendees who are not in partner_ids now.
- all_partner_ids = [part.id for part in event.partner_ids]
- all_part_attendee_ids = [att.partner_id.id for att in event.attendee_ids]
- all_attendee_ids = [att.id for att in event.attendee_ids]
+ all_partner_ids = meeting.partner_ids.ids
+ all_part_attendee_ids = meeting.attendee_ids.mapped('partner_id').ids
+ all_attendee_ids = meeting.attendee_ids.ids
partner_ids_to_remove = map(lambda x: x, set(all_part_attendee_ids + new_att_partner_ids) - set(all_partner_ids))
attendee_ids_to_remove = []
if partner_ids_to_remove:
- attendee_ids_to_remove = self.pool["calendar.attendee"].search(cr, uid, [('partner_id.id', 'in', partner_ids_to_remove), ('event_id', '=', event.id)], context=context)
+ attendee_ids_to_remove = self.env["calendar.attendee"].search([('partner_id.id', 'in', partner_ids_to_remove), ('event_id', '=', meeting.id)]).ids
if attendee_ids_to_remove:
- self.pool['calendar.attendee'].unlink(cr, uid, attendee_ids_to_remove, context)
+ self.env['calendar.attendee'].browse(attendee_ids_to_remove).unlink()
- res[event.id] = {
- 'new_attendee_ids': new_attendees,
+ result[meeting.id] = {
+ 'new_attendee_ids': meeting_attendees.ids,
'old_attendee_ids': all_attendee_ids,
'removed_attendee_ids': attendee_ids_to_remove,
'removed_partner_ids': partner_ids_to_remove
}
- return res
+ return result
+ #TODO JEM : clean code !! make it api.multi
+ @api.model
def get_search_fields(self, browse_event, order_fields, r_date=None):
sort_fields = {}
- for ord in order_fields:
- if ord == 'id' and r_date:
- sort_fields[ord] = '%s-%s' % (browse_event[ord], r_date.strftime("%Y%m%d%H%M%S"))
+ for field in order_fields:
+ if field == 'id' and r_date:
+ sort_fields[field] = '%s-%s' % (browse_event[field], r_date.strftime("%Y%m%d%H%M%S"))
else:
- sort_fields[ord] = browse_event[ord]
- if type(browse_event[ord]) is openerp.osv.orm.browse_record:
- name_get = browse_event[ord].name_get()
+ sort_fields[field] = browse_event[field]
+ if isinstance(browse_event[field], models.BaseModel):
+ name_get = browse_event[field].name_get()
if len(name_get) and len(name_get[0]) >= 2:
- sort_fields[ord] = name_get[0][1]
+ sort_fields[field] = name_get[0][1]
if r_date:
sort_fields['sort_start'] = r_date.strftime("%Y%m%d%H%M%S")
else:
display_start = browse_event['display_start']
- sort_fields['sort_start'] = display_start and display_start.replace(' ', '').replace('-', '') or False
+ sort_fields['sort_start'] = display_start.replace(' ', '').replace('-', '') if display_start else False
return sort_fields
- def get_recurrent_ids(self, cr, uid, event_id, domain, order=None, context=None):
-
- """Gives virtual event ids for recurring events
- This method gives ids of dates that comes between start date and end date of calendar views
-
- @param order: The fields (comma separated, format "FIELD {DESC|ASC}") on which the events should be sorted
+ @api.multi
+ def get_recurrent_ids(self, domain, order=None):
+ """ Gives virtual event ids for recurring events. This method gives ids of dates
+ that comes between start date and end date of calendar views
+ :param order: The fields (comma separated, format "FIELD {DESC|ASC}") on which
+ the events should be sorted
"""
- if not context:
- context = {}
-
- if isinstance(event_id, (basestring, int, long)):
- ids_to_browse = [event_id] # keep select for return
- else:
- ids_to_browse = event_id
-
if order:
order_fields = [field.split()[0] for field in order.split(',')]
else:
@@ -1127,12 +1044,12 @@ class calendar_event(osv.Model):
result_data = []
result = []
- for ev in self.browse(cr, uid, ids_to_browse, context=context):
- if not ev.recurrency or not ev.rrule:
- result.append(ev.id)
- result_data.append(self.get_search_fields(ev, order_fields))
+ for meeting in self:
+ if not meeting.recurrency or not meeting.rrule:
+ result.append(meeting.id)
+ result_data.append(self.get_search_fields(meeting, order_fields))
continue
- rdates = self.get_recurrent_date_by_event(cr, uid, ev, context=context)
+ rdates = self.get_recurrent_date_by_event(meeting)
for r_date in rdates:
# fix domain evaluation
@@ -1175,7 +1092,7 @@ class calendar_event(osv.Model):
if [True for item in new_pile if not item]:
continue
- result_data.append(self.get_search_fields(ev, order_fields, r_date=r_date))
+ result_data.append(self.get_search_fields(meeting, order_fields, r_date=r_date))
if order_fields:
uniq = lambda it: collections.OrderedDict((id(x), x) for x in it).values()
@@ -1193,56 +1110,48 @@ class calendar_event(osv.Model):
comparers = [((itemgetter(col[1:]), -1) if col[0] == '-' else (itemgetter(col), 1)) for col in sort_params]
ids = [r['id'] for r in sorted(result_data, cmp=comparer)]
- if isinstance(event_id, (basestring, int, long)):
- return ids and ids[0] or False
- else:
- return ids
+ return ids
- def compute_rule_string(self, data):
+ @api.multi
+ def compute_rule_string(self):
+ """ Compute rule string according to value type RECUR of iCalendar from the values given.
+ :return: string containing recurring rule (empty if no rule)
"""
- Compute rule string according to value type RECUR of iCalendar from the values given.
- @param self: the object pointer
- @param data: dictionary of freq and interval value
- @return: string containing recurring rule (empty if no rule)
- """
- if data['interval'] and data['interval'] < 0:
+ if self.interval and self.interval < 0:
raise UserError(_('interval cannot be negative.'))
- if data['count'] and data['count'] <= 0:
+ if self.count and self.count <= 0:
raise UserError(_('Event recurrence interval cannot be negative.'))
- def get_week_string(freq, data):
+ def get_week_string(freq):
weekdays = ['mo', 'tu', 'we', 'th', 'fr', 'sa', 'su']
if freq == 'weekly':
- byday = map(lambda x: x.upper(), filter(lambda x: data.get(x) and x in weekdays, data))
+ byday = [field.upper() for field in weekdays if self[field]]
if byday:
return ';BYDAY=' + ','.join(byday)
return ''
- def get_month_string(freq, data):
+ def get_month_string(freq):
if freq == 'monthly':
- if data.get('month_by') == 'date' and (data.get('day') < 1 or data.get('day') > 31):
+ if self.month_by == 'date' and (self.day < 1 or self.day > 31):
raise UserError(_("Please select a proper day of the month."))
- if data.get('month_by') == 'day': # Eg : Second Monday of the month
- return ';BYDAY=' + data.get('byday') + data.get('week_list')
- elif data.get('month_by') == 'date': # Eg : 16th of the month
- return ';BYMONTHDAY=' + str(data.get('day'))
+ if self.month_by == 'day': # Eg : Second Monday of the month
+ return ';BYDAY=' + self.byday + self.week_list
+ elif self.month_by == 'date': # Eg : 16th of the month
+ return ';BYMONTHDAY=' + str(self.day)
return ''
- def get_end_date(data):
- if data.get('final_date'):
- data['end_date_new'] = ''.join((re.compile('\d')).findall(data.get('final_date'))) + 'T235959Z'
+ def get_end_date():
+ end_date_new = ''.join((re.compile('\d')).findall(self.final_date)) + 'T235959Z' if self.final_date else False
+ return (self.end_type == 'count' and (';COUNT=' + str(self.count)) or '') +\
+ ((end_date_new and self.end_type == 'end_date' and (';UNTIL=' + end_date_new)) or '')
- return (data.get('end_type') == 'count' and (';COUNT=' + str(data.get('count'))) or '') +\
- ((data.get('end_date_new') and data.get('end_type') == 'end_date' and (';UNTIL=' + data.get('end_date_new'))) or '')
-
- freq = data.get('rrule_type', False) # day/week/month/year
- res = ''
+ freq = self.rrule_type # day/week/month/year
+ result = ''
if freq:
- interval_srting = data.get('interval') and (';INTERVAL=' + str(data.get('interval'))) or ''
- res = 'FREQ=' + freq.upper() + get_week_string(freq, data) + interval_srting + get_end_date(data) + get_month_string(freq, data)
-
- return res
+ interval_srting = self.interval and (';INTERVAL=' + str(self.interval)) or ''
+ result = 'FREQ=' + freq.upper() + get_week_string(freq) + interval_srting + get_end_date() + get_month_string(freq)
+ return result
def _get_empty_rrule_data(self):
return {
@@ -1268,33 +1177,33 @@ class calendar_event(osv.Model):
def _parse_rrule(self, rule, data, date_start):
day_list = ['mo', 'tu', 'we', 'th', 'fr', 'sa', 'su']
rrule_type = ['yearly', 'monthly', 'weekly', 'daily']
- r = rrule.rrulestr(rule, dtstart=datetime.strptime(date_start, DEFAULT_SERVER_DATETIME_FORMAT))
+ rule = rrule.rrulestr(rule_str, dtstart=fields.Datetime.from_string(date_start))
- if r._freq > 0 and r._freq < 4:
- data['rrule_type'] = rrule_type[r._freq]
- data['count'] = r._count
- data['interval'] = r._interval
- data['final_date'] = r._until and r._until.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
+ if rule._freq > 0 and rule._freq < 4:
+ data['rrule_type'] = rrule_type[rule._freq]
+ data['count'] = rule._count
+ data['interval'] = rule._interval
+ data['final_date'] = rule._until and rule._until.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
#repeat weekly
- if r._byweekday:
+ if rule._byweekday:
for i in xrange(0, 7):
- if i in r._byweekday:
+ if i in rule._byweekday:
data[day_list[i]] = True
data['rrule_type'] = 'weekly'
#repeat monthly by nweekday ((weekday, weeknumber), )
- if r._bynweekday:
- data['week_list'] = day_list[r._bynweekday[0][0]].upper()
- data['byday'] = str(r._bynweekday[0][1])
+ if rule._bynweekday:
+ data['week_list'] = day_list[rule._bynweekday[0][0]].upper()
+ data['byday'] = str(rule._bynweekday[0][1])
data['month_by'] = 'day'
data['rrule_type'] = 'monthly'
- if r._bymonthday:
- data['day'] = r._bymonthday[0]
+ if rule._bymonthday:
+ data['day'] = rule._bymonthday[0]
data['month_by'] = 'date'
data['rrule_type'] = 'monthly'
#repeat yearly but for openerp it's monthly, take same information as monthly but interval is 12 times
- if r._bymonth:
+ if rule._bymonth:
data['interval'] = data['interval'] * 12
#FIXEME handle forever case
@@ -1308,49 +1217,24 @@ class calendar_event(osv.Model):
data['end_type'] = 'end_date'
return data
- def onchange_partner_ids(self, cr, uid, ids, value, context=None):
- """ The basic purpose of this method is to check that destination partners
- effectively have email addresses. Otherwise a warning is thrown.
- :param value: value format: [[6, 0, [3, 4]]]
- """
- res = {'value': {}}
-
- if not value or not value[0] or not value[0][0] == 6:
- return
-
- res.update(self.check_partners_email(cr, uid, value[0][2], context=context))
- return res
-
- def check_partners_email(self, cr, uid, partner_ids, context=None):
- """ Verify that selected partner_ids have an email_address defined.
- Otherwise throw a warning. """
- partner_wo_email_lst = []
- for partner in self.pool['res.partner'].browse(cr, uid, partner_ids, context=context):
- if not partner.email:
- partner_wo_email_lst.append(partner)
- if not partner_wo_email_lst:
- return {}
- warning_msg = _('The following contacts have no email address :')
- for partner in partner_wo_email_lst:
- warning_msg += '\n- %s' % (partner.name)
- return {'warning': {
- 'title': _('Email addresses not found'),
- 'message': warning_msg,
- }}
+ ####################################################
+ # Messaging
+ ####################################################
# shows events of the day for this user
- def _needaction_domain_get(self, cr, uid, context=None):
+ @api.model
+ def _needaction_domain_get(self):
return [
('stop', '<=', time.strftime(DEFAULT_SERVER_DATE_FORMAT + ' 23:59:59')),
('start', '>=', time.strftime(DEFAULT_SERVER_DATE_FORMAT + ' 00:00:00')),
- ('user_id', '=', uid),
+ ('user_id', '=', self.env.user.id),
]
@api.multi
def _get_message_unread(self):
id_map = {x: calendar_id2real_id(x) for x in self.ids}
real = self.browse(set(id_map.values()))
- super(calendar_event, real)._get_message_unread()
+ super(Meeting, real)._get_message_unread()
for event in self:
if event.id == id_map[event.id]:
continue
@@ -1362,7 +1246,7 @@ class calendar_event(osv.Model):
def _get_message_needaction(self):
id_map = {x: calendar_id2real_id(x) for x in self.ids}
real = self.browse(set(id_map.values()))
- super(calendar_event, real)._get_message_needaction()
+ super(Meeting, real)._get_message_needaction()
for event in self:
if event.id == id_map[event.id]:
continue
@@ -1370,67 +1254,53 @@ class calendar_event(osv.Model):
event.message_needaction_counter = rec.message_needaction_counter
event.message_needaction = rec.message_needaction
- @api.multi
- def get_metadata(self):
- real = self.browse(set({x: calendar_id2real_id(x) for x in self.ids}.values()))
- return super(calendar_event, real).get_metadata()
-
- @api.cr_uid_ids_context
- @api.returns('mail.message', lambda value: value.id)
- def message_post(self, cr, uid, thread_id, context=None, **kwargs):
- if isinstance(thread_id, basestring):
- thread_id = get_real_ids(thread_id)
- if context.get('default_date'):
+ @api.returns('self', lambda value: value.id)
+ def message_post(self, **kwargs):
+ thread_id = self.id
+ if isinstance(self.id, basestring):
+ thread_id = get_real_ids(self.id)
+ if self.env.context.get('default_date'):
+ context = dict(self.env.context)
del context['default_date']
- return super(calendar_event, self).message_post(cr, uid, thread_id, context=context, **kwargs)
+ self = self.with_context(context)
+ return super(Meeting, self.browse(thread_id)).message_post(**kwargs)
- def message_subscribe(self, cr, uid, ids, partner_ids=None, channel_ids=None, subtype_ids=None, force=True, context=None):
- return super(calendar_event, self).message_subscribe(
- cr, uid, get_real_ids(ids),
+ @api.multi
+ def message_subscribe(self, partner_ids=None, channel_ids=None, subtype_ids=None, force=True):
+ records = self.browse(get_real_ids(self.ids))
+ return super(Meeting, records).message_subscribe(
partner_ids=partner_ids,
channel_ids=channel_ids,
subtype_ids=subtype_ids,
- force=force,
- context=context)
+ force=force)
- def message_unsubscribe(self, cr, uid, ids, partner_ids=None, channel_ids=None, context=None):
- return super(calendar_event, self).message_unsubscribe(cr, uid, get_real_ids(ids), partner_ids=partner_ids, channel_ids=channel_ids, context=context)
+ @api.multi
+ def message_unsubscribe(self, partner_ids=None, channel_ids=None):
+ records = self.browse(get_real_ids(self.ids))
+ return super(Meeting, records).message_unsubscribe(partner_ids=partner_ids, channel_ids=channel_ids)
- def do_sendmail(self, cr, uid, ids, context=None):
- for event in self.browse(cr, uid, ids, context):
- current_user = self.pool['res.users'].browse(cr, uid, uid, context=context)
+ @api.multi
+ def do_sendmail(self):
+ email = self.env.user.email
+ if email:
+ for meeting in self:
+ meeting.attendee_ids._send_mail_to_attendees(email_from=email)
+ return True
- if current_user.email:
- self.pool['calendar.attendee']._send_mail_to_attendees(cr, uid, [att.id for att in event.attendee_ids], email_from=current_user.email, context=context)
- return
-
- def get_attendee(self, cr, uid, meeting_id, context=None):
- # Used for view in controller
- invitation = {'meeting': {}, 'attendee': []}
-
- meeting = self.browse(cr, uid, int(meeting_id), context=context)
- invitation['meeting'] = {
- 'event': meeting.name,
- 'where': meeting.location,
- 'when': meeting.display_time
- }
-
- for attendee in meeting.attendee_ids:
- invitation['attendee'].append({'name': attendee.cn, 'status': attendee.state})
- return invitation
-
- def get_interval(self, cr, uid, ids, date, interval, tz=None, context=None):
- ''' Format and localize some dates to be used in email templates
+ # TODO JEM : remove date arg, and call self.start instead
+ @api.multi
+ def get_interval(self, date, interval, tz=None):
+ """ Format and localize some dates to be used in email templates
:param string date: date/time to be formatted
:param string interval: Among 'day', 'month', 'dayname' and 'time' indicating the desired formatting
:param string tz: Timezone indicator (optional)
-
:return unicode: Formatted date or time (as unicode string, to prevent jinja2 crash)
- (Function used only in calendar_event_data.xml) '''
-
- date = openerp.fields.Datetime.from_string(date)
+ (Function used only in calendar_event_data.xml)
+ """
+ self.ensure_one()
+ date = fields.Datetime.from_string(date)
if tz:
timezone = pytz.timezone(tz or 'UTC')
@@ -1438,70 +1308,69 @@ class calendar_event(osv.Model):
if interval == 'day':
# Day number (1-31)
- res = unicode(date.day)
+ result = unicode(date.day)
elif interval == 'month':
# Localized month name and year
- res = babel.dates.format_date(date=date, format='MMMM y', locale=context.get('lang', 'en_US'))
+ result = babel.dates.format_date(date=date, format='MMMM y', locale=self._context.get('lang', 'en_US'))
elif interval == 'dayname':
# Localized day name
- res = babel.dates.format_date(date=date, format='EEEE', locale=context.get('lang', 'en_US'))
+ result = babel.dates.format_date(date=date, format='EEEE', locale=self._context.get('lang', 'en_US'))
elif interval == 'time':
# Localized time
+ dummy, format_time = self.get_date_formats()
+ result = tools.ustr(date.strftime(format_time + " %Z"))
- dummy, format_time = self.get_date_formats(cr, uid, context=context)
- res = tools.ustr(date.strftime(format_time + " %Z"))
+ return result
- return res
-
- def search(self, cr, uid, args, offset=0, limit=0, order=None, context=None, count=False):
- if context is None:
- context = {}
-
- if context.get('mymeetings', False):
- partner_id = self.pool['res.users'].browse(cr, uid, uid, context).partner_id.id
- args += [('partner_ids', 'in', [partner_id])]
+ @api.model
+ def search(self, args, offset=0, limit=0, order=None, count=False):
+ if self._context.get('mymeetings'):
+ args += [('partner_ids', 'in', self.env.user.partner_id.ids)]
new_args = []
for arg in args:
new_arg = arg
-
if arg[0] in ('stop_date', 'stop_datetime', 'stop',) and arg[1] == ">=":
- if context.get('virtual_id', True):
+ if self._context.get('virtual_id', True):
new_args += ['|', '&', ('recurrency', '=', 1), ('final_date', arg[1], arg[2])]
elif arg[0] == "id":
- new_id = get_real_ids(arg[2])
- new_arg = (arg[0], arg[1], new_id)
+ new_arg = (arg[0], arg[1], get_real_ids(arg[2]))
new_args.append(new_arg)
- if not context.get('virtual_id', True):
- return super(calendar_event, self).search(cr, uid, new_args, offset=offset, limit=limit, order=order, count=count, context=context)
+ if not self._context.get('virtual_id', True):
+ return super(Meeting, self).search(new_args, offset=offset, limit=limit, order=order, count=count)
# offset, limit, order and count must be treated separately as we may need to deal with virtual ids
- res = super(calendar_event, self).search(cr, uid, new_args, offset=0, limit=0, order=None, context=context, count=False)
- res = self.get_recurrent_ids(cr, uid, res, args, order=order, context=context)
+ events = super(Meeting, self).search(new_args, offset=0, limit=0, order=None, count=False)
+ events = self.browse(events.get_recurrent_ids(args, order=order))
if count:
- return len(res)
+ return len(events)
elif limit:
- return res[offset: offset + limit]
- return res
+ return events[offset: offset + limit]
+ return events
- def copy(self, cr, uid, id, default=None, context=None):
+ @api.multi
+ def copy(self, default=None):
+ self.ensure_one()
default = default or {}
- self._set_date(cr, uid, default, id=default.get('id'), context=context)
- return super(calendar_event, self).copy(cr, uid, calendar_id2real_id(id), default, context)
+ self._set_date(default, id=default.get('id'))
+ return super(Meeting, self.browse(calendar_id2real_id(self.id))).copy(default)
- def _detach_one_event(self, cr, uid, id, values=dict(), context=None):
- real_event_id = calendar_id2real_id(id)
- data = self.read(cr, uid, id, ['allday', 'start', 'stop', 'rrule', 'duration'])
+ @api.multi
+ def _detach_one_event(self, values=dict()):
+ real_id = calendar_id2real_id(self.id)
+ meeting_origin = self.browse(real_id)
+
+ data = self.read(['allday', 'start', 'stop', 'rrule', 'duration'])[0]
data['start_date' if data['allday'] else 'start_datetime'] = data['start']
data['stop_date' if data['allday'] else 'stop_datetime'] = data['stop']
if data.get('rrule'):
data.update(
values,
- recurrent_id=real_event_id,
+ recurrent_id=real_id,
recurrent_id_date=data.get('start'),
rrule_type=False,
rrule='',
@@ -1509,55 +1378,58 @@ class calendar_event(osv.Model):
final_date=datetime.strptime(data.get('start'), DEFAULT_SERVER_DATETIME_FORMAT if data['allday'] else DEFAULT_SERVER_DATETIME_FORMAT) + timedelta(hours=values.get('duration', False) or data.get('duration'))
)
- #do not copy the id
+ # do not copy the id
if data.get('id'):
del(data['id'])
- new_id = self.copy(cr, uid, real_event_id, default=data, context=context)
- return new_id
+ return meeting_origin.copy(default=data)
- def open_after_detach_event(self, cr, uid, ids, context=None):
- if context is None:
- context = {}
-
- new_id = self._detach_one_event(cr, uid, ids[0], context=context)
+ @api.multi
+ def open_after_detach_event(self):
+ meeting = self._detach_one_event()
return {
'type': 'ir.actions.act_window',
'res_model': 'calendar.event',
'view_mode': 'form',
- 'res_id': new_id,
+ 'res_id': meeting.id,
'target': 'current',
'flags': {'form': {'action_buttons': True, 'options': {'mode': 'edit'}}}
}
- def _name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=100, name_get_uid=None):
+ ####################################################
+ # ORM Overrides
+ ####################################################
+
+ @api.multi
+ def get_metadata(self):
+ real = self.browse(set({x: calendar_id2real_id(x) for x in self.ids}.values()))
+ return super(Meeting, real).get_metadata()
+
+ @api.model
+ def _name_search(self, name='', args=None, operator='ilike', limit=100, name_get_uid=None):
for arg in args:
if arg[0] == 'id':
for n, calendar_id in enumerate(arg[2]):
if isinstance(calendar_id, basestring):
arg[2][n] = calendar_id.split('-')[0]
- return super(calendar_event, self)._name_search(cr, user, name=name, args=args, operator=operator, context=context, limit=limit, name_get_uid=name_get_uid)
+ return super(Meeting, self)._name_search(name=name, args=args, operator=operator, limit=limit, name_get_uid=name_get_uid)
- def write(self, cr, uid, ids, values, context=None):
- context = context or {}
- if not isinstance(ids, (tuple, list)):
- ids = [ids]
-
- values0 = values
- dont_notify_ctx = dict(context, dont_notify=True) # to prevent multiple notify_next_alarm
+ @api.multi
+ def write(self, values):
+ initial_values = values
# process events one by one
- for event_id in ids:
+ for meeting in self:
# make a copy, since _set_date() modifies values depending on event
- values = dict(values0)
- self._set_date(cr, uid, values, event_id, context=context)
+ values = dict(initial_values)
+ self._set_date(values, meeting.id)
# special write of complex IDS
real_ids = []
new_ids = []
- if '-' not in str(event_id):
- real_ids = [int(event_id)]
+ if '-' not in str(meeting.id):
+ real_ids = [int(meeting.id)]
else:
- real_event_id = calendar_id2real_id(event_id)
+ real_event_id = calendar_id2real_id(meeting.id)
# if we are setting the recurrency flag to False or if we are only changing fields that
# should be only updated on the real ID and not on the virtual (like message_follower_ids):
@@ -1566,109 +1438,94 @@ class calendar_event(osv.Model):
if not values.get('recurrency', True) or not blacklisted:
real_ids = [real_event_id]
else:
- data = self.read(cr, uid, event_id, ['start', 'stop', 'rrule', 'duration'])
+ data = meeting.read(['start', 'stop', 'rrule', 'duration'])[0]
if data.get('rrule'):
- new_ids = [self._detach_one_event(cr, uid, event_id, values, context=dont_notify_ctx)]
+ new_ids = meeting.with_context(dont_notify=True)._detach_one_event(values).ids # to prevent multiple notify_next_alarm
- super(calendar_event, self).write(cr, uid, real_ids, values, context=context)
+ new_meetings = self.browse(new_ids)
+ real_meetings = self.browse(real_ids)
+ all_meetings = real_meetings + new_meetings
+ super(Meeting, real_meetings).write(values)
# set end_date for calendar searching
if values.get('recurrency') and values.get('end_type', 'count') in ('count', unicode('count')) and \
(values.get('rrule_type') or values.get('count') or values.get('start') or values.get('stop')):
- for id in real_ids:
- final_date = self._get_recurrency_end_date(cr, uid, id, context=context)
- super(calendar_event, self).write(cr, uid, [id], {'final_date': final_date}, context=context)
+ for real_meeting in real_meetings:
+ final_date = real_meeting._get_recurrency_end_date()
+ super(Meeting, real_meeting).write({'final_date': final_date})
attendees_create = False
if values.get('partner_ids', False):
- attendees_create = self.create_attendees(cr, uid, real_ids + new_ids, context=dont_notify_ctx)
+ attendees_create = all_meetings.with_context(dont_notify=True).create_attendees() # to prevent multiple notify_next_alarm
# Notify attendees if there is an alarm on the modified event, or if there was an alarm
# that has just been removed, as it might have changed their next event notification
- if not context.get('dont_notify'):
- event = self.browse(cr, uid, event_id, context=context)
- if len(event.alarm_ids) > 0 or values.get('alarm_ids'):
- partners_to_notify = set([p.id for p in event.partner_ids])
+ if not self._context.get('dont_notify'):
+ if len(meeting.alarm_ids) > 0 or values.get('alarm_ids'):
+ partners_to_notify = meeting.partner_ids.ids
event_attendees_changes = attendees_create and attendees_create[real_ids[0]]
if event_attendees_changes:
partners_to_notify.update(event_attendees_changes['removed_partner_ids'])
- self.pool['calendar.alarm_manager'].notify_next_alarm(cr, uid, partners_to_notify)
+ self.env['calendar.alarm_manager'].notify_next_alarm(partners_to_notify)
if (values.get('start_date') or values.get('start_datetime')) and values.get('active', True):
- for the_id in real_ids + new_ids:
+ for current_meeting in all_meetings:
if attendees_create:
- attendees_create = attendees_create[the_id]
+ attendees_create = attendees_create[current_meeting.id]
mail_to_ids = list(set(attendees_create['old_attendee_ids']) - set(attendees_create['removed_attendee_ids']))
else:
- mail_to_ids = [att.id for att in self.browse(cr, uid, the_id, context=context).attendee_ids]
+ mail_to_ids = current_meeting.attendee_ids.ids
if mail_to_ids:
- current_user = self.pool['res.users'].browse(cr, uid, uid, context=context)
- self.pool['calendar.attendee']._send_mail_to_attendees(cr, uid, mail_to_ids, template_xmlid='calendar_template_meeting_changedate', email_from=current_user.email, context=context)
-
+ self.env['calendar.attendee'].browse(mail_to_ids)._send_mail_to_attendees(template_xmlid='calendar_template_meeting_changedate', email_from=self.env.user.email)
return True
- def create(self, cr, uid, vals, context=None):
- if context is None:
- context = {}
+ @api.model
+ def create(self, values):
+ self._set_date(values, id=False)
+ if not 'user_id' in values: # Else bug with quick_create when we are filter on an other user
+ values['user_id'] = self.env.user.id
- self._set_date(cr, uid, vals, id=False, context=context)
- if not 'user_id' in vals: # Else bug with quick_create when we are filter on an other user
- vals['user_id'] = uid
+ meeting = super(Meeting, self).create(values)
- res = super(calendar_event, self).create(cr, uid, vals, context=context)
-
- dont_notify_context = dict(context, dont_notify=True) # to prevent multiple notify_next_alarm
-
- final_date = self._get_recurrency_end_date(cr, uid, res, context=context)
- self.write(cr, uid, [res], {'final_date': final_date}, context=dont_notify_context)
-
- self.create_attendees(cr, uid, [res], context=dont_notify_context)
+ final_date = meeting._get_recurrency_end_date()
+ # `dont_notify=True` in context to prevent multiple notify_next_alarm
+ meeting.with_context(dont_notify=True).write({'final_date': final_date})
+ meeting.with_context(dont_notify=True).create_attendees()
# Notify attendees if there is an alarm on the created event, as it might have changed their
# next event notification
- if not context.get('dont_notify'):
- event = self.browse(cr, uid, [res], context=context) # remove this when migrating to new API
- if len(event.alarm_ids) > 0:
- self.pool['calendar.alarm_manager'].notify_next_alarm(cr, uid, [p.id for p in event.partner_ids])
+ if not self._context.get('dont_notify'):
+ if len(meeting.alarm_ids) > 0:
+ self.env['calendar.alarm_manager'].notify_next_alarm(meeting.partner_ids.ids)
+ return meeting
- return res
-
- def export_data(self, cr, uid, ids, *args, **kwargs):
+ @api.multi
+ def export_data(self, fields_to_export, raw_data=False):
""" Override to convert virtual ids to ids """
- real_ids = []
- for real_id in get_real_ids(ids):
- if real_id not in real_ids:
- real_ids.append(real_id)
- return super(calendar_event, self).export_data(cr, uid, real_ids, *args, **kwargs)
-
- def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False, lazy=True):
- context = dict(context or {})
+ records = self.browse(set(get_real_ids(self.ids)))
+ return super(Meeting, records).export_data(fields_to_export, raw_data)
+ @api.model
+ def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
if 'date' in groupby:
raise UserError(_('Group by date is not supported, use the calendar view instead.'))
- virtual_id = context.get('virtual_id', True)
- context.update({'virtual_id': False})
- res = super(calendar_event, self).read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby, lazy=lazy)
- return res
+ return super(Meeting, self.with_context(virtual_id=False)).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy)
- def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
- if context is None:
- context = {}
+ @api.multi
+ def read(self, fields=None, load='_classic_read'):
fields2 = fields and fields[:] or None
EXTRAFIELDS = ('privacy', 'user_id', 'duration', 'allday', 'start', 'start_date', 'start_datetime', 'rrule')
for f in EXTRAFIELDS:
if fields and (f not in fields):
fields2.append(f)
- if isinstance(ids, (basestring, int, long)):
- select = [ids]
- else:
- select = ids
- select = map(lambda x: (x, calendar_id2real_id(x)), select)
- result = []
- real_data = super(calendar_event, self).read(cr, uid, [real_id for calendar_id, real_id in select], fields=fields2, context=context, load=load)
- real_data = dict(zip([x['id'] for x in real_data], real_data))
+ select = map(lambda x: (x, calendar_id2real_id(x)), self.ids)
+ real_events = self.browse([real_id for calendar_id, real_id in select])
+ real_data = super(Meeting, real_events).read(fields=fields2, load=load)
+ real_data = dict((d['id'], d) for d in real_data)
+
+ result = []
for calendar_id, real_id in select:
res = real_data[real_id].copy()
ls = calendar_id2real_id(calendar_id, with_date=res and res.get('duration', 0) > 0 and res.get('duration') or 1)
@@ -1684,7 +1541,7 @@ class calendar_event(osv.Model):
res['stop_datetime'] = ls[2]
if 'display_time' in fields:
- res['display_time'] = self._get_display_time(cr, uid, ls[1], ls[2], res['duration'], res['allday'], context=context)
+ res['display_time'] = self._get_display_time(ls[1], ls[2], res['duration'], res['allday'])
res['id'] = calendar_id
result.append(res)
@@ -1692,11 +1549,11 @@ class calendar_event(osv.Model):
for r in result:
if r['user_id']:
user_id = type(r['user_id']) in (tuple, list) and r['user_id'][0] or r['user_id']
- if user_id == uid:
+ if user_id == self.env.user.id:
continue
if r['privacy'] == 'private':
for f in r.keys():
- recurrent_fields = self._get_recurrent_fields(cr, uid, context=context)
+ recurrent_fields = self._get_recurrent_fields()
public_fields = list(set(recurrent_fields + ['id', 'allday', 'start', 'stop', 'display_start', 'display_stop', 'duration', 'user_id', 'state', 'interval', 'count', 'recurrent_id_date', 'rrule']))
if f not in public_fields:
if isinstance(r[f], list):
@@ -1710,44 +1567,34 @@ class calendar_event(osv.Model):
for k in EXTRAFIELDS:
if (k in r) and (fields and (k not in fields)):
del r[k]
- if isinstance(ids, (basestring, int, long)):
- return result and result[0] or False
return result
- def unlink(self, cr, uid, ids, can_be_deleted=True, context=None):
- if not isinstance(ids, list):
- ids = [ids]
- res = False
-
- ids_to_exclure = []
- ids_to_unlink = []
-
+ @api.multi
+ def unlink(self, can_be_deleted=True):
# Get concerned attendees to notify them if there is an alarm on the unlinked events,
# as it might have changed their next event notification
- event_ids = self.search(cr, uid, [('id', 'in', ids), ('alarm_ids', '!=', False)], context=context)
- events = self.browse(cr, uid, event_ids, context=context)
- partner_ids = set()
- for event in events:
- partner_ids.update([p.id for p in event.partner_ids])
+ events = self.search([('id', 'in', self.ids), ('alarm_ids', '!=', False)])
+ partner_ids = events.mapped('partner_ids').ids
- for event_id in ids:
- if can_be_deleted and len(str(event_id).split('-')) == 1: # if ID REAL
- if self.browse(cr, uid, int(event_id), context).recurrent_id:
- ids_to_exclure.append(event_id)
+ records_to_exclude = self.env['calendar.event']
+ records_to_unlink = self.env['calendar.event']
+
+ for meeting in self:
+ if can_be_deleted and is_calendar_id(meeting.id): # if ID REAL
+ if meeting.recurrent_id:
+ records_to_exclude |= meeting
else:
- ids_to_unlink.append(int(event_id))
+ # int() required because 'id' from calendar view is a string, since it can be calendar virtual id
+ records_to_unlink |= self.browse(int(meeting.id))
else:
- ids_to_exclure.append(event_id)
+ records_to_exclude |= meeting
- if ids_to_unlink:
- res = super(calendar_event, self).unlink(cr, uid, ids_to_unlink, context=context)
-
- if ids_to_exclure:
- ctx = dict(context, dont_notify=True) # to prevent multiple notify_next_alarm
- for id_to_exclure in ids_to_exclure:
- res = self.write(cr, uid, id_to_exclure, {'active': False}, context=ctx)
+ result = False
+ if records_to_unlink:
+ result = super(Meeting, records_to_unlink).unlink()
+ if records_to_exclude:
+ result = records_to_exclude.with_context(dont_notify=True).write({'active': False})
# Notify the concerned attendees (must be done after removing the events)
- self.pool['calendar.alarm_manager'].notify_next_alarm(cr, uid, partner_ids)
-
- return res
+ self.env['calendar.alarm_manager'].notify_next_alarm(partner_ids)
+ return result
diff --git a/addons/calendar/models/ir_attachment.py b/addons/calendar/models/ir_attachment.py
index a5767b496d1..c98242db7e7 100644
--- a/addons/calendar/models/ir_attachment.py
+++ b/addons/calendar/models/ir_attachment.py
@@ -1,29 +1,28 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from openerp.osv import osv
+from odoo import api, models
from odoo.addons.calendar.models.calendar import get_real_ids
-class ir_attachment(osv.Model):
+class Attachment(models.Model):
+
_inherit = "ir.attachment"
- def search(self, cr, uid, args, offset=0, limit=0, order=None, context=None, count=False):
- '''
- convert the search on real ids in the case it was asked on virtual ids, then call super()
- '''
+ @api.model
+ def search(self, args, offset=0, limit=0, order=None, count=False):
+ """ Convert the search on real ids in the case it was asked on virtual ids, then call super() """
args = list(args)
- if any([leaf for leaf in args if leaf[0] == "res_model" and leaf[2] == 'calendar.event']):
+ if any([leaf for leaf in args if leaf[0] == "res_model" and leaf[2] == 'calendar.event']):
for index in range(len(args)):
if args[index][0] == "res_id" and isinstance(args[index][2], basestring):
args[index] = (args[index][0], args[index][1], get_real_ids(args[index][2]))
- return super(ir_attachment, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=count)
+ return super(Attachment, self).search(args, offset=offset, limit=limit, order=order, count=count)
- def write(self, cr, uid, ids, vals, context=None):
- '''
- when posting an attachment (new or not), convert the virtual ids in real ids.
- '''
+ @api.multi
+ def write(self, vals):
+ """ When posting an attachment (new or not), convert the virtual ids in real ids. """
if isinstance(vals.get('res_id'), basestring):
vals['res_id'] = get_real_ids(vals.get('res_id'))
- return super(ir_attachment, self).write(cr, uid, ids, vals, context=context)
+ return super(Attachment, self).write(vals)
diff --git a/addons/calendar/models/ir_http.py b/addons/calendar/models/ir_http.py
index 4f7a91d8178..53b8a9b9f26 100644
--- a/addons/calendar/models/ir_http.py
+++ b/addons/calendar/models/ir_http.py
@@ -1,34 +1,35 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-import openerp
-from openerp.osv import osv
+import odoo
+from odoo import api, models, SUPERUSER_ID
from openerp.http import request
+from openerp.api import Environment
from werkzeug.exceptions import BadRequest
-class ir_http(osv.AbstractModel):
+class IrHttp(models.AbstractModel):
+
_inherit = 'ir.http'
def _auth_method_calendar(self):
token = request.params['token']
- db = request.params['db']
+ dbname = request.params['db']
- registry = openerp.modules.registry.RegistryManager.get(db)
- attendee_pool = registry.get('calendar.attendee')
+ registry = odoo.modules.registry.RegistryManager.get(dbname)
error_message = False
with registry.cursor() as cr:
- attendee_id = attendee_pool.search(cr, openerp.SUPERUSER_ID, [('access_token', '=', token)])
- if not attendee_id:
+ env = Environment(cr, SUPERUSER_ID, {})
+
+ attendee = env['calendar.attendee'].sudo().search([('access_token', '=', token)], limit=1)
+ if not attendee:
error_message = """Invalid Invitation Token."""
elif request.session.uid and request.session.login != 'anonymous':
- # if valid session but user is not match
- attendee = attendee_pool.browse(cr, openerp.SUPERUSER_ID, attendee_id[0])
- user = registry.get('res.users').browse(cr, openerp.SUPERUSER_ID, request.session.uid)
- if attendee.partner_id.id != user.partner_id.id:
+ # if valid session but user is not match
+ user = env['res.users'].sudo().browse(request.session.uid)
+ if attendee.partner_id != user.partner_id:
error_message = """Invitation cannot be forwarded via email. This event/meeting belongs to %s and you are logged in as %s. Please ask organizer to add you.""" % (attendee.email, user.email)
-
if error_message:
raise BadRequest(error_message)
diff --git a/addons/calendar/models/ir_values.py b/addons/calendar/models/ir_values.py
index 902a736ce9c..d6f2bc86c14 100644
--- a/addons/calendar/models/ir_values.py
+++ b/addons/calendar/models/ir_values.py
@@ -1,32 +1,31 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from openerp.osv import osv
+from odoo import api, models
from odoo.addons.calendar.models.calendar import calendar_id2real_id
-class ir_values(osv.Model):
+class IrValues(models.Model):
+
_inherit = 'ir.values'
- def set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=False, preserve_user=False, company=False):
+ @api.model
+ def set(self, key, key2, name, models, value, replace=True, isobject=False, meta=False, preserve_user=False, company=False):
new_model = []
for data in models:
if type(data) in (list, tuple):
new_model.append((data[0], calendar_id2real_id(data[1])))
else:
new_model.append(data)
- return super(ir_values, self).set(cr, uid, key, key2, name, new_model,
- value, replace, isobject, meta, preserve_user, company)
+ return super(IrValues, self).set(key, key2, name, new_model, value, replace, isobject, meta, preserve_user, company)
- def get(self, cr, uid, key, key2, models, meta=False, context=None, res_id_req=False, without_user=True, key2_req=True):
- if context is None:
- context = {}
+ @api.model
+ def get(self, key, key2, models, meta=False, res_id_req=False, without_user=True, key2_req=True):
new_model = []
for data in models:
if type(data) in (list, tuple):
new_model.append((data[0], calendar_id2real_id(data[1])))
else:
new_model.append(data)
- return super(ir_values, self).get(cr, uid, key, key2, new_model,
- meta, context, res_id_req, without_user, key2_req)
+ return super(IrValues, self).get(key, key2, new_model, meta, res_id_req, without_user, key2_req)
diff --git a/addons/calendar/models/mail_message.py b/addons/calendar/models/mail_message.py
index 518dcae33dd..a33e23b6726 100644
--- a/addons/calendar/models/mail_message.py
+++ b/addons/calendar/models/mail_message.py
@@ -1,18 +1,18 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from openerp.osv import osv
+from odoo import api, models
from odoo.addons.calendar.models.calendar import get_real_ids
-class mail_message(osv.Model):
+class Message(models.Model):
+
_inherit = "mail.message"
- def search(self, cr, uid, args, offset=0, limit=0, order=None, context=None, count=False):
- '''
- convert the search on real ids in the case it was asked on virtual ids, then call super()
- '''
+ @api.model
+ def search(self, args, offset=0, limit=0, order=None, count=False):
+ """ Convert the search on real ids in the case it was asked on virtual ids, then call super() """
args = list(args)
for index in range(len(args)):
if args[index][0] == "res_id":
@@ -20,13 +20,12 @@ class mail_message(osv.Model):
args[index] = (args[index][0], args[index][1], get_real_ids(args[index][2]))
elif isinstance(args[index][2], list):
args[index] = (args[index][0], args[index][1], map(lambda x: get_real_ids(x), args[index][2]))
- return super(mail_message, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=count)
+ return super(Message, self).search(args, offset=offset, limit=limit, order=order, count=count)
- def _find_allowed_model_wise(self, cr, uid, doc_model, doc_dict, context=None):
- if context is None:
- context = {}
+ @api.model
+ def _find_allowed_model_wise(self, doc_model, doc_dict):
if doc_model == 'calendar.event':
- order = context.get('order', self._order)
- for virtual_id in self.pool[doc_model].get_recurrent_ids(cr, uid, doc_dict.keys(), [], order=order, context=context):
+ order = self._context.get('order', self._order)
+ for virtual_id in self.env[doc_model].get_recurrent_ids(doc_dict.keys(), [], order=order):
doc_dict.setdefault(virtual_id, doc_dict[get_real_ids(virtual_id)])
- return super(mail_message, self)._find_allowed_model_wise(cr, uid, doc_model, doc_dict, context=context)
+ return super(Message, self)._find_allowed_model_wise(doc_model, doc_dict)
diff --git a/addons/calendar/models/res_partner.py b/addons/calendar/models/res_partner.py
index 7174820d96e..606a39baf45 100644
--- a/addons/calendar/models/res_partner.py
+++ b/addons/calendar/models/res_partner.py
@@ -3,28 +3,28 @@
from datetime import datetime
-from openerp.osv import osv, fields
+from odoo import api, fields, models
from odoo.addons.calendar.models.calendar import get_real_ids
-class res_partner(osv.Model):
+class Partner(models.Model):
_inherit = 'res.partner'
- _columns = {
- 'calendar_last_notif_ack': fields.datetime('Last notification marked as read from base Calendar'),
- }
- def get_attendee_detail(self, cr, uid, ids, meeting_id, context=None):
- """
- Return a list of tuple (id, name, status)
- Used by web_calendar.js : Many2ManyAttendee
+ calendar_last_notif_ack = fields.Datetime('Last notification marked as read from base Calendar')
+
+ @api.multi
+ def get_attendee_detail(self, meeting_id):
+ """ Return a list of tuple (id, name, status)
+ Used by web_calendar.js : Many2ManyAttendee
"""
datas = []
meeting = None
if meeting_id:
- meeting = self.pool['calendar.event'].browse(cr, uid, get_real_ids(meeting_id), context=context)
- for partner in self.browse(cr, uid, ids, context=context):
- data = self.name_get(cr, uid, [partner.id], context)[0]
+ meeting = self.env['calendar.event'].browse(get_real_ids(meeting_id))
+
+ for partner in self:
+ data = partner.name_get()[0]
data = [data[0], data[1], False, partner.color]
if meeting:
for attendee in meeting.attendee_ids:
@@ -33,7 +33,8 @@ class res_partner(osv.Model):
datas.append(data)
return datas
- def _set_calendar_last_notif_ack(self, cr, uid, context=None):
- partner = self.pool['res.users'].browse(cr, uid, uid, context=context).partner_id
- self.write(cr, uid, partner.id, {'calendar_last_notif_ack': datetime.now()}, context=context)
+ @api.model
+ def _set_calendar_last_notif_ack(self):
+ partner = self.env['res.users'].browse(self.env.uid).partner_id
+ partner.write({'calendar_last_notif_ack': datetime.now()})
return
diff --git a/addons/calendar/security/calendar_security.xml b/addons/calendar/security/calendar_security.xml
index 80eb79553a0..e448e61a075 100644
--- a/addons/calendar/security/calendar_security.xml
+++ b/addons/calendar/security/calendar_security.xml
@@ -1,12 +1,12 @@
-
+Own events
-
+ [('partner_ids','in',user.partner_id.id)]
-
+
@@ -18,10 +18,10 @@
Own attendees
-
+ [(1,'=',1)]
-
+
-
+
diff --git a/addons/calendar/test/calendar_test.yml b/addons/calendar/test/calendar_test.yml
index ec5d7a87d75..70ef9ea1bbb 100644
--- a/addons/calendar/test/calendar_test.yml
+++ b/addons/calendar/test/calendar_test.yml
@@ -34,7 +34,7 @@
ids = self.search(cr, uid, [('start', '>=', '2011-04-30 16:00:00'), ('start', '<=', '2011-05-31 00:00:00')], context={'virtual_id': True} )
before = self.search(cr, uid, [('start', '>=', '2011-04-30 16:00:00'), ('start', '<=', '2011-05-31 00:00:00')], context={'virtual_id': False})
# We start by detach the event
- newid = self._detach_one_event(cr, uid,ids[1])
+ newid = self._detach_one_event(cr, uid,ids[1]).id
self.write(cr, uid,[newid], {'name':'New Name','recurrency' : True}, context={'virtual_id': True})
after = self.search(cr, uid, [('start', '>=', '2011-04-30 16:00:00'), ('start', '<=', '2011-05-31 00:00:00')], context={'virtual_id': False})
assert len(after) == len(before)+1, 'Wrong number of events found, after to have moved a virtual event'
diff --git a/addons/calendar/views/calendar_views.xml b/addons/calendar/views/calendar_views.xml
index ea5fcb693cb..d358c987d27 100644
--- a/addons/calendar/views/calendar_views.xml
+++ b/addons/calendar/views/calendar_views.xml
@@ -1,12 +1,9 @@
-
-
-
-
-
+
+
- Meeting Types Tree
+ calendar.event.typecalendar.event.type
@@ -22,16 +19,16 @@
-
+
- Calendar Alarm Tree
+ calendar.alarm.treecalendar.alarm
-
-
+
+
@@ -47,8 +44,8 @@
-
-
+
+
@@ -62,10 +59,27 @@
-
+
+
+ calendar.event.tree
+ calendar.event
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- Calendar - Event Form
+
+ calendar.event.formcalendar.event
@@ -86,7 +100,6 @@
@@ -103,17 +116,17 @@
-
-
+
+
-
+
-
+ hours
-
+
- Meetings Dialog
+
+ calendar.event.formcalendar.event
@@ -242,29 +255,8 @@
-
-
-
- CRM - Meetings Tree
- calendar.event
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Meeting
+
+ calendar.event.calendarcalendar.event
@@ -279,9 +271,8 @@
-
- CRM - Meetings Search
+ calendar.event.searchcalendar.event
@@ -320,31 +311,54 @@
-
+
+ calendar
-
+
+ tree
-
+
+ form
+
+
+
-
-
-
-
+
+
+
@@ -354,6 +368,4 @@
-
-
-
+
\ No newline at end of file
diff --git a/addons/calendar/wizard/mail_invite.py b/addons/calendar/wizard/mail_invite.py
index 3f67498427e..84901f8d4c4 100644
--- a/addons/calendar/wizard/mail_invite.py
+++ b/addons/calendar/wizard/mail_invite.py
@@ -1,21 +1,21 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from openerp.osv import osv
+from odoo import models
from odoo.addons.calendar.models.calendar import get_real_ids
-class invite_wizard(osv.osv_memory):
+class MailInvite(models.TransientModel):
+
_inherit = 'mail.wizard.invite'
- def default_get(self, cr, uid, fields, context=None):
- '''
- in case someone clicked on 'invite others' wizard in the followers widget, transform virtual ids in real ids
- '''
- if 'default_res_id' in context:
- context = dict(context, default_res_id=get_real_ids(context['default_res_id']))
- result = super(invite_wizard, self).default_get(cr, uid, fields, context=context)
+ def default_get(self, fields):
+ """ In case someone clicked on 'invite others' wizard in the followers widget, transform virtual ids in real ids """
+ if 'default_res_id' in self._context:
+ self = self.with_context(default_res_id=get_real_ids(self._context['default_res_id']))
+
+ result = super(MailInvite, self).default_get(fields)
if 'res_id' in result:
result['res_id'] = get_real_ids(result['res_id'])
return result