2009-12-18 13:44:31 +00:00
# -*- coding: utf-8 -*-
2009-12-04 08:25:52 +00:00
##############################################################################
2010-03-25 12:07:00 +00:00
#
2009-12-04 08:25:52 +00:00
# OpenERP, Open Source Management Solution
2010-01-12 09:18:39 +00:00
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
2009-12-04 08:25:52 +00:00
#
# This program is free software: you can redistribute it and/or modify
2009-12-18 13:44:31 +00:00
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
2009-12-04 08:25:52 +00:00
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2009-12-18 13:44:31 +00:00
# GNU Affero General Public License for more details.
2009-12-04 08:25:52 +00:00
#
2009-12-18 13:44:31 +00:00
# You should have received a copy of the GNU Affero General Public License
2010-03-25 12:07:00 +00:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2009-12-04 08:25:52 +00:00
#
##############################################################################
2010-03-25 12:07:00 +00:00
2013-11-23 11:36:27 +00:00
import hashlib
import pytz
import re
import time
import openerp
import openerp . service . report
2011-01-19 08:08:26 +00:00
from datetime import datetime , timedelta , date
2009-12-16 14:16:20 +00:00
from dateutil import parser
2010-02-11 14:08:46 +00:00
from dateutil import rrule
2011-03-31 12:40:25 +00:00
from dateutil . relativedelta import relativedelta
2013-11-23 11:36:27 +00:00
from openerp import tools , SUPERUSER_ID
2012-12-06 14:56:32 +00:00
from openerp . osv import fields , osv
2013-11-23 11:36:27 +00:00
from openerp . tools import DEFAULT_SERVER_DATE_FORMAT , DEFAULT_SERVER_DATETIME_FORMAT
2012-12-06 14:56:32 +00:00
from openerp . tools . translate import _
2013-11-06 16:47:00 +00:00
2013-11-23 11:36:27 +00:00
2013-11-06 16:47:00 +00:00
2013-12-02 14:52:42 +00:00
2010-02-11 12:37:41 +00:00
def base_calendar_id2real_id ( base_calendar_id = None , with_date = False ) :
2010-03-18 11:30:31 +00:00
"""
2012-10-05 17:10:55 +00:00
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 base_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 + base_calendar_id
@return : real event id
2010-03-18 11:30:31 +00:00
"""
2010-02-11 12:37:41 +00:00
if base_calendar_id and isinstance ( base_calendar_id , ( str , unicode ) ) :
res = base_calendar_id . split ( ' - ' )
if len ( res ) > = 2 :
real_id = res [ 0 ]
if with_date :
2013-11-12 08:18:57 +00:00
real_date = time . strftime ( " % Y- % m- %d % H: % M: % S " , time . strptime ( res [ 1 ] , " % Y % m %d % H % M % S " ) )
2010-02-11 12:37:41 +00:00
start = datetime . strptime ( real_date , " % Y- % m- %d % H: % M: % S " )
2013-11-12 08:18:57 +00:00
end = start + timedelta ( hours = with_date )
2010-02-11 12:37:41 +00:00
return ( int ( real_id ) , real_date , end . strftime ( " % Y- % m- %d % H: % M: % S " ) )
return int ( real_id )
2010-04-05 10:37:31 +00:00
2010-02-11 12:37:41 +00:00
return base_calendar_id and int ( base_calendar_id ) or base_calendar_id
2010-01-21 09:09:21 +00:00
2012-12-11 15:56:27 +00:00
def get_real_ids ( ids ) :
if isinstance ( ids , ( str , int , long ) ) :
return base_calendar_id2real_id ( ids )
if isinstance ( ids , ( list , tuple ) ) :
res = [ ]
for id in ids :
res . append ( base_calendar_id2real_id ( id ) )
return res
2010-02-11 12:37:41 +00:00
class calendar_attendee ( osv . osv ) :
2010-03-18 11:30:31 +00:00
"""
Calendar Attendee Information
"""
2010-02-11 12:37:41 +00:00
_name = ' calendar.attendee '
_description = ' Attendee information '
2013-12-09 14:08:19 +00:00
# def _get_address(self, name=None, email=None):
# """
# Gives email information in ical CAL-ADDRESS type format.
# @param name: name for CAL-ADDRESS value
# @param email: email address for CAL-ADDRESS value
# """
# if name and email:
# name += ':'
# return (name or '') + (email and ('MAILTO:' + email) or '')
2010-02-11 12:37:41 +00:00
2010-11-19 13:48:01 +00:00
def _compute_data ( self , cr , uid , ids , name , arg , context = None ) :
2010-03-18 11:30:31 +00:00
"""
2012-10-05 17:10:55 +00:00
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 ' }}
2010-03-18 11:30:31 +00:00
"""
2010-02-11 12:37:41 +00:00
name = name [ 0 ]
result = { }
for attdata in self . browse ( cr , uid , ids , context = context ) :
id = attdata . id
result [ id ] = { }
2013-11-08 16:05:49 +00:00
2010-02-11 12:37:41 +00:00
if name == ' cn ' :
2013-11-08 16:05:49 +00:00
if attdata . partner_id :
2012-03-05 09:30:39 +00:00
result [ id ] [ name ] = attdata . partner_id . name or False
2010-02-11 12:37:41 +00:00
else :
2010-05-13 11:37:59 +00:00
result [ id ] [ name ] = attdata . email or ' '
2013-11-08 16:05:49 +00:00
2010-02-11 12:37:41 +00:00
if name == ' event_date ' :
2013-12-09 14:08:19 +00:00
result [ id ] [ name ] = attdata . event_id . date
2010-02-11 12:37:41 +00:00
if name == ' event_end_date ' :
2013-12-09 14:08:19 +00:00
result [ id ] [ name ] = attdata . event_id . date_deadline
2010-02-11 12:37:41 +00:00
return result
2010-01-22 13:55:53 +00:00
2010-01-21 15:05:53 +00:00
_columns = {
2013-11-08 16:05:49 +00:00
' state ' : fields . selection ( [ ( ' needs-action ' , ' Needs Action ' ) , ( ' tentative ' , ' Uncertain ' ) , ( ' declined ' , ' Declined ' ) , ( ' accepted ' , ' Accepted ' ) ] , ' Status ' , readonly = True , help = " Status of the attendee ' s participation " ) ,
' cn ' : fields . function ( _compute_data , string = ' Common name ' , type = " char " , size = 124 , multi = ' cn ' , store = True ) ,
' dir ' : fields . char ( ' URI Reference ' , size = 124 , help = " Reference to the URI that points to the directory information corresponding to the attendee. " ) ,
2013-11-23 11:36:27 +00:00
' partner_id ' : fields . many2one ( ' res.partner ' , ' Contact ' , readonly = " True " ) ,
2010-04-29 13:50:23 +00:00
' email ' : fields . char ( ' Email ' , size = 124 , help = " Email of Invited Person " ) ,
2013-11-08 16:05:49 +00:00
' event_date ' : fields . function ( _compute_data , string = ' Event Date ' , type = " datetime " , multi = ' event_date ' ) ,
' event_end_date ' : fields . function ( _compute_data , string = ' Event End Date ' , type = " datetime " , multi = ' event_end_date ' ) ,
2010-04-29 13:50:23 +00:00
' availability ' : fields . selection ( [ ( ' free ' , ' Free ' ) , ( ' busy ' , ' Busy ' ) ] , ' Free/Busy ' , readonly = " True " ) ,
2013-11-08 16:05:49 +00:00
' access_token ' : fields . char ( ' Invitation Token ' , size = 256 ) ,
2013-12-09 14:08:19 +00:00
' event_id ' : fields . many2one ( ' crm.meeting ' , ' Meeting linked ' ) ,
2011-03-09 10:59:59 +00:00
}
2010-02-11 12:37:41 +00:00
_defaults = {
2013-11-15 16:59:05 +00:00
' state ' : ' needs-action ' ,
2010-01-21 15:05:53 +00:00
}
2010-07-13 11:17:53 +00:00
2010-06-24 12:55:03 +00:00
def copy ( self , cr , uid , id , default = None , context = None ) :
2011-09-18 13:53:10 +00:00
raise osv . except_osv ( _ ( ' Warning! ' ) , _ ( ' You cannot duplicate a calendar attendee. ' ) )
2012-11-30 06:00:20 +00:00
def onchange_partner_id ( self , cr , uid , ids , partner_id , context = None ) :
"""
2013-11-12 08:18:57 +00:00
Make entry on email and availability on change of partner_id field .
2012-11-30 06:00:20 +00:00
@param partner_id : changed value of partner id
2013-11-15 16:59:05 +00:00
"""
2012-11-30 06:00:20 +00:00
if not partner_id :
return { ' value ' : { ' email ' : ' ' } }
partner = self . pool . get ( ' res.partner ' ) . browse ( cr , uid , partner_id , context = context )
return { ' value ' : { ' email ' : partner . email } }
2010-04-30 12:39:39 +00:00
def get_ics_file ( self , cr , uid , event_obj , context = None ) :
"""
2012-10-05 17:10:55 +00:00
Returns iCalendar file for the event invitation .
@param event_obj : event object ( browse record )
2010-04-30 12:39:39 +00:00
@return : . ics file content
"""
res = None
def ics_datetime ( idate , short = False ) :
2010-09-20 11:49:32 +00:00
if idate :
2012-12-28 09:42:36 +00:00
#returns the datetime as UTC, because it is stored as it in the database
2013-11-25 08:50:18 +00:00
return datetime . strptime ( idate . split ( ' . ' ) [ 0 ] , ' % Y- % m- %d % H: % M: % S ' ) . replace ( tzinfo = pytz . timezone ( ' UTC ' ) )
#return datetime.strptime(idate, DEFAULT_SERVER_DATETIME_FORMAT).replace(tzinfo=pytz.timezone('UTC'))
2012-12-28 09:42:36 +00:00
return False
2013-11-15 16:59:05 +00:00
2010-04-30 12:39:39 +00:00
try :
2010-09-03 13:15:30 +00:00
# FIXME: why isn't this in CalDAV?
2010-04-30 12:39:39 +00:00
import vobject
except ImportError :
return res
2013-11-15 16:59:05 +00:00
2010-04-30 12:39:39 +00:00
cal = vobject . iCalendar ( )
2010-07-13 11:17:53 +00:00
event = cal . add ( ' vevent ' )
2010-12-31 12:18:35 +00:00
if not event_obj . date_deadline or not event_obj . date :
2012-08-07 11:34:14 +00:00
raise osv . except_osv ( _ ( ' Warning! ' ) , _ ( " First you have to specify the date of the invitation. " ) )
2010-04-30 12:39:39 +00:00
event . add ( ' created ' ) . value = ics_datetime ( time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) )
event . add ( ' dtstart ' ) . value = ics_datetime ( event_obj . date )
event . add ( ' dtend ' ) . value = ics_datetime ( event_obj . date_deadline )
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
2013-11-08 16:05:49 +00:00
2013-11-23 11:36:27 +00:00
if event_obj . alarm_ids :
for alarm in event_obj . alarm_ids :
# computes alarm data
valarm = event . add ( ' valarm ' )
# Compute trigger data
interval = alarm . interval
occurs = ' before '
duration = alarm . duration
trigger = valarm . add ( ' TRIGGER ' )
trigger . params [ ' related ' ] = [ " START " ]
if interval == ' days ' :
delta = timedelta ( days = duration )
elif interval == ' hours ' :
delta = timedelta ( hours = duration )
elif interval == ' minutes ' :
delta = timedelta ( minutes = duration )
trigger . value = delta
# Compute other details
valarm . add ( ' DESCRIPTION ' ) . value = alarm . name or ' OpenERP '
2011-02-09 09:18:48 +00:00
2010-04-30 12:39:39 +00:00
for attendee in event_obj . attendee_ids :
attendee_add = event . add ( ' attendee ' )
2010-05-27 10:10:34 +00:00
attendee_add . value = ' MAILTO: ' + ( attendee . email or ' ' )
2010-04-30 12:39:39 +00:00
res = cal . serialize ( )
return res
2010-07-13 11:17:53 +00:00
2013-11-26 18:01:06 +00:00
def _send_mail_to_attendees ( self , cr , uid , ids , email_from = tools . config . get ( ' email_from ' , False ) , template_xmlid = ' crm_email_template_meeting_invitation ' , context = None ) :
2010-03-18 11:30:31 +00:00
"""
2010-07-13 11:17:53 +00:00
Send mail for event invitation to event attendees .
2012-10-05 17:10:55 +00:00
@param email_from : email address for user sending the mail
2010-03-18 11:30:31 +00:00
"""
2013-11-23 11:36:27 +00:00
res = False
2013-07-05 07:34:36 +00:00
mail_id = [ ]
2013-08-16 12:47:41 +00:00
data_pool = self . pool . get ( ' ir.model.data ' )
mail_pool = self . pool . get ( ' mail.mail ' )
template_pool = self . pool . get ( ' email.template ' )
2013-08-02 08:56:07 +00:00
local_context = context . copy ( )
2013-07-12 11:51:22 +00:00
color = {
' needs-action ' : ' grey ' ,
' accepted ' : ' green ' ,
' tentative ' : ' #FFFF00 ' ,
2013-11-15 16:59:05 +00:00
' declined ' : ' red '
2013-08-16 12:47:41 +00:00
}
2013-11-15 16:59:05 +00:00
2013-11-24 14:31:01 +00:00
if not isinstance ( ids , ( tuple , list ) ) :
ids = [ ids ]
2013-12-09 14:08:19 +00:00
2013-11-23 11:36:27 +00:00
for attendee in self . browse ( cr , uid , ids , context = context ) :
2013-12-09 14:08:19 +00:00
dummy , template_id = data_pool . get_object_reference ( cr , uid , ' base_calendar ' , template_xmlid )
dummy , act_id = data_pool . get_object_reference ( cr , uid , ' base_calendar ' , " view_crm_meeting_calendar " )
body = template_pool . browse ( cr , uid , template_id , context = context ) . body_html
if attendee . email and email_from :
ics_file = self . get_ics_file ( cr , uid , attendee . event_id , context = context )
local_context [ ' att_obj ' ] = attendee
local_context [ ' color ' ] = color
local_context [ ' action_id ' ] = self . pool . get ( ' ir.actions.act_window ' ) . search ( cr , uid , [ ( ' view_id ' , ' = ' , act_id ) ] , context = context ) [ 0 ]
local_context [ ' dbname ' ] = cr . dbname
local_context [ ' base_url ' ] = self . pool . get ( ' ir.config_parameter ' ) . get_param ( cr , uid , ' web.base.url ' , default = ' http://localhost:8069 ' , context = context )
vals = template_pool . generate_email ( cr , uid , template_id , attendee . event_id . id , context = local_context )
2013-11-26 18:01:06 +00:00
2013-12-09 14:08:19 +00:00
if ics_file :
vals [ ' attachment_ids ' ] = [ ( 0 , 0 , { ' name ' : ' invitation.ics ' ,
' 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!
vals [ ' auto_delete ' ] = True #We don't need mail after it has been sended !
if ( vals [ ' email_to ' ] == attendee . partner_id . email ) :
vals [ ' email_to ' ] = ' '
vals [ ' recipient_ids ' ] = [ ( 4 , attendee . partner_id . id ) , ]
if not attendee . partner_id . opt_out :
mail_id . append ( mail_pool . create ( cr , uid , vals , context = context ) )
2013-11-23 11:36:27 +00:00
2013-11-01 09:19:41 +00:00
if mail_id :
2013-11-23 11:36:27 +00:00
try :
res = mail_pool . send ( cr , uid , mail_id , context = context )
except Exception as e :
print e
return res
2013-11-26 18:01:06 +00:00
2010-02-11 12:37:41 +00:00
def onchange_user_id ( self , cr , uid , ids , user_id , * args , * * argv ) :
2010-03-18 11:30:31 +00:00
"""
2010-04-06 07:28:49 +00:00
Make entry on email and availbility on change of user_id field .
2013-11-15 16:59:05 +00:00
@param ids : list of attendee ' s IDs
2012-10-05 17:10:55 +00:00
@param user_id : changed value of User id
@return : dictionary of values which put value in email and availability fields
2010-03-18 11:30:31 +00:00
"""
2010-02-11 12:37:41 +00:00
if not user_id :
return { ' value ' : { ' email ' : ' ' } }
2013-11-15 16:59:05 +00:00
usr_obj = self . pool . get ( ' res.users ' ) . browse ( cr , uid , user_id , * args )
2012-08-10 10:22:57 +00:00
return { ' value ' : { ' email ' : user . email , ' availability ' : user . availability } }
2010-01-25 12:57:21 +00:00
2010-02-11 12:37:41 +00:00
def do_tentative ( self , cr , uid , ids , context = None , * args ) :
2012-10-05 17:10:55 +00:00
"""
Makes event invitation as Tentative .
2013-11-15 16:59:05 +00:00
@param ids : list of attendee ' s IDs
2010-05-14 10:14:26 +00:00
"""
2010-07-02 07:34:06 +00:00
return self . write ( cr , uid , ids , { ' state ' : ' tentative ' } , context )
2010-02-11 12:37:41 +00:00
def do_accept ( self , cr , uid , ids , context = None , * args ) :
2010-03-18 11:30:31 +00:00
"""
2013-02-26 06:52:39 +00:00
Marks event invitation as Accepted .
2013-11-15 16:59:05 +00:00
@param ids : list of attendee ' s IDs
2010-03-18 11:30:31 +00:00
"""
2010-10-21 06:50:03 +00:00
if context is None :
2010-03-18 11:30:31 +00:00
context = { }
2013-06-27 10:42:06 +00:00
meeting_obj = self . pool . get ( ' crm.meeting ' )
2013-10-10 13:21:00 +00:00
res = self . write ( cr , uid , ids , { ' state ' : ' accepted ' } , context )
2013-11-15 16:59:05 +00:00
for attendee in self . browse ( cr , uid , ids , context = context ) :
2013-11-26 18:01:06 +00:00
if attendee . ref :
2013-12-09 14:08:19 +00:00
meeting_obj . message_post ( cr , uid , attendee . event_id . id , body = _ ( ( " %s has accepted invitation " ) % ( attendee . cn ) ) , subtype = " base_calendar.subtype_invitation " , context = context )
2013-11-26 11:45:02 +00:00
2013-10-10 13:21:00 +00:00
return res
2013-11-15 16:59:05 +00:00
2010-02-11 12:37:41 +00:00
def do_decline ( self , cr , uid , ids , context = None , * args ) :
2012-10-05 17:10:55 +00:00
"""
Marks event invitation as Declined .
@param ids : list of calendar attendee ' s IDs
"""
2010-10-21 06:50:03 +00:00
if context is None :
2010-07-13 11:17:53 +00:00
context = { }
2013-07-05 07:34:36 +00:00
meeting_obj = self . pool . get ( ' crm.meeting ' )
2013-10-10 13:21:00 +00:00
res = self . write ( cr , uid , ids , { ' state ' : ' declined ' } , context )
2013-11-26 18:01:06 +00:00
for attendee in self . browse ( cr , uid , ids , context = context ) :
2013-12-09 14:08:19 +00:00
meeting_obj . message_post ( cr , uid , attendee . event_id . id , body = _ ( ( " %s has declined invitation " ) % ( attendee . cn ) ) , subtype = " base_calendar.subtype_invitation " , context = context )
2013-10-11 05:17:16 +00:00
return res
2010-02-11 12:37:41 +00:00
2010-03-18 06:31:52 +00:00
def create ( self , cr , uid , vals , context = None ) :
2010-10-21 06:50:03 +00:00
if context is None :
2010-03-18 06:31:52 +00:00
context = { }
2010-02-11 12:37:41 +00:00
if not vals . get ( " email " ) and vals . get ( " cn " ) :
cnval = vals . get ( " cn " ) . split ( ' : ' )
2010-04-06 07:28:49 +00:00
email = filter ( lambda x : x . __contains__ ( ' @ ' ) , cnval )
2010-07-01 06:05:16 +00:00
vals [ ' email ' ] = email and email [ 0 ] or ' '
2010-02-11 12:37:41 +00:00
vals [ ' cn ' ] = vals . get ( " cn " )
2012-12-28 09:42:36 +00:00
res = super ( calendar_attendee , self ) . create ( cr , uid , vals , context = context )
2010-02-11 12:37:41 +00:00
return res
2012-10-05 11:49:19 +00:00
2013-11-08 16:05:49 +00:00
class res_partner ( osv . osv ) :
2013-10-22 05:17:55 +00:00
_inherit = ' res.partner '
2013-11-23 11:36:27 +00:00
_columns = {
' cal_last_notif ' : fields . datetime ( ' Last Notification from base Calendar ' ) ,
}
2013-10-22 05:17:55 +00:00
def get_attendee_detail ( self , cr , uid , ids , meeting_id , context = None ) :
datas = [ ]
meeting = False
if meeting_id :
meeting = self . pool . get ( ' crm.meeting ' ) . browse ( cr , uid , get_real_ids ( meeting_id ) , context )
for partner in self . browse ( cr , uid , ids , context = context ) :
data = self . name_get ( cr , uid , [ partner . id ] , context ) [ 0 ]
if meeting :
for attendee in meeting . attendee_ids :
if attendee . partner_id . id == partner . id :
data = ( data [ 0 ] , data [ 1 ] , attendee . state )
datas . append ( data )
return datas
2013-11-23 11:36:27 +00:00
def update_cal_last_event ( self , cr , uid , context = None ) :
partner = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , context = context ) . partner_id ;
self . write ( cr , uid , partner . id , { ' cal_last_notif ' : datetime . now ( ) } , context = context )
return " OK "
2013-12-02 14:52:42 +00:00
2013-11-23 11:36:27 +00:00
class calendar_alarm_manager ( osv . osv ) :
_name = ' calendar.alarm_manager '
def get_next_potential_limit_alarm ( self , cr , uid , seconds , notif = True , mail = True , partner_id = None , context = None ) :
res = { }
base_request = """
SELECT
crm . id ,
crm . date - interval ' 1 ' minute * calcul_delta . max_delta AS first_alarm ,
CASE
WHEN crm . recurrency THEN crm . end_date - interval ' 1 ' minute * calcul_delta . min_delta
ELSE crm . date_deadline - interval ' 1 ' minute * calcul_delta . min_delta
END as last_alarm ,
crm . date as first_event_date ,
CASE
WHEN crm . recurrency THEN crm . end_date
ELSE crm . date_deadline
END as last_event_date ,
calcul_delta . min_delta ,
calcul_delta . max_delta ,
crm . rrule
FROM
crm_meeting AS crm
RIGHT JOIN
(
SELECT
rel . crm_meeting_id , max ( alarm . duration_minutes ) AS max_delta , min ( alarm . duration_minutes ) AS min_delta
FROM
calendar_alarm_crm_meeting_rel AS rel
LEFT JOIN calendar_alarm AS alarm ON alarm . id = rel . calendar_alarm_id
WHERE alarm . type in % s
GROUP BY rel . crm_meeting_id
) AS calcul_delta ON calcul_delta . crm_meeting_id = crm . id
"""
filter_user = """
LEFT JOIN crm_meeting_res_partner_rel AS part_rel ON part_rel . crm_meeting_id = crm . id
AND part_rel . res_partner_id = % s
2010-03-25 12:07:00 +00:00
"""
2013-11-23 11:36:27 +00:00
#Add filter on type
type_to_read = ( ) #('dummy',)
if notif :
type_to_read + = ( ' notification ' , )
if mail :
type_to_read + = ( ' email ' , )
tuple_params = ( type_to_read , )
#ADD FILTER ON PARTNER_ID
if partner_id :
base_request + = filter_user
tuple_params + = ( partner_id , )
2010-07-02 13:30:13 +00:00
2013-11-23 11:36:27 +00:00
#Add filter on hours
tuple_params + = ( seconds , seconds , )
cr . execute ( """
SELECT
*
FROM (
"""
+ base_request
+ """
) AS ALL_EVENTS
WHERE
ALL_EVENTS . first_alarm < ( now ( ) at time zone ' utc ' + interval ' %s ' second )
AND ALL_EVENTS . last_alarm > ( now ( ) at time zone ' utc ' - interval ' %s ' second )
""" ,tuple_params)
for event_id , first_alarm , last_alarm , first_meeting , last_meeting , min_duration , max_duration , rrule in cr . fetchall ( ) :
res [ event_id ] = { }
res [ event_id ] [ ' event_id ' ] = event_id
res [ event_id ] [ ' first_alarm ' ] = first_alarm
res [ event_id ] [ ' last_alarm ' ] = last_alarm
res [ event_id ] [ ' first_meeting ' ] = first_meeting
res [ event_id ] [ ' last_meeting ' ] = last_meeting
res [ event_id ] [ ' min_duration ' ] = min_duration
res [ event_id ] [ ' max_duration ' ] = max_duration
res [ event_id ] [ ' rrule ' ] = rrule
2013-12-09 14:08:19 +00:00
2013-11-23 11:36:27 +00:00
return res
def do_check_alarm_for_one_date ( self , cr , uid , one_date , event , event_maxdelta , in_the_next_X_seconds , after = False , notif = True , mail = True , context = None ) :
res = [ ]
alarm_type = [ ]
if notif :
alarm_type . append ( ' notification ' )
if mail :
alarm_type . append ( ' email ' )
if one_date - timedelta ( minutes = event_maxdelta ) < datetime . now ( ) + timedelta ( seconds = in_the_next_X_seconds ) : #if an alarm is possible for this date
print " ALARMIDS = " , event . alarm_ids
for alarm in event . alarm_ids :
print " type = " , alarm . type
print " after = " , after
print " cond 0 = " , alarm . type in alarm_type
print " cond 1 = " , one_date - timedelta ( minutes = alarm . duration_minutes ) , " < " , datetime . now ( ) + timedelta ( seconds = in_the_next_X_seconds )
#print "cond 2", one_date - timedelta(minutes=alarm.duration_minutes), " > ",datetime.strptime(after.split('.')[0], "%Y-%m-%d %H:%M:%S")
2013-11-26 18:01:06 +00:00
2013-11-23 11:36:27 +00:00
if alarm . type in alarm_type and \
one_date - timedelta ( minutes = alarm . duration_minutes ) < datetime . now ( ) + timedelta ( seconds = in_the_next_X_seconds ) and \
( not after or one_date - timedelta ( minutes = alarm . duration_minutes ) > datetime . strptime ( after . split ( ' . ' ) [ 0 ] , " % Y- % m- %d % H: % M: % S " ) ) :
alert = {
' alarm_id ' : alarm . id ,
' event_id ' : event . id ,
' notify_at ' : one_date - timedelta ( minutes = alarm . duration_minutes ) ,
}
print " ALERT ADDED : " , alert
res . append ( alert )
else :
print " Not in condition... "
return res
def do_run_scheduler_mail ( self , cr , uid , context = None ) :
cron = self . pool . get ( ' ir.cron ' ) . search ( cr , uid , [ ( ' model ' , ' ilike ' , self . _name ) ] , context = context )
if cron and len ( cron ) == 1 :
cron = self . pool . get ( ' ir.cron ' ) . browse ( cr , uid , cron [ 0 ] , context = context )
else :
raise ( " Cron for " + self . _name + " not identified :( ! " )
if cron . interval_type == " weeks " :
cron_interval = cron . interval_number * 7 * 24 * 60 * 60
elif cron . interval_type == " days " :
cron_interval = cron . interval_number * 24 * 60 * 60
elif cron . interval_type == " hours " :
cron_interval = cron . interval_number * 60 * 60
elif cron . interval_type == " minutes " :
cron_interval = cron . interval_number * 60
elif cron . interval_type == " seconds " :
cron_interval = cron . interval_number
if not cron_interval :
raise ( " Cron delay for " + self . _name + " not calculated :( ! " )
2013-12-09 14:08:19 +00:00
2013-11-23 11:36:27 +00:00
all_events = self . get_next_potential_limit_alarm ( cr , uid , cron_interval , notif = False , context = context )
for event in all_events : #.values()
max_delta = all_events [ event ] [ ' max_duration ' ] ;
curEvent = self . pool . get ( ' crm.meeting ' ) . browse ( cr , uid , event , context = context )
if curEvent . recurrency :
bFound = False
LastFound = False
2013-12-09 14:08:19 +00:00
for one_date in self . pool . get ( ' crm.meeting ' ) . get_recurrent_date_by_event ( cr , uid , curEvent , context = context ) :
2013-11-23 11:36:27 +00:00
in_date_format = datetime . strptime ( one_date , ' % Y- % m- %d % H: % M: % S ' ) ;
LastFound = self . do_check_alarm_for_one_date ( cr , uid , in_date_format , curEvent , max_delta , cron_interval , notif = False , context = context )
if LastFound :
for alert in LastFound :
self . do_mail_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 precendent event had alarm but not this one, we can stop the search fot this event
break
2010-07-02 13:30:13 +00:00
else :
2013-11-23 11:36:27 +00:00
in_date_format = datetime . strptime ( curEvent . date , ' % Y- % m- %d % H: % M: % S ' ) ;
LastFound = self . do_check_alarm_for_one_date ( cr , uid , in_date_format , curEvent , max_delta , cron_interval , notif = False , context = context )
if LastFound :
for alert in LastFound :
self . do_mail_reminder ( cr , uid , alert , context = context )
#Purge all done
def get_next_event ( self , cr , uid , context = None ) :
ajax_check_every_seconds = 300
partner = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , context = context ) . partner_id ;
2013-12-09 14:08:19 +00:00
2013-11-23 11:36:27 +00:00
all_notif = [ ]
all_events = self . get_next_potential_limit_alarm ( cr , uid , ajax_check_every_seconds , partner_id = partner . id , mail = False , context = context )
print all_events
for event in all_events : #.values()
max_delta = all_events [ event ] [ ' max_duration ' ] ;
curEvent = self . pool . get ( ' crm.meeting ' ) . browse ( cr , uid , event , context = context )
if curEvent . recurrency :
bFound = False
LastFound = False
2013-12-09 14:08:19 +00:00
for one_date in self . pool . get ( " crm.meeting " ) . get_recurrent_date_by_event ( cr , uid , curEvent , context = context ) :
2013-11-23 11:36:27 +00:00
in_date_format = datetime . strptime ( one_date , ' % Y- % m- %d % H: % M: % S ' ) ;
LastFound = self . do_check_alarm_for_one_date ( cr , uid , in_date_format , curEvent , max_delta , ajax_check_every_seconds , after = partner . cal_last_notif , mail = False , 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 precendent event had alarm but not this one, we can stop the search fot this event
break
2010-07-02 13:30:13 +00:00
else :
2013-11-23 11:36:27 +00:00
in_date_format = datetime . strptime ( curEvent . date , ' % Y- % m- %d % H: % M: % S ' ) ;
LastFound = self . do_check_alarm_for_one_date ( cr , uid , in_date_format , curEvent , max_delta , ajax_check_every_seconds , partner . cal_last_notif , mail = False , context = context )
if LastFound :
for alert in LastFound :
all_notif . append ( self . do_notif_reminder ( cr , uid , alert , context = context ) )
return all_notif
def do_mail_reminder ( self , cr , uid , alert , context = None ) :
if context is None :
context = { }
2013-11-27 12:33:29 +00:00
res = False
2013-11-23 11:36:27 +00:00
event = self . pool . get ( " crm.meeting " ) . browse ( cr , uid , alert [ ' event_id ' ] , context = context )
alarm = self . pool . get ( " calendar.alarm " ) . browse ( cr , uid , alert [ ' alarm_id ' ] , context = context )
if alarm . type == ' email ' :
2013-11-27 12:33:29 +00:00
mail_ids = [ ]
2013-11-23 11:36:27 +00:00
data_pool = self . pool . get ( ' ir.model.data ' )
2013-11-27 12:33:29 +00:00
mail_pool = self . pool . get ( ' mail.mail ' )
template_pool = self . pool . get ( ' email.template ' )
local_context = context and context . copy ( ) or { }
color = {
' needs-action ' : ' grey ' ,
' accepted ' : ' green ' ,
' tentative ' : ' #FFFF00 ' ,
' declined ' : ' red '
}
2013-11-23 11:36:27 +00:00
for attendee in event . attendee_ids :
2013-11-27 12:33:29 +00:00
dummy , template_id = data_pool . get_object_reference ( cr , uid , ' base_calendar ' , ' crm_email_template_meeting_reminder ' )
2013-11-23 11:36:27 +00:00
dummy , act_id = data_pool . get_object_reference ( cr , uid , ' base_calendar ' , " view_crm_meeting_calendar " )
body = template_pool . browse ( cr , uid , template_id , context = context ) . body_html
2013-11-27 12:33:29 +00:00
#mail_from = tools.config.get('email_from',event.user_id.email)
if attendee . email :
2013-11-23 11:36:27 +00:00
local_context [ ' att_obj ' ] = attendee
2013-11-27 12:33:29 +00:00
local_context [ ' color ' ] = color
2013-11-23 11:36:27 +00:00
local_context [ ' action_id ' ] = self . pool . get ( ' ir.actions.act_window ' ) . search ( cr , uid , [ ( ' view_id ' , ' = ' , act_id ) ] , context = context ) [ 0 ]
local_context [ ' dbname ' ] = cr . dbname
local_context [ ' base_url ' ] = self . pool . get ( ' ir.config_parameter ' ) . get_param ( cr , uid , ' web.base.url ' , default = ' http://localhost:8069 ' , context = context )
2013-12-09 14:08:19 +00:00
vals = template_pool . generate_email ( cr , uid , template_id , attendee . event_id . id , context = local_context )
2013-11-27 12:33:29 +00:00
2013-11-23 11:36:27 +00:00
vals [ ' model ' ] = None #We don't want to have the mail in the tchatter while in queue!
vals [ ' auto_delete ' ] = True #We don't need mail after it has been sended !
2013-11-27 12:33:29 +00:00
if ( vals [ ' email_to ' ] == attendee . partner_id . email ) :
vals [ ' email_to ' ] = ' '
vals [ ' recipient_ids ' ] = [ ( 4 , attendee . partner_id . id ) , ]
if not attendee . partner_id . opt_out :
mail_ids . append ( mail_pool . create ( cr , uid , vals , context = local_context ) )
if mail_ids :
try :
res = mail_pool . send ( cr , uid , mail_ids , context = local_context )
print " REMINDER SENDED ... EMAIL : " , mail_ids
except Exception as e :
print e
2013-11-23 11:36:27 +00:00
else :
print " SHOULD BE AN MAIL ALARM :( FOR EVENT %s / ALARM %s " % ( alert [ ' event_id ' ] , alert [ ' alarm_id ' ] )
2013-11-27 12:33:29 +00:00
return res
2010-01-21 08:14:58 +00:00
2013-11-23 11:36:27 +00:00
def do_notif_reminder ( self , cr , uid , alert , context = None ) :
alarm = self . pool . get ( " calendar.alarm " ) . browse ( cr , uid , alert [ ' alarm_id ' ] , context = context )
event = self . pool . get ( " crm.meeting " ) . browse ( cr , uid , alert [ ' event_id ' ] , context = context )
if alarm . type == ' notification ' :
mail_id = [ ]
mail_pool = self . pool . get ( ' mail.mail ' )
data_pool = self . pool . get ( ' ir.model.data ' )
template_pool = self . pool . get ( ' email.template ' )
local_context = context . copy ( )
message = event . display_time
delta = alert [ ' notify_at ' ] - datetime . now ( )
delta = delta . seconds + delta . days * 3600 * 24
return {
' event_id ' : event . id ,
' title ' : event . name ,
' message ' : message ,
' timer ' : delta , #Now - event_date - alaram.duration_minute
' notify_at ' : alert [ ' notify_at ' ] . strftime ( " % Y- % m- %d % H: % M: % S " ) , #Now - event_date - alaram.duration_minute
}
else :
print " SHOULD BE AN NOTIF ALARM :( FOR EVENT %s / ALARM %s " % ( alert [ ' event_id ' ] , alert [ ' alarm_id ' ] )
2013-11-15 16:59:05 +00:00
2013-11-23 11:36:27 +00:00
2013-11-08 16:05:49 +00:00
class calendar_alarm ( osv . osv ) :
_name = ' calendar.alarm '
_description = ' Event alarm '
2011-12-11 20:12:37 +00:00
2013-11-23 11:36:27 +00:00
def _get_duration ( self , cr , uid , ids , field_name , arg , context = None ) :
res = { }
for alarm in self . browse ( cr , uid , ids , context = context ) :
if alarm . interval == " minutes " :
res [ alarm . id ] = alarm . duration
elif alarm . interval == " hours " :
res [ alarm . id ] = alarm . duration * 60
elif alarm . interval == " days " :
res [ alarm . id ] = alarm . duration * 60 * 24
else :
res [ alarm . id ] = 0
return res
2010-01-21 08:14:58 +00:00
_columns = {
2013-11-08 16:05:49 +00:00
' name ' : fields . char ( ' Name ' , size = 256 , required = True ) , # fields function
' type ' : fields . selection ( [ ( ' notification ' , ' Notification ' ) , ( ' email ' , ' Email ' ) ] , ' Type ' , required = True ) ,
' duration ' : fields . integer ( ' Amount ' , required = True ) ,
' interval ' : fields . selection ( [ ( ' minutes ' , ' Minutes ' ) , ( ' hours ' , ' Hours ' ) , ( ' days ' , ' Days ' ) ] , ' Unit ' , required = True ) ,
2013-11-23 11:36:27 +00:00
' duration_minutes ' : fields . function ( _get_duration , type = ' integer ' , string = ' duration_minutes ' , store = True ) ,
2013-11-08 16:05:49 +00:00
}
2013-11-23 11:36:27 +00:00
2010-01-21 12:58:40 +00:00
_defaults = {
2013-11-08 16:05:49 +00:00
' type ' : ' notification ' ,
' duration ' : 1 ,
' interval ' : ' hours ' ,
2010-07-13 11:17:53 +00:00
}
2013-11-23 11:36:27 +00:00
2010-02-11 12:37:41 +00:00
class ir_values ( osv . osv ) :
_inherit = ' ir.values '
2013-11-08 16:05:49 +00:00
def set ( self , cr , uid , key , key2 , name , models , value , replace = True , isobject = False , meta = False , preserve_user = False , company = False ) :
2010-02-11 12:37:41 +00:00
new_model = [ ]
for data in models :
if type ( data ) in ( list , tuple ) :
new_model . append ( ( data [ 0 ] , base_calendar_id2real_id ( data [ 1 ] ) ) )
2009-12-15 13:43:55 +00:00
else :
2010-02-11 12:37:41 +00:00
new_model . append ( data )
2010-03-18 11:30:31 +00:00
return super ( ir_values , self ) . set ( cr , uid , key , key2 , name , new_model , \
2010-02-11 12:37:41 +00:00
value , replace , isobject , meta , preserve_user , company )
2009-12-17 06:26:30 +00:00
2013-11-08 16:05:49 +00:00
def get ( self , cr , uid , key , key2 , models , meta = False , context = None , res_id_req = False , without_user = True , key2_req = True ) :
2010-10-21 06:50:03 +00:00
if context is None :
2010-05-14 10:14:26 +00:00
context = { }
2010-02-11 12:37:41 +00:00
new_model = [ ]
for data in models :
if type ( data ) in ( list , tuple ) :
new_model . append ( ( data [ 0 ] , base_calendar_id2real_id ( data [ 1 ] ) ) )
2009-12-14 11:07:43 +00:00
else :
2010-02-11 12:37:41 +00:00
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 )
2013-11-12 08:18:57 +00:00
2010-02-11 12:37:41 +00:00
class ir_model ( osv . osv ) :
2009-12-18 13:44:31 +00:00
2010-02-11 12:37:41 +00:00
_inherit = ' ir.model '
2013-11-12 08:18:57 +00:00
def read ( self , cr , uid , ids , fields = None , context = None , load = ' _classic_read ' ) :
2013-11-08 16:05:49 +00:00
2010-05-26 12:15:25 +00:00
new_ids = isinstance ( ids , ( str , int , long ) ) and [ ids ] or ids
2010-10-21 06:50:03 +00:00
if context is None :
2010-05-14 10:14:26 +00:00
context = { }
2010-05-26 12:15:25 +00:00
data = super ( ir_model , self ) . read ( cr , uid , new_ids , fields = fields , \
2010-02-11 12:37:41 +00:00
context = context , load = load )
if data :
for val in data :
val [ ' id ' ] = base_calendar_id2real_id ( val [ ' id ' ] )
2010-05-19 12:22:19 +00:00
return isinstance ( ids , ( str , int , long ) ) and data [ 0 ] or data
2010-02-11 12:37:41 +00:00
2013-01-30 15:55:01 +00:00
original_exp_report = openerp . service . report . exp_report
2010-02-11 12:37:41 +00:00
2013-01-30 15:55:01 +00:00
def exp_report ( db , uid , object , ids , data = None , context = None ) :
"""
Export Report
"""
if object == ' printscreen.list ' :
original_exp_report ( db , uid , object , ids , data , context )
new_ids = [ ]
for id in ids :
new_ids . append ( base_calendar_id2real_id ( id ) )
if data . get ( ' id ' , False ) :
data [ ' id ' ] = base_calendar_id2real_id ( data [ ' id ' ] )
return original_exp_report ( db , uid , object , new_ids , data , context )
2010-02-11 12:37:41 +00:00
2013-01-30 15:55:01 +00:00
openerp . service . report . exp_report = exp_report
2010-02-11 12:37:41 +00:00
2013-11-08 16:05:49 +00:00
2013-11-23 11:36:27 +00:00
class crm_meeting_type ( osv . Model ) :
_name = ' crm.meeting.type '
_description = ' Meeting Type '
_columns = {
' name ' : fields . char ( ' Name ' , size = 64 , required = True , translate = True ) ,
}
2013-12-09 14:08:19 +00:00
2013-11-23 11:36:27 +00:00
class crm_meeting ( osv . Model ) :
""" Model for CRM meetings """
_name = ' crm.meeting '
_description = " Meeting "
_order = " id desc "
_inherit = [ " mail.thread " , " ir.needaction_mixin " ]
def do_run_scheduler ( self , cr , uid , id , context = None ) :
self . pool . get ( ' calendar.alarm_manager ' ) . do_run_scheduler ( cr , uid , context = context )
2013-12-09 14:08:19 +00:00
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
"""
def todate ( date ) :
val = parser . parse ( ' ' . join ( ( re . compile ( ' \ d ' ) ) . findall ( date ) ) )
## Dates are localized to saved timezone if any, else current timezone.
if not val . tzinfo :
val = pytz . UTC . localize ( val )
return val . astimezone ( timezone )
timezone = pytz . timezone ( event . vtimezone or context . get ( ' tz ' ) or ' UTC ' )
startdate = pytz . UTC . localize ( datetime . strptime ( event . date , " % Y- % m- %d % H: % M: % S " ) ) #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.
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 ) )
#rset1.rdate(pytz.UTC.localize(datetime.strptime(ev.date, "%Y-%m-%d %H:%M:%S")))
return [ d . astimezone ( pytz . UTC ) for d in rset1 ]
2013-11-23 11:36:27 +00:00
def _get_recurrency_end_date ( self , data , context = None ) :
if data . get ( ' recurrency ' ) and data . get ( ' end_type ' ) in ( ' count ' , unicode ( ' count ' ) ) :
data_date_deadline = datetime . strptime ( data . get ( ' date_deadline ' ) , ' % Y- % m- %d % H: % M: % S ' )
if data . get ( ' rrule_type ' ) in ( ' daily ' , unicode ( ' count ' ) ) :
rel_date = relativedelta ( days = data . get ( ' count ' ) + 1 )
elif data . get ( ' rrule_type ' ) in ( ' weekly ' , unicode ( ' weekly ' ) ) :
rel_date = relativedelta ( days = ( data . get ( ' count ' ) + 1 ) * 7 )
elif data . get ( ' rrule_type ' ) in ( ' monthly ' , unicode ( ' monthly ' ) ) :
rel_date = relativedelta ( months = data . get ( ' count ' ) + 1 )
elif data . get ( ' rrule_type ' ) in ( ' yearly ' , unicode ( ' yearly ' ) ) :
rel_date = relativedelta ( years = data . get ( ' count ' ) + 1 )
end_date = data_date_deadline + rel_date
else :
end_date = data . get ( ' end_date ' )
return end_date
def _find_my_attendee ( self , cr , uid , meeting_ids , context = None ) :
"""
Return the first attendee where the user connected has been invited from all the meeting_ids in parameters
"""
user = self . pool . get ( ' 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
return False
def _get_display_time ( self , cr , uid , meeting_id , context = None ) :
"""
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
"""
if context is None :
context = { }
tz = context . get ( ' tz ' , False )
if not tz : #tz can have a value False, so dont do it in the default value of get !
tz = pytz . timezone ( ' UTC ' )
meeting = self . browse ( cr , uid , meeting_id , context = context )
date = fields . datetime . context_timestamp ( cr , uid , datetime . strptime ( meeting . date , tools . DEFAULT_SERVER_DATETIME_FORMAT ) , context = context )
date_deadline = fields . datetime . context_timestamp ( cr , uid , datetime . strptime ( meeting . date_deadline , tools . DEFAULT_SERVER_DATETIME_FORMAT ) , context = context )
event_date = date . strftime ( ' % B- %d - % Y ' )
display_time = date . strftime ( ' % H- % M ' )
if meeting . allday :
time = _ ( " AllDay , %s " ) % ( event_date )
elif meeting . duration < 24 :
duration = date + timedelta ( hours = meeting . duration )
time = ( " %s at ( %s To %s ) ( %s ) " ) % ( event_date , display_time , duration . strftime ( ' % H- % M ' ) , tz )
else :
time = ( " %s at %s To \n %s at %s ( %s ) " ) % ( event_date , display_time , date_deadline . strftime ( ' % B- %d - % Y ' ) , date_deadline . strftime ( ' % H- % M ' ) , tz )
return time
def _compute ( self , cr , uid , ids , fields , arg , context = None ) :
res = { }
for meeting_id in ids :
res [ meeting_id ] = { }
attendee = self . _find_my_attendee ( cr , uid , [ meeting_id ] , context )
for field in fields :
if field == ' is_attendee ' :
res [ meeting_id ] [ field ] = True if attendee else False
elif field == ' attendee_status ' :
res [ meeting_id ] [ field ] = attendee . state if attendee else ' needs-action '
elif field == ' display_time ' :
res [ meeting_id ] [ field ] = self . _get_display_time ( cr , uid , meeting_id , context = context )
return res
def _get_rulestring ( self , cr , uid , ids , name , arg , context = None ) :
"""
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 ]
for id in ids :
#read these fields as SUPERUSER because if the record is private a normal search could return False and raise an error
data = self . browse ( cr , SUPERUSER_ID , id , context = context )
2013-11-26 18:01:06 +00:00
if data . interval and data . interval < 0 :
2013-11-23 11:36:27 +00:00
raise osv . except_osv ( _ ( ' Warning! ' ) , _ ( ' Interval cannot be negative. ' ) )
2013-11-26 18:01:06 +00:00
if data . count and data . count < = 0 :
2013-11-23 11:36:27 +00:00
raise osv . except_osv ( _ ( ' Warning! ' ) , _ ( ' Count cannot be negative or 0. ' ) )
data = self . read ( cr , uid , id , [ ' id ' , ' byday ' , ' recurrency ' , ' month_list ' , ' end_date ' , ' rrule_type ' , ' month_by ' , ' interval ' , ' count ' , ' end_type ' , ' mo ' , ' tu ' , ' we ' , ' th ' , ' fr ' , ' sa ' , ' su ' , ' day ' , ' week_list ' ] , context = context )
event = data [ ' id ' ]
if data [ ' recurrency ' ] :
result [ event ] = self . compute_rule_string ( data )
else :
result [ event ] = " "
return result
2013-12-09 14:08:19 +00:00
def _rrule_write ( self , cr , uid , ids , field_name , field_value , args , context = None ) :
if not isinstance ( ids , list ) :
ids = [ ids ]
2013-11-23 11:36:27 +00:00
data = self . _get_empty_rrule_data ( )
if field_value :
2013-12-09 14:08:19 +00:00
2013-11-23 11:36:27 +00:00
data [ ' recurrency ' ] = True
for event in self . browse ( cr , uid , ids , context = context ) :
2013-12-09 14:08:19 +00:00
rdate = event . date
2013-11-23 11:36:27 +00:00
update_data = self . _parse_rrule ( field_value , dict ( data ) , rdate )
2013-12-09 14:08:19 +00:00
print ' UPDATE_DATA = ' , update_data
2013-11-23 11:36:27 +00:00
data . update ( update_data )
self . write ( cr , uid , ids , data , context = context )
return True
def _tz_get ( self , cr , uid , context = None ) :
return [ ( x . lower ( ) , x ) for x in pytz . all_timezones ]
2013-11-24 13:02:41 +00:00
_track = {
' location ' : {
2013-11-26 11:45:02 +00:00
' base_calendar.subtype_invitation ' : lambda self , cr , uid , obj , ctx = None : True ,
} ,
' date ' : {
' base_calendar.subtype_invitation ' : lambda self , cr , uid , obj , ctx = None : True ,
2013-11-24 13:02:41 +00:00
} ,
}
2013-11-23 11:36:27 +00:00
_columns = {
' create_date ' : fields . datetime ( ' Creation Date ' , readonly = True ) ,
' write_date ' : fields . datetime ( ' Write Date ' , readonly = True ) ,
' state ' : fields . selection ( [ ( ' draft ' , ' Unconfirmed ' ) , ( ' open ' , ' Confirmed ' ) ] , string = ' Status ' , size = 16 , readonly = True , track_visibility = ' onchange ' ) ,
# Meeting fields
' name ' : fields . char ( ' Meeting Subject ' , size = 128 , 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 " , multi = ' attendee ' ) ,
' display_time ' : fields . function ( _compute , string = ' Event Time ' , type = " char " , multi = ' attendee ' ) ,
# ---------------------
# OLD CALENDAR_EVENT
# ---------------------
' id ' : fields . integer ( ' ID ' , readonly = True ) ,
' sequence ' : fields . integer ( ' Sequence ' ) ,
2013-11-26 11:45:02 +00:00
' date ' : fields . datetime ( ' Date ' , states = { ' done ' : [ ( ' readonly ' , True ) ] } , required = True , track_visibility = ' onchange ' ) ,
2013-11-23 11:36:27 +00:00
' date_deadline ' : fields . datetime ( ' End Date ' , states = { ' done ' : [ ( ' readonly ' , True ) ] } , required = True , ) ,
' duration ' : fields . float ( ' Duration ' , states = { ' done ' : [ ( ' readonly ' , True ) ] } ) ,
' description ' : fields . text ( ' Description ' , states = { ' done ' : [ ( ' readonly ' , True ) ] } ) ,
' class ' : fields . selection ( [ ( ' public ' , ' Public ' ) , ( ' private ' , ' Private ' ) , ( ' confidential ' , ' Public for Employees ' ) ] , ' Privacy ' , states = { ' done ' : [ ( ' readonly ' , True ) ] } ) ,
2013-11-24 13:02:41 +00:00
' location ' : fields . char ( ' Location ' , size = 264 , help = " Location of Event " , track_visibility = ' onchange ' , states = { ' done ' : [ ( ' readonly ' , True ) ] } ) ,
2013-11-23 11:36:27 +00:00
' show_as ' : fields . selection ( [ ( ' free ' , ' Free ' ) , ( ' busy ' , ' Busy ' ) ] , ' Show Time as ' , states = { ' done ' : [ ( ' readonly ' , True ) ] } ) ,
#'state': fields.selection([('tentative', 'Uncertain'),('cancelled', 'Cancelled'),('confirmed', 'Confirmed'),],'Status', readonly=True, track_visibility='onchange'),
#FIELD FOR RECURRENCY
2013-12-09 14:08:19 +00:00
#'exdate': fields.text('Exception Date/Times', help="This property defines the list of date/time exceptions for a recurring calendar component."),
2013-11-23 11:36:27 +00:00
' rrule ' : fields . function ( _get_rulestring , type = ' char ' , size = 124 , fnct_inv = _rrule_write , 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 ' ) ,
2013-12-09 14:08:19 +00:00
' recurrent_id_date ' : fields . datetime ( ' Recurrent ID date ' ) ,
2013-11-23 11:36:27 +00:00
#'recurrence_end_date': fields.function(_get_recurrence_end_date, type='datetime', store=True, string='Recurrence end date',priority=30),
' vtimezone ' : fields . selection ( _tz_get , size = 64 , string = ' Timezone ' ) ,
' 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 ' ) ,
' 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 ' ) ,
' end_date ' : fields . date ( ' Repeat Until ' ) ,
' allday ' : fields . boolean ( ' All Day ' , states = { ' done ' : [ ( ' readonly ' , True ) ] } ) ,
' user_id ' : fields . many2one ( ' res.users ' , ' Responsible ' , states = { ' done ' : [ ( ' readonly ' , True ) ] } ) ,
' color_partner_id ' : fields . related ( ' user_id ' , ' partner_id ' , ' id ' , type = " int " , string = " colorize " , store = False ) , #Color of creator
' active ' : fields . boolean ( ' Active ' , help = " If the active field is set to true, it will allow you to hide the event alarm information without removing it. " ) ,
' categ_ids ' : fields . many2many ( ' crm.meeting.type ' , ' meeting_category_rel ' , ' event_id ' , ' type_id ' , ' Tags ' ) ,
2013-12-09 14:08:19 +00:00
' attendee_ids ' : fields . one2many ( ' calendar.attendee ' , ' event_id ' , ' Attendees ' , ondelete = ' cascade ' ) ,
#'attendee_ids': fields.many2many('calendar.attendee', 'crmmeeting_attendee_rel', 'crmmeeting_id', 'attendee_id', 'Attendees', ondelete='cascade'),
2013-11-23 11:36:27 +00:00
' partner_ids ' : fields . many2many ( ' res.partner ' , string = ' Attendees ' , states = { ' done ' : [ ( ' readonly ' , True ) ] } ) ,
' alarm_ids ' : fields . many2many ( ' calendar.alarm ' , string = ' Reminders ' ) ,
}
_defaults = {
' end_type ' : ' count ' ,
' count ' : 1 ,
' rrule_type ' : False ,
' state ' : ' draft ' ,
' class ' : ' public ' ,
' show_as ' : ' busy ' ,
' month_by ' : ' date ' ,
' interval ' : 1 ,
' active ' : 1 ,
' user_id ' : lambda self , cr , uid , ctx : uid ,
' partner_ids ' : lambda self , cr , uid , ctx : [ self . pool . get ( ' res.users ' ) . browse ( cr , uid , [ uid ] , context = ctx ) [ 0 ] . partner_id . id ]
}
def _check_closing_date ( self , cr , uid , ids , context = None ) :
for event in self . browse ( cr , uid , ids , context = context ) :
if event . date_deadline < event . date :
return False
return True
_constraints = [
( _check_closing_date , ' Error ! End date cannot be set before start date. ' , [ ' date_deadline ' ] ) ,
]
def onchange_dates ( self , cr , uid , ids , start_date , duration = False , end_date = False , allday = False , context = None ) :
""" Returns duration and/or end date based on values passed
@param ids : List of calendar event ' s IDs.
@param start_date : Starting date
@param duration : Duration between start date and end date
@param end_date : Ending Datee
"""
if context is None :
context = { }
value = { }
if not start_date :
return value
2013-11-26 11:45:02 +00:00
2013-11-23 11:36:27 +00:00
if not end_date and not duration :
duration = 1.00
value [ ' duration ' ] = duration
2013-12-09 14:08:19 +00:00
2013-11-23 11:36:27 +00:00
if allday : # For all day event
2013-12-09 14:08:19 +00:00
start = datetime . strptime ( start_date . split ( ' ' ) [ 0 ] . split ( ' T ' ) [ 0 ] , " % Y- % m- %d " )
2013-11-23 11:36:27 +00:00
duration = 24.0
value [ ' duration ' ] = duration
# change start_date's time to 00:00:00 in the user's timezone
user = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid )
tz = pytz . timezone ( user . tz ) if user . tz else pytz . utc
start = pytz . utc . localize ( start ) . astimezone ( tz ) # convert start in user's timezone
2013-11-26 11:45:02 +00:00
#start = start.replace(hour=0, minute=0, second=0) # remove time
2013-11-23 11:36:27 +00:00
start = start . astimezone ( pytz . utc ) # convert start back to utc
2013-12-09 14:08:19 +00:00
value [ ' date ' ] = start . strftime ( " % Y- % m- %d " ) + ' 00:00:00 '
else :
start = datetime . strptime ( start_date , " % Y- % m- %d % H: % M: % S " )
2013-11-23 11:36:27 +00:00
if end_date and not duration :
end = datetime . strptime ( end_date , " % Y- % m- %d % H: % M: % S " )
diff = end - start
duration = float ( diff . days ) * 24 + ( float ( diff . seconds ) / 3600 )
value [ ' duration ' ] = round ( duration , 2 )
elif not end_date :
end = start + timedelta ( hours = duration )
value [ ' date_deadline ' ] = end . strftime ( " % Y- % m- %d % H: % M: % S " )
elif end_date and duration and not allday :
# we have both, keep them synchronized:
# set duration based on end_date (arbitrary decision: this avoid
# getting dates like 06:31:48 instead of 06:32:00)
end = datetime . strptime ( end_date , " % Y- % m- %d % H: % M: % S " )
diff = end - start
duration = float ( diff . days ) * 24 + ( float ( diff . seconds ) / 3600 )
value [ ' duration ' ] = round ( duration , 2 )
2013-11-26 18:01:06 +00:00
2013-11-23 11:36:27 +00:00
return { ' value ' : value }
2013-12-09 14:08:19 +00:00
# def unlink_events(self, cr, uid, ids, context=None):
# """
# This function deletes event which are linked with the event with recurrent_id
# (Removes the events which refers to the same UID value)
# """
# if context is None:
# context = {}
# for event_id in ids:
# r_ids = self.search(cr,uid,[('recurrent_id','=',event_id)],context=context)
# self.unlink(cr, uid, r_ids, context=context)
# return True
2013-11-23 11:36:27 +00:00
def new_invitation_token ( self , cr , uid , record , partner_id ) :
db_uuid = self . pool . get ( ' ir.config_parameter ' ) . get_param ( cr , uid , ' database.uuid ' )
invitation_token = hashlib . sha256 ( ' %s - %s - %s - %s - %s ' % ( time . time ( ) , db_uuid , record . _name , record . id , partner_id ) ) . hexdigest ( )
return invitation_token
def create_attendees ( self , cr , uid , ids , context ) :
att_obj = self . pool . get ( ' calendar.attendee ' )
user_obj = self . pool . get ( ' res.users ' )
current_user = user_obj . browse ( cr , uid , uid , context = context )
2013-11-26 18:01:06 +00:00
res = { }
2013-11-23 11:36:27 +00:00
for event in self . browse ( cr , uid , ids , context ) :
attendees = { }
for att in event . attendee_ids :
attendees [ att . partner_id . id ] = True
new_attendees = [ ]
2013-11-26 18:01:06 +00:00
new_att_partner_ids = [ ]
2013-11-26 11:45:02 +00:00
# mail_to = ""
2013-11-23 11:36:27 +00:00
for partner in event . partner_ids :
if partner . id in attendees :
continue
access_token = self . new_invitation_token ( cr , uid , event , partner . id )
att_id = self . pool . get ( ' calendar.attendee ' ) . create ( cr , uid , {
' partner_id ' : partner . id ,
' user_id ' : partner . user_ids and partner . user_ids [ 0 ] . id or False ,
2013-12-09 14:08:19 +00:00
' event_id ' : event . id ,
2013-11-23 11:36:27 +00:00
' access_token ' : access_token ,
' email ' : partner . email ,
} , context = context )
2013-11-26 11:45:02 +00:00
# if partner.email:
# mail_to = mail_to + " " + partner.email
2013-11-23 11:36:27 +00:00
new_attendees . append ( att_id )
new_att_partner_ids . append ( partner . id )
2013-11-26 11:45:02 +00:00
if not current_user . email or current_user . email != partner . email :
mail_from = current_user . email or tools . config . get ( ' email_from ' , False )
print " Send mail... from " , mail_from , " to " , att_id
2013-11-26 18:01:06 +00:00
if self . pool . get ( ' calendar.attendee ' ) . _send_mail_to_attendees ( cr , uid , att_id , email_from = mail_from , context = context ) :
2013-11-26 11:45:02 +00:00
self . message_post ( cr , uid , event . id , body = _ ( " An invitation email has been sent to attendee %s " ) % ( partner . name , ) , subtype = " base_calendar.subtype_invitation " , context = context )
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 )
2013-11-23 11:36:27 +00:00
# We remove old attendees who are not in partner_ids now.
all_partner_ids = [ part . id for part in event . partner_ids ]
all_attendee_ids = [ att . partner_id . id for att in event . attendee_ids ]
partner_ids_to_remove = map ( lambda x : x , set ( all_attendee_ids + new_att_partner_ids ) - set ( all_partner_ids ) )
2013-11-26 18:01:06 +00:00
attendee_ids_to_remove = [ ]
2013-11-23 11:36:27 +00:00
if partner_ids_to_remove :
2013-12-09 14:08:19 +00:00
attendee_ids_to_remove = self . pool . get ( " calendar.attendee " ) . search ( cr , uid , [ ( ' partner_id.id ' , ' in ' , partner_ids_to_remove ) , ( ' event_id.id ' , ' = ' , event . id ) ] , context = context )
2013-11-23 11:36:27 +00:00
if attendee_ids_to_remove :
2013-11-26 11:45:02 +00:00
self . pool . get ( " calendar.attendee " ) . unlink ( cr , uid , attendee_ids_to_remove , context )
## NEED TO UNSUBSCRIBE ?
2013-11-23 11:36:27 +00:00
2013-11-26 18:01:06 +00:00
res [ event . id ] = {
' new_attendee_ids ' : new_attendees ,
' old_attendee_ids ' : all_attendee_ids ,
' removed_attendee_ids ' : attendee_ids_to_remove
}
return res
2013-11-23 11:36:27 +00:00
def get_recurrent_ids ( self , cr , uid , select , domain , limit = 100 , context = None ) :
""" Gives virtual event ids for recurring events based on value of Recurrence Rule
This method gives ids of dates that comes between start date and end date of calendar views
@param limit : The Number of Results to Return """
if not context :
context = { }
2013-12-09 14:08:19 +00:00
if isinstance ( select , ( str , int , long ) ) :
ids_to_browse = [ select ] #keep select for return
else :
ids_to_browse = select
2013-11-23 11:36:27 +00:00
result = [ ]
2013-12-09 14:08:19 +00:00
for ev in self . browse ( cr , uid , select , context = context ) :
if not ev . recurrency or not ev . rrule :
result . append ( ev . id )
2013-11-23 11:36:27 +00:00
continue
# event_date = datetime.strptime(data['date'], "%Y-%m-%d %H:%M:%S")
# event_date = pytz.UTC.localize(event_date)
2013-12-09 14:08:19 +00:00
rdates = self . get_recurrent_date_by_event ( cr , uid , ev , context = context )
2013-11-23 11:36:27 +00:00
for r_date in rdates :
# fix domain evaluation
# step 1: check date and replace expression by True or False, replace other expressions by True
# step 2: evaluation of & and |
# check if there are one False
pile = [ ]
ok = True
for arg in domain :
if str ( arg [ 0 ] ) in ( str ( ' date ' ) , str ( ' date_deadline ' ) , str ( ' end_date ' ) ) :
if ( arg [ 1 ] == ' = ' ) :
ok = r_date . strftime ( ' % Y- % m- %d ' ) == arg [ 2 ]
if ( arg [ 1 ] == ' > ' ) :
ok = r_date . strftime ( ' % Y- % m- %d ' ) > arg [ 2 ]
if ( arg [ 1 ] == ' < ' ) :
ok = r_date . strftime ( ' % Y- % m- %d ' ) < arg [ 2 ]
if ( arg [ 1 ] == ' >= ' ) :
ok = r_date . strftime ( ' % Y- % m- %d ' ) > = arg [ 2 ]
if ( arg [ 1 ] == ' <= ' ) :
ok = r_date . strftime ( ' % Y- % m- %d ' ) < = arg [ 2 ]
pile . append ( ok )
elif str ( arg ) == str ( ' & ' ) or str ( arg ) == str ( ' | ' ) :
pile . append ( arg )
else :
pile . append ( True )
pile . reverse ( )
new_pile = [ ]
for item in pile :
if not isinstance ( item , basestring ) :
res = item
elif str ( item ) == str ( ' & ' ) :
first = new_pile . pop ( )
second = new_pile . pop ( )
res = first and second
elif str ( item ) == str ( ' | ' ) :
first = new_pile . pop ( )
second = new_pile . pop ( )
res = first or second
new_pile . append ( res )
if [ True for item in new_pile if not item ] :
continue
# idval = real_id2base_calendar_id(data['id'], r_date.strftime("%Y-%m-%d %H:%M:%S"))
2013-12-09 14:08:19 +00:00
idval = ' %d - %s ' % ( ev . id , r_date . strftime ( " % Y % m %d % H % M % S " ) )
2013-11-23 11:36:27 +00:00
result . append ( idval )
2013-12-09 14:08:19 +00:00
2013-11-23 11:36:27 +00:00
if isinstance ( select , ( str , int , long ) ) :
return ids and ids [ 0 ] or False
else :
ids = list ( set ( result ) )
2013-12-09 14:08:19 +00:00
2013-11-23 11:36:27 +00:00
return ids
def compute_rule_string ( self , data ) :
"""
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 )
"""
def get_week_string ( freq , data ) :
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 = map(lambda x: x.upper(),[data[day] for day in weekdays if data[day]])
if byday :
return ' ;BYDAY= ' + ' , ' . join ( byday )
return ' '
def get_month_string ( freq , data ) :
if freq == ' monthly ' :
if data . get ( ' month_by ' ) == ' date ' and ( data . get ( ' day ' ) < 1 or data . get ( ' day ' ) > 31 ) :
raise osv . except_osv ( _ ( ' Error! ' ) , ( " 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 ' ) )
return ' '
def get_end_date ( data ) :
if data . get ( ' end_date ' ) :
data [ ' end_date_new ' ] = ' ' . join ( ( re . compile ( ' \ d ' ) ) . findall ( data . get ( ' end_date ' ) ) ) + ' T235959Z '
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 = ' '
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
def _get_empty_rrule_data ( self ) :
return {
' byday ' : False ,
' recurrency ' : False ,
' end_date ' : False ,
' rrule_type ' : False ,
' month_by ' : False ,
' interval ' : 0 ,
' count ' : False ,
' end_type ' : False ,
' mo ' : False ,
' tu ' : False ,
' we ' : False ,
' th ' : False ,
' fr ' : False ,
' sa ' : False ,
' su ' : False ,
' day ' : False ,
' week_list ' : False
}
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 , " % Y- % m- %d % H: % M: % S " ) )
if r . _freq > 0 and r . _freq < 4 :
data [ ' rrule_type ' ] = rrule_type [ r . _freq ]
data [ ' count ' ] = r . _count
data [ ' interval ' ] = r . _interval
data [ ' end_date ' ] = r . _until and r . _until . strftime ( " % Y- % m- %d % H: % M: % S " )
#repeat weekly
if r . _byweekday :
for i in xrange ( 0 , 7 ) :
if i in r . _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 ' ] = r . _bynweekday [ 0 ] [ 1 ]
data [ ' month_by ' ] = ' day '
data [ ' rrule_type ' ] = ' monthly '
if r . _bymonthday :
data [ ' day ' ] = r . _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 :
data [ ' interval ' ] = data [ ' interval ' ] * 12
#FIXEME handle forever case
#end of recurrence
#in case of repeat for ever that we do not support right now
if not ( data . get ( ' count ' ) or data . get ( ' end_date ' ) ) :
data [ ' count ' ] = 100
if data . get ( ' count ' ) :
data [ ' end_type ' ] = ' count '
else :
data [ ' end_type ' ] = ' end_date '
2013-12-09 14:08:19 +00:00
2013-11-23 11:36:27 +00:00
return data
#def _get_data(self, cr, uid, id, context=None):
# return self.read(cr, uid, id,['date', 'date_deadline'])
# def need_to_update(self, event_id, vals):
# split_id = str(event_id).split("-")
# if len(split_id) < 2:
# return False
# else:
# date_start = vals.get('date', '')
# try:
# date_start = datetime.strptime(date_start, '%Y-%m-%d %H:%M:%S').strftime("%Y%m%d%H%M%S")
# return date_start == split_id[1]
# except Exception:
# return True
def message_get_subscription_data ( self , cr , uid , ids , user_pid = None , context = None ) :
res = { }
for virtual_id in ids :
real_id = base_calendar_id2real_id ( virtual_id )
result = super ( crm_meeting , self ) . message_get_subscription_data ( cr , uid , [ real_id ] , user_pid = None , context = context )
res [ virtual_id ] = result [ real_id ]
return res
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 ) :
##TODO : REFACTOR !
""" Verify that selected partner_ids have an email_address defined.
Otherwise throw a warning . """
partner_wo_email_lst = [ ]
for partner in self . pool . get ( ' 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 ,
}
}
# ----------------------------------------
# OpenChatter
# ----------------------------------------
# shows events of the day for this user
def _needaction_domain_get ( self , cr , uid , context = None ) :
return [ ( ' end_date ' , ' >= ' , time . strftime ( DEFAULT_SERVER_DATE_FORMAT + ' 23:59:59 ' ) ) , ( ' date ' , ' >= ' , time . strftime ( DEFAULT_SERVER_DATE_FORMAT + ' 23:59:59 ' ) ) , ( ' user_id ' , ' = ' , uid ) ]
def message_post ( self , cr , uid , thread_id , body = ' ' , subject = None , type = ' notification ' , subtype = None , parent_id = False , attachments = None , context = None , * * kwargs ) :
if isinstance ( thread_id , str ) :
thread_id = get_real_ids ( thread_id )
if context . get ( ' default_date ' ) :
del context [ ' default_date ' ]
return super ( crm_meeting , self ) . message_post ( cr , uid , thread_id , body = body , subject = subject , type = type , subtype = subtype , parent_id = parent_id , attachments = attachments , context = context , * * kwargs )
def do_sendmail ( self , cr , uid , ids , context = None ) :
for event in self . browse ( cr , uid , ids , context ) :
current_user = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , context = context )
if current_user . email :
2013-11-26 18:01:06 +00:00
if self . pool . get ( ' calendar.attendee ' ) . _send_mail_to_attendees ( cr , uid , [ att . id for att in event . attendee_ids ] , email_from = current_user . email , context = context ) :
2013-11-26 11:45:02 +00:00
self . message_post ( cr , uid , event . id , body = _ ( " An invitation email has been sent to attendee(s) " ) , subtype = " base_calendar.subtype_invitation " , context = context )
2013-11-23 11:36:27 +00:00
return ;
2013-11-24 13:02:41 +00:00
2013-11-23 11:36:27 +00:00
def get_attendee ( self , cr , uid , meeting_id , context = None ) :
#Used for view in controller
invitation = { ' meeting ' : { } , ' attendee ' : [ ] , ' logo ' : ' ' }
attendee_pool = self . pool . get ( ' calendar.attendee ' )
company_logo = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , context = context ) . company_id . logo
meeting = self . browse ( cr , uid , int ( meeting_id ) , context )
invitation [ ' meeting ' ] = {
' event ' : meeting . name ,
' where ' : meeting . location ,
' when ' : meeting . display_time
}
invitation [ ' logo ' ] = company_logo . replace ( ' \n ' , ' \\ n ' ) if company_logo else ' '
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 , context = None ) :
#Function used only in crm_meeting_data.xml for email template
2013-11-26 11:45:02 +00:00
date = datetime . strptime ( date . split ( ' . ' ) [ 0 ] , DEFAULT_SERVER_DATETIME_FORMAT )
2013-11-23 11:36:27 +00:00
if interval == ' day ' :
res = str ( date . day )
elif interval == ' month ' :
res = date . strftime ( ' % B ' ) + " " + str ( date . year )
elif interval == ' dayname ' :
res = date . strftime ( ' % A ' )
elif interval == ' time ' :
res = date . strftime ( ' % I: % M % p ' )
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 . get ( ' res.users ' ) . browse ( cr , uid , uid , context ) . partner_id . id
args + = [ ' | ' , ( ' partner_ids ' , ' in ' , [ partner_id ] ) , ( ' user_id ' , ' = ' , uid ) ]
new_args = [ ]
for arg in args :
new_arg = arg
if arg [ 0 ] in ( ' date ' , unicode ( ' date ' ) ) and arg [ 1 ] == " >= " :
if context . get ( ' virtual_id ' , True ) :
new_args + = [ ' | ' , ' & ' , ( ' recurrency ' , ' = ' , 1 ) , ( ' end_date ' , arg [ 1 ] , arg [ 2 ] ) ]
# new_args += ['|','&',('recurrency','=',1),('date_deadline', arg[1], arg[2])]
elif arg [ 0 ] in ( ' date ' , unicode ( ' date ' ) ) :
if context . get ( ' virtual_id ' , True ) :
2013-11-26 20:52:23 +00:00
print ' '
#new_args += ['|','&',('recurrency','=',1),('end_date', arg[1], arg[2])]
2013-11-23 11:36:27 +00:00
# new_args += ['|','&',('recurrency','=',1),('date_deadline', arg[1], arg[2])]
elif arg [ 0 ] == " id " :
new_id = get_real_ids ( arg [ 2 ] )
new_arg = ( arg [ 0 ] , arg [ 1 ] , new_id )
new_args . append ( new_arg )
#offset, limit and count must be treated separately as we may need to deal with virtual ids
2013-12-09 14:08:19 +00:00
2013-11-23 11:36:27 +00:00
res = super ( crm_meeting , self ) . search ( cr , uid , new_args , offset = 0 , limit = 0 , order = order , context = context , count = False )
if context . get ( ' virtual_id ' , True ) :
res = self . get_recurrent_ids ( cr , uid , res , args , limit , context = context )
if count :
return len ( res )
elif limit :
return res [ offset : offset + limit ]
return res
def copy ( self , cr , uid , id , default = None , context = None ) :
if context is None :
context = { }
default = default or { }
default [ ' attendee_ids ' ] = False
2013-12-02 14:52:42 +00:00
2013-11-23 11:36:27 +00:00
res = super ( crm_meeting , self ) . copy ( cr , uid , base_calendar_id2real_id ( id ) , default , context )
return res
def write ( self , cr , uid , ids , values , context = None ) :
2013-12-09 14:08:19 +00:00
print " Write : " , ids
print values
2013-11-23 11:36:27 +00:00
def _only_changes_to_apply_on_real_ids ( field_names ) :
''' return True if changes are only to be made on the real ids '''
for field in field_names :
if field not in [ ' message_follower_ids ' ] :
return False
return True
context = context or { }
if isinstance ( ids , ( str , int , long ) ) :
ids = [ ids ]
res = False
2013-11-27 12:33:29 +00:00
new_id = False
2013-11-23 11:36:27 +00:00
# Special write of complex IDS
2013-12-09 14:08:19 +00:00
for event_id in ids :
2013-11-23 11:36:27 +00:00
if len ( str ( event_id ) . split ( ' - ' ) ) == 1 :
continue
2013-12-09 14:08:19 +00:00
2013-11-23 11:36:27 +00:00
ids . remove ( event_id )
real_event_id = base_calendar_id2real_id ( event_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):
# then set real ids to be updated.
if not values . get ( ' recurrency ' , True ) or _only_changes_to_apply_on_real_ids ( values . keys ( ) ) :
ids . append ( real_event_id )
continue
#if edit one instance of a reccurrent id
data = self . read ( cr , uid , event_id , [ ' date ' , ' date_deadline ' , \
2013-12-09 14:08:19 +00:00
' rrule ' , ' duration ' ] ) #, 'exdate'])
2013-11-23 11:36:27 +00:00
if data . get ( ' rrule ' ) :
data . update (
values ,
recurrent_id = real_event_id ,
2013-12-09 14:08:19 +00:00
recurrent_id_date = data . get ( ' date ' ) ,
2013-11-23 11:36:27 +00:00
rrule_type = False ,
rrule = ' ' ,
recurrency = False ,
2013-12-09 14:08:19 +00:00
end_date = datetime . strptime ( values . get ( ' date ' , False ) or data . get ( ' date ' ) , " % Y- % m- %d % H: % M: % S " ) + timedelta ( hours = values . get ( ' duration ' , False ) or data . get ( ' duration ' ) )
2013-11-23 11:36:27 +00:00
)
2013-12-09 14:08:19 +00:00
2013-11-23 11:36:27 +00:00
#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 )
date_new = event_id . split ( ' - ' ) [ 1 ]
2013-11-25 08:50:18 +00:00
date_new = time . strftime ( " % Y % m %d T % H % M % SZ " , time . strptime ( date_new , " % Y % m %d % H % M % S " ) )
2013-12-09 14:08:19 +00:00
#exdate = (data['exdate'] and (data['exdate'] + ',') or '') + date_new
#res = super(crm_meeting, self).write(cr, uid, [real_event_id], {'exdate': exdate})
2013-11-23 11:36:27 +00:00
context . update ( { ' active_id ' : new_id , ' active_ids ' : [ new_id ] } )
continue
res = super ( crm_meeting , self ) . write ( cr , uid , ids , values , context = context )
# set end_date for calendar searching
if values . get ( ' recurrency ' , True ) and values . get ( ' end_type ' , ' count ' ) in ( ' count ' , unicode ( ' count ' ) ) and \
( values . get ( ' rrule_type ' ) or values . get ( ' count ' ) or values . get ( ' date ' ) or values . get ( ' date_deadline ' ) ) :
for data in self . read ( cr , uid , ids , [ ' date ' , ' date_deadline ' , ' recurrency ' , ' rrule_type ' , ' count ' , ' end_type ' ] , context = context ) :
end_date = self . _get_recurrency_end_date ( data , context = context )
super ( crm_meeting , self ) . write ( cr , uid , [ data [ ' id ' ] ] , { ' end_date ' : end_date } , context = context )
2013-12-02 14:31:33 +00:00
attendees_create = False
2013-11-23 11:36:27 +00:00
if values . get ( ' partner_ids ' , False ) :
2013-11-24 13:02:41 +00:00
attendees_create = self . create_attendees ( cr , uid , ids , context )
2013-12-02 14:31:33 +00:00
2013-12-09 14:08:19 +00:00
if values . get ( ' date ' , False ) and not context . get ( ' install_mode ' , False ) and values . get ( ' active ' , True ) : #Not send mail when install data
2013-11-27 12:33:29 +00:00
the_id = new_id or ( ids and int ( ids [ 0 ] ) ) ;
2013-11-26 18:01:06 +00:00
if attendees_create :
2013-11-27 12:33:29 +00:00
attendees_create = attendees_create [ the_id ]
2013-11-26 18:01:06 +00:00
mail_to_ids = list ( set ( attendees_create [ ' old_attendee_ids ' ] ) - set ( attendees_create [ ' removed_attendee_ids ' ] ) )
else :
2013-11-27 12:33:29 +00:00
mail_to_ids = [ att . id for att in self . browse ( cr , uid , the_id , context = context ) . attendee_ids ]
2013-11-24 13:02:41 +00:00
2013-11-26 18:01:06 +00:00
if mail_to_ids :
current_user = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , context = context )
if self . pool . get ( ' calendar.attendee ' ) . _send_mail_to_attendees ( cr , uid , mail_to_ids , template_xmlid = ' crm_email_template_meeting_changedate ' , email_from = current_user . email , context = context ) :
2013-11-27 12:33:29 +00:00
self . message_post ( cr , uid , the_id , body = _ ( " A email has been send to specify that the date has been changed ! " ) , subtype = " base_calendar.subtype_invitation " , context = context )
2013-11-26 18:01:06 +00:00
else :
print ' Send mail return false '
2013-11-23 11:36:27 +00:00
return res or True and False
def create ( self , cr , uid , vals , context = None ) :
if context is None :
context = { }
if not ' user_id ' in vals : #Else bug with quick_create when we are filter on an other user
vals [ ' user_id ' ] = uid
2013-11-26 20:52:23 +00:00
if vals . get ( ' recurrency ' , True ) and vals . get ( ' end_type ' , ' count ' ) in ( ' count ' , unicode ( ' count ' ) ) and \
( vals . get ( ' rrule_type ' ) or vals . get ( ' count ' ) or vals . get ( ' date ' ) or vals . get ( ' date_deadline ' ) ) :
vals [ ' end_date ' ] = self . _get_recurrency_end_date ( vals , context = context )
2013-12-09 14:08:19 +00:00
print " CREATE WITH VALUES " , vals
2013-11-23 11:36:27 +00:00
res = super ( crm_meeting , self ) . create ( cr , uid , vals , context = context )
#res = self.write(cr, uid, id_res,vals, context)
self . create_attendees ( cr , uid , [ res ] , context = context )
return res
def read_group ( self , cr , uid , domain , fields , groupby , offset = 0 , limit = None , context = None , orderby = False ) :
if not context :
context = { }
if ' date ' in groupby :
raise osv . except_osv ( _ ( ' Warning! ' ) , _ ( ' 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 ( crm_meeting , self ) . read_group ( cr , uid , domain , fields , groupby , offset = offset , limit = limit , context = context , orderby = orderby )
for re in res :
#remove the count, since the value is not consistent with the result of the search when expand the group
for groupname in groupby :
if re . get ( groupname + " _count " ) :
del re [ groupname + " _count " ]
re . get ( ' __context ' , { } ) . update ( { ' virtual_id ' : virtual_id } )
return res
def read ( self , cr , uid , ids , fields = None , context = None , load = ' _classic_read ' ) :
if context is None :
context = { }
fields2 = fields and fields [ : ] or None
2013-12-09 14:08:19 +00:00
EXTRAFIELDS = ( ' class ' , ' user_id ' , ' duration ' , ' date ' , ' rrule ' , ' vtimezone ' ) #, 'exdate')
2013-11-23 11:36:27 +00:00
for f in EXTRAFIELDS :
if fields and ( f not in fields ) :
fields2 . append ( f )
# FIXME This whole id mangling has to go!
if isinstance ( ids , ( str , int , long ) ) :
select = [ ids ]
else :
select = ids
select = map ( lambda x : ( x , base_calendar_id2real_id ( x ) ) , select )
result = [ ]
real_data = super ( crm_meeting , self ) . read ( cr , uid , [ real_id for base_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 ) )
for base_calendar_id , real_id in select :
res = real_data [ real_id ] . copy ( )
res = real_data [ real_id ] . copy ( )
ls = base_calendar_id2real_id ( base_calendar_id , with_date = res and res . get ( ' duration ' , 0 ) or 0 )
if not isinstance ( ls , ( str , int , long ) ) and len ( ls ) > = 2 :
2013-12-09 14:08:19 +00:00
#recurrent_dates = [d.strftime("%Y-%m-%d %H:%M:%S") for d in get_recurrent_dates(res['rrule'], res['date'], res['exdate'],res['vtimezone'], context=context)]
2013-11-23 11:36:27 +00:00
#if not (ls[1] in recurrent_dates or ls[1] in res['exdate']): #when update a recurrent event
res [ ' date ' ] = ls [ 1 ]
res [ ' date_deadline ' ] = ls [ 2 ]
res [ ' id ' ] = base_calendar_id
result . append ( res )
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 :
continue
if r [ ' class ' ] == ' private ' :
for f in r . keys ( ) :
if f not in ( ' id ' , ' date ' , ' date_deadline ' , ' duration ' , ' user_id ' , ' state ' , ' interval ' , ' count ' ) :
if isinstance ( r [ f ] , list ) :
r [ f ] = [ ]
else :
r [ f ] = False
if f == ' name ' :
r [ f ] = _ ( ' Busy ' )
for r in result :
for k in EXTRAFIELDS :
if ( k in r ) and ( fields and ( k not in fields ) ) :
del r [ k ]
if isinstance ( ids , ( str , int , long ) ) :
return result and result [ 0 ] or False
return result
2013-12-09 14:08:19 +00:00
def count_left_instance ( self , cr , uid , event_id , context = None ) :
event = self . browse ( cr , uid , event_id , context = context )
if event . recurrent_id and event . recurrent_id > 0 :
parent_event_id = event . recurrent_id
else :
parent_event_id = event . id
domain = [ ' | ' , ( ' id ' , ' = ' , parent_event_id ) , ( ' recurrent_id ' , ' = ' , parent_event_id ) ]
count = self . search ( cr , uid , domain , context = context )
print " Count = " , count
return len ( count )
def get_linked_ids ( self , cr , uid , event_id , show_unactive = True , context = None ) :
event = self . browse ( cr , uid , event_id , context = context )
if event . recurrent_id and event . recurrent_id > 0 :
parent_event_id = event . recurrent_id
else :
parent_event_id = event . id
domain = [ ' | ' , ( ' id ' , ' = ' , parent_event_id ) , ( ' recurrent_id ' , ' = ' , parent_event_id ) ]
if show_unactive :
domain + = [ ' | ' , ( ' active ' , ' = ' , True ) , ( ' active ' , ' = ' , False ) ]
return super ( crm_meeting , self ) . search ( cr , uid , domain , context = context )
def delete ( self , cr , uid , ids , context = None ) :
if not isinstance ( ids , list ) :
ids = [ ids ]
all_ids = [ ]
for id_to_unlink in ids :
all_ids + = self . get_linked_ids ( cr , uid , id_to_unlink , context = context )
print " in deleTe functIon === ids : %s , all_ids : %s " % ( ids , all_ids )
all_ids = list ( set ( all_ids ) )
res = super ( crm_meeting , self ) . unlink ( cr , uid , all_ids , context = context )
return all_ids
def unlink ( self , cr , uid , ids , unlink_level = 0 , context = None ) :
print " IN UNLINK !!! "
2013-11-23 11:36:27 +00:00
if not isinstance ( ids , list ) :
ids = [ ids ]
res = False
2013-12-09 14:08:19 +00:00
ids_to_exclure = [ ]
ids_to_unlink = [ ]
#One time moved to google_Calendar, we can specify, an if not in google, and not rec or get_inst = 0, we delete it
for event_id in ids :
#if unlink_level == 1 and len(str(event_id).split('-')) == 1: ## if ID REAL
if unlink_level == 1 and len ( str ( event_id ) . split ( ' - ' ) ) == 1 : ## if ID REAL
if self . browse ( cr , uid , event_id ) . recurrent_id :
print " Could not be deleted ! because instance of recursive "
ids_to_exclure . append ( event_id )
else :
ids_to_unlink . append ( event_id )
else :
print " Could not be deleted ! because instance virtual "
ids_to_exclure . append ( event_id )
2013-11-23 11:36:27 +00:00
2013-12-09 14:08:19 +00:00
if ids_to_unlink :
res = super ( crm_meeting , self ) . unlink ( cr , uid , ids_to_unlink , context = context )
if ids_to_exclure :
for id_to_exclure in ids_to_exclure :
res = self . write ( cr , uid , id_to_exclure , { ' active ' : False } , context = context )
2013-11-23 11:36:27 +00:00
return res
2013-12-09 14:08:19 +00:00
2013-11-23 11:36:27 +00:00
class mail_message ( osv . osv ) :
_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 ( )
'''
for index in range ( len ( args ) ) :
if args [ index ] [ 0 ] == " res_id " and isinstance ( args [ index ] [ 2 ] , str ) :
args [ index ] [ 2 ] = get_real_ids ( args [ index ] [ 2 ] )
return super ( mail_message , self ) . search ( cr , uid , args , offset = offset , limit = limit , order = order , context = context , count = count )
def _find_allowed_model_wise ( self , cr , uid , doc_model , doc_dict , context = None ) :
if doc_model == ' crm.meeting ' :
for virtual_id in self . pool [ doc_model ] . get_recurrent_ids ( cr , uid , doc_dict . keys ( ) , [ ] , context = context ) :
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 )
class ir_attachment ( osv . osv ) :
_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 ( )
'''
for index in range ( len ( args ) ) :
if args [ index ] [ 0 ] == " res_id " and isinstance ( args [ index ] [ 2 ] , str ) :
args [ index ] [ 2 ] = 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 )
def write ( self , cr , uid , ids , vals , context = None ) :
'''
when posting an attachment ( new or not ) , convert the virtual ids in real ids .
'''
if isinstance ( vals . get ( ' res_id ' ) , str ) :
vals [ ' res_id ' ] = get_real_ids ( vals . get ( ' res_id ' ) )
return super ( ir_attachment , self ) . write ( cr , uid , ids , vals , context = context )
class invite_wizard ( osv . osv_memory ) :
_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
'''
result = super ( invite_wizard , self ) . default_get ( cr , uid , fields , context = context )
if ' res_id ' in result :
result [ ' res_id ' ] = get_real_ids ( result [ ' res_id ' ] )
return result