[REF] calendar: reorder methods, make some private, and rename some others

This commit is contained in:
Jérome Maes
2016-07-14 14:04:34 +02:00
parent e3560bd310
commit 21e4579551
2 changed files with 195 additions and 184 deletions
+193 -182
View File
@@ -348,7 +348,7 @@ class AlarmManager(models.AbstractModel):
if meeting.recurrency:
at_least_one = False
last_found = False
for one_date in current_event.get_recurrent_date_by_event():
for one_date in current_event._get_recurrent_date_by_event():
in_date_format = one_date.replace(tzinfo=None)
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:
@@ -526,7 +526,7 @@ class Meeting(models.Model):
return partners
@api.multi
def get_recurrent_date_by_event(self):
def _get_recurrent_date_by_event(self):
""" Get recurrent dates based on Rule string and all event where recurrent_id is child """
self.ensure_one()
@@ -588,7 +588,7 @@ class Meeting(models.Model):
return False
@api.model
def get_date_formats(self):
def _get_date_formats(self):
""" get current date and time format, according to the context lang
:return: a tuple with (format date, format time)
"""
@@ -606,13 +606,11 @@ class Meeting(models.Model):
format_time = lang_params.get("time_format", '%I-%M %p').encode('utf-8')
return (format_date, format_time)
@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:
self = self.with_context(tz=tz)
return self._get_display_time(self.start, self.stop, self.duration, self.allday)
@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']
@api.model
def _get_display_time(self, start, stop, zduration, zallday):
@@ -626,7 +624,7 @@ class Meeting(models.Model):
timezone = tools.ustr(timezone).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.with_context(tz=timezone)._get_date_formats()
# convert date and time into user timezone
date = fields.Datetime.context_timestamp(self.with_context(tz=timezone), fields.Datetime.from_string(start))
@@ -645,61 +643,6 @@ class Meeting(models.Model):
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
@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'
@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']
@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.
"""
#read these fields as SUPERUSER because if the record is private a normal search could raise an error
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:
meeting.rrule = ''
@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)
@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') \
@@ -818,6 +761,55 @@ class Meeting(models.Model):
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)
@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'
@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.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.
"""
#read these fields as SUPERUSER because if the record is private a normal search could raise an error
recurrent_fields = self._get_recurrent_fields()
data = self.sudo().read(recurrent_fields)
for meeting in self:
if meeting.recurrency:
meeting.rrule = meeting._rrule_serialize()
else:
meeting.rrule = ''
@api.multi
def _inverse_rrule(self):
for meeting in self:
if meeting.rrule:
data = self._rrule_default_values()
data['recurrency'] = True
data.update(self._rrule_parse(meeting.rrule, data, meeting.start))
meeting.update(data)
@api.multi
def _compute_color_partner(self):
for meeting in self:
meeting.color_partner_id = meeting.user_id.partner_id.id
@api.constrains('start_datetime', 'stop_datetime', 'start_date', 'stop_date')
def _check_closing_date(self):
for meeting in self:
@@ -898,6 +890,10 @@ class Meeting(models.Model):
self.stop_datetime = fields.Datetime.to_string(end)
self.stop = fields.Datetime.to_string(end)
####################################################
# Calendar Business, Reccurency, ...
####################################################
@api.multi
def get_ics_file(self):
""" Returns iCalendar file for the event invitation.
@@ -1051,7 +1047,7 @@ class Meeting(models.Model):
result.append(meeting.id)
result_data.append(meeting.get_search_fields(order_fields))
continue
rdates = meeting.get_recurrent_date_by_event()
rdates = meeting._get_recurrent_date_by_event()
for r_date in rdates:
# fix domain evaluation
@@ -1115,8 +1111,8 @@ class Meeting(models.Model):
return ids
@api.multi
def compute_rule_string(self):
""" Compute rule string according to value type RECUR of iCalendar from the values given.
def _rrule_serialize(self):
""" Compute rule string according to value type RECUR of iCalendar
:return: string containing recurring rule (empty if no rule)
"""
if self.interval and self.interval < 0:
@@ -1155,7 +1151,7 @@ class Meeting(models.Model):
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):
def _rrule_default_values(self):
return {
'byday': False,
'recurrency': False,
@@ -1176,7 +1172,7 @@ class Meeting(models.Model):
'week_list': False
}
def _parse_rrule(self, rule, data, date_start):
def _rrule_parse(self, rule_str, data, date_start):
day_list = ['mo', 'tu', 'we', 'th', 'fr', 'sa', 'su']
rrule_type = ['yearly', 'monthly', 'weekly', 'daily']
rule = rrule.rrulestr(rule_str, dtstart=fields.Datetime.from_string(date_start))
@@ -1219,6 +1215,97 @@ class Meeting(models.Model):
data['end_type'] = 'end_date'
return data
@api.multi
def get_interval(self, interval, tz=None):
""" Format and localize some dates to be used in email templates
: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)
"""
self.ensure_one()
date = fields.Datetime.from_string(self.start)
if tz:
timezone = pytz.timezone(tz or 'UTC')
date = date.replace(tzinfo=pytz.timezone('UTC')).astimezone(timezone)
if interval == 'day':
# Day number (1-31)
result = unicode(date.day)
elif interval == 'month':
# Localized month name and year
result = babel.dates.format_date(date=date, format='MMMM y', locale=self._context.get('lang', 'en_US'))
elif interval == 'dayname':
# Localized day name
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"))
return result
@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:
self = self.with_context(tz=tz)
return self._get_display_time(self.start, self.stop, self.duration, self.allday)
@api.multi
def detach_recurring_event(self, values=None):
""" Detach a virtual recurring event by duplicating the original and change reccurent values
:param values : dict of value to override on the detached event
"""
if not values:
values = {}
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_id,
recurrent_id_date=data.get('start'),
rrule_type=False,
rrule='',
recurrency=False,
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
if data.get('id'):
del data['id']
return meeting_origin.copy(default=data)
@api.multi
def action_detach_recurring_event(self):
meeting = self.detach_recurring_event()
return {
'type': 'ir.actions.act_window',
'res_model': 'calendar.event',
'view_mode': 'form',
'res_id': meeting.id,
'target': 'current',
'flags': {'form': {'action_buttons': True, 'options': {'mode': 'edit'}}}
}
@api.multi
def action_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
####################################################
# Messaging
####################################################
@@ -1256,6 +1343,7 @@ class Meeting(models.Model):
event.message_needaction_counter = rec.message_needaction_counter
event.message_needaction = rec.message_needaction
@api.multi
@api.returns('self', lambda value: value.id)
def message_post(self, **kwargs):
thread_id = self.id
@@ -1281,117 +1369,6 @@ class Meeting(models.Model):
records = self.browse(get_real_ids(self.ids))
return super(Meeting, records).message_unsubscribe(partner_ids=partner_ids, channel_ids=channel_ids)
@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
@api.multi
def get_interval(self, interval, tz=None):
""" Format and localize some dates to be used in email templates
: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)
"""
self.ensure_one()
date = fields.Datetime.from_string(self.start)
if tz:
timezone = pytz.timezone(tz or 'UTC')
date = date.replace(tzinfo=pytz.timezone('UTC')).astimezone(timezone)
if interval == 'day':
# Day number (1-31)
result = unicode(date.day)
elif interval == 'month':
# Localized month name and year
result = babel.dates.format_date(date=date, format='MMMM y', locale=self._context.get('lang', 'en_US'))
elif interval == 'dayname':
# Localized day name
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"))
return result
@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 self._context.get('virtual_id', True):
new_args += ['|', '&', ('recurrency', '=', 1), ('final_date', arg[1], arg[2])]
elif arg[0] == "id":
new_arg = (arg[0], arg[1], get_real_ids(arg[2]))
new_args.append(new_arg)
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
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(events)
elif limit:
return events[offset: offset + limit]
return events
@api.multi
def copy(self, default=None):
self.ensure_one()
default = default or {}
self._set_date(default, id=default.get('id'))
return super(Meeting, self.browse(calendar_id2real_id(self.id))).copy(default)
@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_id,
recurrent_id_date=data.get('start'),
rrule_type=False,
rrule='',
recurrency=False,
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
if data.get('id'):
del(data['id'])
return meeting_origin.copy(default=data)
@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': meeting.id,
'target': 'current',
'flags': {'form': {'action_buttons': True, 'options': {'mode': 'edit'}}}
}
####################################################
# ORM Overrides
####################################################
@@ -1595,3 +1572,37 @@ class Meeting(models.Model):
# Notify the concerned attendees (must be done after removing the events)
self.env['calendar.alarm_manager'].notify_next_alarm(partner_ids)
return result
@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 self._context.get('virtual_id', True):
new_args += ['|', '&', ('recurrency', '=', 1), ('final_date', arg[1], arg[2])]
elif arg[0] == "id":
new_arg = (arg[0], arg[1], get_real_ids(arg[2]))
new_args.append(new_arg)
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
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(events)
elif limit:
return events[offset: offset + limit]
return events
@api.multi
def copy(self, default=None):
self.ensure_one()
default = default or {}
self._set_date(default, id=default.get('id'))
return super(Meeting, self.browse(calendar_id2real_id(self.id))).copy(default)
+2 -2
View File
@@ -107,7 +107,7 @@
<page string="Meeting Details">
<group attrs="{'invisible': [('recurrency','==',False)]}" class="oe_edit_only ">
<p class='alert alert-warning'> This event is linked to a recurrence...<br/>
<button type="object" name="open_after_detach_event" string="Update only this instance" help="Click here to update only this instance and not all recurrences. " class="oe_link"/>
<button type="object" name="action_detach_recurring_event" string="Update only this instance" help="Click here to update only this instance and not all recurrences. " class="oe_link"/>
</p>
</group>
<group>
@@ -195,7 +195,7 @@
</page>
<page string="Invitations" groups="base.group_no_one">
<button name="do_sendmail" type="object" string="Send mail" icon="fa-envelope" class="oe_link"/>
<button name="action_sendmail" type="object" string="Send mail" icon="fa-envelope" class="oe_link"/>
<field name="attendee_ids" widget="one2many" >
<tree string="Invitation details" editable="top" create="false" delete="false">
<field name="partner_id" />