[FIX] calendar, google_calendar: multiple fixes with timezones, filters, google sync and dashboards

bzr revid: odo@openerp.com-20140218171508-6li402027u57ltrx
This commit is contained in:
jke-openerp 2014-02-18 18:15:08 +01:00 committed by Olivier Dony
parent 3226a16b99
commit 629daccd56
6 changed files with 418 additions and 321 deletions

View File

@ -37,6 +37,8 @@ from openerp.tools.translate import _
from openerp.http import request from openerp.http import request
from operator import itemgetter from operator import itemgetter
from werkzeug.exceptions import BadRequest
import logging import logging
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@ -843,6 +845,7 @@ class calendar_event(osv.Model):
'attendee_ids': fields.one2many('calendar.attendee', 'event_id', 'Attendees', ondelete='cascade'), 'attendee_ids': fields.one2many('calendar.attendee', 'event_id', 'Attendees', ondelete='cascade'),
'partner_ids': fields.many2many('res.partner', string='Attendees', states={'done': [('readonly', True)]}), 'partner_ids': fields.many2many('res.partner', string='Attendees', states={'done': [('readonly', True)]}),
'alarm_ids': fields.many2many('calendar.alarm', string='Reminders', ondelete="restrict"), 'alarm_ids': fields.many2many('calendar.alarm', string='Reminders', ondelete="restrict"),
} }
_defaults = { _defaults = {
'end_type': 'count', 'end_type': 'count',
@ -872,9 +875,6 @@ class calendar_event(osv.Model):
"""Returns duration and/or end date based on values passed """Returns duration and/or end date based on values passed
@param ids: List of calendar event's IDs. @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: if context is None:
context = {} context = {}
@ -1353,16 +1353,56 @@ class calendar_event(osv.Model):
res = super(calendar_event, self).copy(cr, uid, calendar_id2real_id(id), default, context) res = super(calendar_event, self).copy(cr, uid, calendar_id2real_id(id), default, context)
return res return res
def _detach_one_event(self, cr, uid, id, values=dict(), context=None):
real_event_id = calendar_id2real_id(id)
data = self.read(cr, uid, id, ['date', 'date_deadline', 'rrule', 'duration'])
if data.get('rrule'):
data.update(
values,
recurrent_id=real_event_id,
recurrent_id_date=data.get('date'),
rrule_type=False,
rrule='',
recurrency=False,
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'))
)
#do not copy the id
if data.get('id'):
del(data['id'])
new_id = self.copy(cr, uid, real_event_id, default=data, context=context)
return new_id
def open_after_detach_event(self, cr, uid, ids, context=None):
if context is None:
context = {}
new_id = self._detach_one_event(cr, uid, ids[0], context=context)
return {
'type': 'ir.actions.act_window',
'res_model': 'calendar.event',
'view_mode': 'form',
'res_id': new_id,
'target': 'current',
'flags': {'form': {'action_buttons': True, 'options' : { 'mode' : 'edit' } } }
}
def write(self, cr, uid, ids, values, context=None): def write(self, cr, uid, ids, values, context=None):
def _only_changes_to_apply_on_real_ids(field_names): def _only_changes_to_apply_on_real_ids(field_names):
''' return True if changes are only to be made on the real ids''' ''' return True if changes are only to be made on the real ids'''
for field in field_names: for field in field_names:
if field not in ['name', 'message_follower_ids','oe_update_date']: if field in ['date','active']:
return False
return True return True
return False
context = context or {} context = context or {}
if isinstance(ids, (str,int, long)): if isinstance(ids, (str,int, long)):
if len(str(ids).split('-')) == 1: if len(str(ids).split('-')) == 1:
ids = [int(ids)] ids = [int(ids)]
@ -1383,30 +1423,13 @@ class calendar_event(osv.Model):
# if we are setting the recurrency flag to False or if we are only changing fields that # 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): # should be only updated on the real ID and not on the virtual (like message_follower_ids):
# then set real ids to be updated. # then set real ids to be updated.
if not values.get('recurrency', True) or _only_changes_to_apply_on_real_ids(values.keys()): if not values.get('recurrency', True) or not _only_changes_to_apply_on_real_ids(values.keys()):
ids.append(real_event_id) ids.append(real_event_id)
continue continue
else:
#if edit one instance of a reccurrent id
data = self.read(cr, uid, event_id, ['date', 'date_deadline', 'rrule', 'duration']) data = self.read(cr, uid, event_id, ['date', 'date_deadline', 'rrule', 'duration'])
if data.get('rrule'): if data.get('rrule'):
data.update( new_id = self._detach_one_event(cr, uid, event_id, values, context=None)
values,
recurrent_id=real_event_id,
recurrent_id_date=data.get('date'),
rrule_type=False,
rrule='',
recurrency=False,
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'))
)
#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)
context.update({'active_id': new_id, 'active_ids': [new_id]})
continue
res = super(calendar_event, self).write(cr, uid, ids, values, context=context) res = super(calendar_event, self).write(cr, uid, ids, values, context=context)
@ -1473,7 +1496,6 @@ class calendar_event(osv.Model):
if context is None: if context is None:
context = {} context = {}
fields2 = fields and fields[:] or None fields2 = fields and fields[:] or None
EXTRAFIELDS = ('class', 'user_id', 'duration', 'date', 'rrule', 'vtimezone') EXTRAFIELDS = ('class', 'user_id', 'duration', 'date', 'rrule', 'vtimezone')
for f in EXTRAFIELDS: for f in EXTRAFIELDS:
if fields and (f not in fields): if fields and (f not in fields):
@ -1518,6 +1540,7 @@ class calendar_event(osv.Model):
for k in EXTRAFIELDS: for k in EXTRAFIELDS:
if (k in r) and (fields and (k not in fields)): if (k in r) and (fields and (k not in fields)):
del r[k] del r[k]
if isinstance(ids, (str, int, long)): if isinstance(ids, (str, int, long)):
return result and result[0] or False return result and result[0] or False
return result return result

View File

@ -51,6 +51,11 @@
</div> </div>
<notebook> <notebook>
<page string="Meeting Details"> <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"/>
</p>
</group>
<group> <group>
<group> <group>
<field name="date" string="Starting at" on_change="onchange_dates(date, duration, False, allday)"/> <field name="date" string="Starting at" on_change="onchange_dates(date, duration, False, allday)"/>

View File

@ -77,7 +77,6 @@ openerp.calendar = function(instance) {
if(instance.session.session_is_valid(self.db) && instance.session.username != "anonymous") { if(instance.session.session_is_valid(self.db) && instance.session.username != "anonymous") {
self.redirect_meeting_view(self.db,self.action,self.id,self.view); self.redirect_meeting_view(self.db,self.action,self.id,self.view);
} else { } else {
alert('in anonymous or null ');
self.open_invitation_form(self.attendee_data); self.open_invitation_form(self.attendee_data);
} }
}, },
@ -94,7 +93,6 @@ openerp.calendar = function(instance) {
return location.replace(action_url); return location.replace(action_url);
}; };
reload_page(); reload_page();
}, },
}); });

View File

@ -33,7 +33,9 @@
!python {model: calendar.event}: | !python {model: calendar.event}: |
ids = self.search(cr, uid, [('date', '>=', '2011-04-30 16:00:00'), ('date', '<=', '2011-05-31 00:00:00')], context={'virtual_id': True} ) ids = self.search(cr, uid, [('date', '>=', '2011-04-30 16:00:00'), ('date', '<=', '2011-05-31 00:00:00')], context={'virtual_id': True} )
before = self.search(cr, uid, [('date', '>=', '2011-04-30 16:00:00'), ('date', '<=', '2011-05-31 00:00:00')], context={'virtual_id': False}) before = self.search(cr, uid, [('date', '>=', '2011-04-30 16:00:00'), ('date', '<=', '2011-05-31 00:00:00')], context={'virtual_id': False})
self.write(cr, uid,[ids[1]], {'name':'New Name','recurrency' : True}, context={'virtual_id': True}) # We start by detach the event
newid = self._detach_one_event(cr, uid,ids[1])
self.write(cr, uid,[newid], {'name':'New Name','recurrency' : True}, context={'virtual_id': True})
after = self.search(cr, uid, [('date', '>=', '2011-04-30 16:00:00'), ('date', '<=', '2011-05-31 00:00:00')], context={'virtual_id': False}) after = self.search(cr, uid, [('date', '>=', '2011-04-30 16:00:00'), ('date', '<=', '2011-05-31 00:00:00')], context={'virtual_id': False})
assert len(after) == len(before)+1, 'Wrong number of events found, after to have moved a virtual event' assert len(after) == len(before)+1, 'Wrong number of events found, after to have moved a virtual event'
new_id = list(set(after)-set(before))[0] new_id = list(set(after)-set(before))[0]
@ -58,7 +60,6 @@
duration: 1 duration: 1
interval: days interval: days
type: notification type: notification
- -
Now I will assign this reminder to all day event Now I will assign this reminder to all day event
- -

View File

@ -84,9 +84,12 @@
idval = '%d-%s' % (ref('calendar_event_sprintreview0'), '20110425124700') idval = '%d-%s' % (ref('calendar_event_sprintreview0'), '20110425124700')
self.write(cr, uid, [idval], {'description': 'Review code of the module: sync_google_calendar.'}) self.write(cr, uid, [idval], {'description': 'Review code of the module: sync_google_calendar.'})
- -
I check whether the record is edited perfectly or not. I check whether that all the records of this recurrence has been edited.
- -
!python {model: calendar.event}: | !python {model: calendar.event}: |
meeting_ids = self.search(cr, uid, [('recurrent_id', '=', ref('calendar_event_sprintreview0')), ('recurrent_id_date','=','2011-04-25 12:47:00')], context) meeting_ids = self.search(cr, uid, [('recurrent_id', '=', ref('calendar_event_sprintreview0'))], context)
assert meeting_ids, 'Meeting is not edited !' meetings = self.browse(cr, uid, meeting_ids, context)
for meeting in meetings:
assert meeting.description == 'Review code of the module: sync_google_calendar.', 'Description not changed for id: %s' %meeting.id

View File

@ -7,6 +7,7 @@
# it under the terms of the GNU Affero General Public License as # it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the # published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version. # License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
@ -36,6 +37,168 @@ from dateutil import parser
import pytz import pytz
from openerp.osv import fields, osv from openerp.osv import fields, osv
from openerp.osv import osv from openerp.osv import osv
from collections import namedtuple
import logging
_logger = logging.getLogger(__name__)
class Meta(type):
""" This Meta class allow to define class as a structure, and so instancied variable
in __init__ to avoid to have side effect alike 'static' variable """
def __new__(typ, name, parents, attrs):
methods = dict((k, v) for k, v in attrs.iteritems()
if callable(v))
attrs = dict((k, v) for k, v in attrs.iteritems()
if not callable(v))
def init(self, **kw):
for k, v in attrs.iteritems():
setattr(self, k, v)
for k, v in kw.iteritems():
assert k in attrs
setattr(self, k, v)
methods['__init__'] = init
methods['__getitem__'] = getattr
return type.__new__(typ, name, parents, methods)
class Struct(object):
__metaclass__ = Meta
class OpenerpEvent(Struct):
event = False
found = False
event_id = False
isRecurrence = False
isInstance = False
update = False
status = False
attendee_id = False
synchro = False
class GmailEvent(Struct):
event = False
found = False
isRecurrence = False
isInstance = False
update = False
status = False
class SyncEvent(object):
def __init__(self):
self.OE = OpenerpEvent()
self.GG = GmailEvent()
self.OP = None
def __getitem__(self, key):
return getattr(self,key)
def compute_OP(self):
#If event are already in Gmail and in OpenERP
if self.OE.found and self.GG.found:
#If the event has been deleted from one side, we delete on other side !
if self.OE.status != self.GG.status:
self.OP = Delete((self.OE.status and "OE") or (self.GG.status and "GG"),
'The event has been deleted from one side, we delete on other side !' )
#If event is not deleted !
elif self.OE.status and self.GG.status:
if self.OE.update.split('.')[0] != self.GG.update.split('.')[0]:
if self.OE.update < self.GG.update:
tmpSrc = 'GG'
elif self.OE.update > self.GG.update:
tmpSrc = 'OE'
assert tmpSrc in ['GG','OE']
#if self.OP.action == None:
if self[tmpSrc].isRecurrence:
if self[tmpSrc].status:
self.OP = Update(tmpSrc, 'Only need to update, because i\'m active')
else:
self.OP = Exclude(tmpSrc, 'Need to Exclude (Me = First event from recurrence) from recurrence')
elif self[tmpSrc].isInstance:
self.OP= Update(tmpSrc, 'Only need to update, because already an exclu');
else:
self.OP = Update(tmpSrc, 'Simply Update... I\'m a single event');
#end-if self.OP.action == None:
else:
if not self.OE.synchro or self.OE.synchro.split('.')[0] < self.OE.update.split('.')[0]:
self.OP = Update('OE','Event already updated by another user, but not synchro with my google calendar')
#import ipdb; ipdb.set_trace();
else:
self.OP = NothingToDo("",'Not update needed')
else:
self.OP = NothingToDo("", "Both are already deleted");
# New in openERP... Create on create_events of synchronize function
elif self.OE.found and not self.GG.found:
#Has been deleted from gmail
if self.OE.status:
self.OP = Delete('OE', 'Removed from GOOGLE')
else:
self.OP = NothingToDo("","Already Deleted in gmail and unlinked in OpenERP")
elif self.GG.found and not self.OE.found:
tmpSrc = 'GG'
if not self.GG.status and not self.GG.isInstance:
# don't need to make something... because event has been created and deleted before the synchronization
self.OP = NothingToDo("", 'Nothing to do... Create and Delete directly')
else:
if self.GG.isInstance:
if self[tmpSrc].status:
self.OP = Exclude(tmpSrc, 'Need to create the new exclu')
else:
self.OP = Exclude(tmpSrc, 'Need to copy and Exclude')
else:
self.OP = Create(tmpSrc, 'New EVENT CREATE from GMAIL')
def __str__(self):
return self.__repr__()
def __repr__(self):
myPrint = "---- A SYNC EVENT ---"
myPrint += "\n ID OE: %s " % (self.OE.event and self.OE.event.id)
myPrint += "\n ID GG: %s " % (self.GG.event and self.GG.event.get('id', False))
myPrint += "\n Name OE: %s " % (self.OE.event and self.OE.event.name)
myPrint += "\n Name GG: %s " % (self.GG.event and self.GG.event.get('summary', False))
myPrint += "\n Found OE:%5s vs GG: %5s" % (self.OE.found, self.GG.found)
myPrint += "\n Recurrence OE:%5s vs GG: %5s" % (self.OE.isRecurrence, self.GG.isRecurrence)
myPrint += "\n Instance OE:%5s vs GG: %5s" % (self.OE.isInstance, self.GG.isInstance)
myPrint += "\n Synchro OE: %10s " % (self.OE.synchro)
myPrint += "\n Update OE: %10s " % (self.OE.update)
myPrint += "\n Update GG: %10s " % (self.GG.update)
myPrint += "\n Status OE:%5s vs GG: %5s" % (self.OE.status, self.GG.status)
if (self.OP is None):
myPrint += "\n Action %s" % "---!!!---NONE---!!!---"
else:
myPrint += "\n Action %s" % type(self.OP).__name__
myPrint += "\n Source %s" % (self.OP.src)
myPrint += "\n comment %s" % (self.OP.info)
return myPrint
class SyncOperation(object):
def __init__(self, src,info, **kw):
self.src = src
self.info = info
for k,v in kw.items():
setattr(self,k,v)
def __str__(self):
return 'in__STR__'
class Create(SyncOperation):
pass
class Update(SyncOperation):
pass
class Delete(SyncOperation):
pass
class NothingToDo(SyncOperation):
pass
class Exclude(SyncOperation):
pass
class google_calendar(osv.AbstractModel): class google_calendar(osv.AbstractModel):
@ -47,10 +210,12 @@ class google_calendar(osv.AbstractModel):
start_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.date, tools.DEFAULT_SERVER_DATETIME_FORMAT) , context=context).isoformat('T').split('T')[0] start_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.date, tools.DEFAULT_SERVER_DATETIME_FORMAT) , context=context).isoformat('T').split('T')[0]
end_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.date, tools.DEFAULT_SERVER_DATETIME_FORMAT) + timedelta(hours=event.duration), context=context).isoformat('T').split('T')[0] end_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.date, tools.DEFAULT_SERVER_DATETIME_FORMAT) + timedelta(hours=event.duration), context=context).isoformat('T').split('T')[0]
type = 'date' type = 'date'
vstype = 'dateTime'
else: else:
start_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.date, tools.DEFAULT_SERVER_DATETIME_FORMAT), context=context).isoformat('T') start_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.date, tools.DEFAULT_SERVER_DATETIME_FORMAT), context=context).isoformat('T')
end_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.date_deadline, tools.DEFAULT_SERVER_DATETIME_FORMAT), context=context).isoformat('T') end_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.date_deadline, tools.DEFAULT_SERVER_DATETIME_FORMAT), context=context).isoformat('T')
type = 'dateTime' type = 'dateTime'
vstype = 'date'
attendee_list = [] attendee_list = []
for attendee in event.attendee_ids: for attendee in event.attendee_ids:
@ -64,10 +229,12 @@ class google_calendar(osv.AbstractModel):
"description": event.description or '', "description": event.description or '',
"start":{ "start":{
type:start_date, type:start_date,
vstype:None,
'timeZone':'UTC' 'timeZone':'UTC'
}, },
"end":{ "end":{
type:end_date, type:end_date,
vstype:None,
'timeZone':'UTC' 'timeZone':'UTC'
}, },
"attendees":attendee_list, "attendees":attendee_list,
@ -80,10 +247,13 @@ class google_calendar(osv.AbstractModel):
if not event.active: if not event.active:
data["state"] = "cancelled" data["state"] = "cancelled"
if not self.get_need_synchro_attendee(cr,uid,context=context):
data.pop("attendees")
return data return data
def create_an_event(self, cr, uid,event, context=None): def create_an_event(self, cr, uid,event, context=None):
gs_pool = self.pool.get('google.service') gs_pool = self.pool['google.service']
data = self.generate_data(cr, uid,event, context=context) data = self.generate_data(cr, uid,event, context=context)
@ -94,7 +264,7 @@ class google_calendar(osv.AbstractModel):
return gs_pool._do_request(cr, uid, url, data_json, headers, type='POST', context=context) return gs_pool._do_request(cr, uid, url, data_json, headers, type='POST', context=context)
def delete_an_event(self, cr, uid,event_id, context=None): def delete_an_event(self, cr, uid,event_id, context=None):
gs_pool = self.pool.get('google.service') gs_pool = self.pool['google.service']
params = { params = {
'access_token' : self.get_token(cr,uid,context) 'access_token' : self.get_token(cr,uid,context)
@ -108,12 +278,14 @@ class google_calendar(osv.AbstractModel):
if not token: if not token:
token = self.get_token(cr,uid,context) token = self.get_token(cr,uid,context)
gs_pool = self.pool.get('google.service') gs_pool = self.pool['google.service']
params = { params = {
'fields': 'items,nextPageToken', 'fields': 'items,nextPageToken',
'access_token' : token, 'access_token' : token,
'maxResults':1000 'maxResults':1000,
'timeMin': self.get_start_time_to_synchro(cr,uid,context=context).strftime("%Y-%m-%dT%H:%M:%S.%fz"),
} }
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'} headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
@ -134,7 +306,7 @@ class google_calendar(osv.AbstractModel):
def update_to_google(self, cr, uid, oe_event, google_event, context): def update_to_google(self, cr, uid, oe_event, google_event, context):
calendar_event = self.pool['calendar.event'] calendar_event = self.pool['calendar.event']
gs_pool = self.pool.get('google.service') gs_pool = self.pool['google.service']
url = "/calendar/v3/calendars/%s/events/%s?fields=%s&access_token=%s" % ('primary', google_event['id'],'id,updated', self.get_token(cr,uid,context)) url = "/calendar/v3/calendars/%s/events/%s?fields=%s&access_token=%s" % ('primary', google_event['id'],'id,updated', self.get_token(cr,uid,context))
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'} headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
@ -148,10 +320,10 @@ class google_calendar(osv.AbstractModel):
calendar_event.write(cr, uid, [oe_event.id], {'oe_update_date':update_date}) calendar_event.write(cr, uid, [oe_event.id], {'oe_update_date':update_date})
if context['curr_attendee']: if context['curr_attendee']:
self.pool.get('calendar.attendee').write(cr,uid,[context['curr_attendee']], {'oe_synchro_date':update_date},context) self.pool['calendar.attendee'].write(cr,uid,[context['curr_attendee']], {'oe_synchro_date':update_date},context)
def update_an_event(self, cr, uid,event, context=None): def update_an_event(self, cr, uid,event, context=None):
gs_pool = self.pool.get('google.service') gs_pool = self.pool['google.service']
data = self.generate_data(cr, uid,event, context=context) data = self.generate_data(cr, uid,event, context=context)
@ -164,7 +336,7 @@ class google_calendar(osv.AbstractModel):
return response return response
def update_recurrent_event_exclu(self, cr, uid,instance_id,event_ori_google_id,event_new, context=None): def update_recurrent_event_exclu(self, cr, uid,instance_id,event_ori_google_id,event_new, context=None):
gs_pool = self.pool.get('google.service') gs_pool = self.pool['google.service']
data = self.generate_data(cr, uid,event_new, context=context) data = self.generate_data(cr, uid,event_new, context=context)
@ -186,7 +358,7 @@ class google_calendar(osv.AbstractModel):
calendar_event = self.pool['calendar.event'] calendar_event = self.pool['calendar.event']
res_partner_obj = self.pool['res.partner'] res_partner_obj = self.pool['res.partner']
calendar_attendee_obj = self.pool['calendar.attendee'] calendar_attendee_obj = self.pool['calendar.attendee']
user_obj = self.pool.get('res.users') user_obj = self.pool['res.users']
myPartnerID = user_obj.browse(cr,uid,uid,context).partner_id.id myPartnerID = user_obj.browse(cr,uid,uid,context).partner_id.id
attendee_record = [] attendee_record = []
partner_record = [(4,myPartnerID)] partner_record = [(4,myPartnerID)]
@ -203,14 +375,16 @@ class google_calendar(osv.AbstractModel):
if google_attendee.get('found',False): if google_attendee.get('found',False):
continue continue
if self.get_need_synchro_attendee(cr,uid,context=context):
attendee_id = res_partner_obj.search(cr, uid,[('email', '=', google_attendee['email'])], context=context) attendee_id = res_partner_obj.search(cr, uid,[('email', '=', google_attendee['email'])], context=context)
if not attendee_id: if not attendee_id:
attendee_id = [res_partner_obj.create(cr, uid,{'email': google_attendee['email'],'Customer': False, 'name': google_attendee.get("displayName",False) or google_attendee['email'] }, context=context)] attendee_id = [res_partner_obj.create(cr, uid,{'email': google_attendee['email'],'customer': False, 'name': google_attendee.get("displayName",False) or google_attendee['email'] }, context=context)]
attendee = res_partner_obj.read(cr, uid, attendee_id[0], ['email'], context=context) attendee = res_partner_obj.read(cr, uid, attendee_id[0], ['email'], context=context)
partner_record.append((4, attendee.get('id'))) partner_record.append((4, attendee.get('id')))
attendee['partner_id'] = attendee.pop('id') attendee['partner_id'] = attendee.pop('id')
attendee['state'] = google_attendee['responseStatus'] attendee['state'] = google_attendee['responseStatus']
attendee_record.append((0, 0, attendee)) attendee_record.append((0, 0, attendee))
UTC = pytz.timezone('UTC') UTC = pytz.timezone('UTC')
if single_event_dict.get('start') and single_event_dict.get('end'): # If not cancelled if single_event_dict.get('start') and single_event_dict.get('end'): # If not cancelled
if single_event_dict['start'].get('dateTime',False) and single_event_dict['end'].get('dateTime',False): if single_event_dict['start'].get('dateTime',False) and single_event_dict['end'].get('dateTime',False):
@ -261,16 +435,17 @@ class google_calendar(osv.AbstractModel):
res = calendar_event.create(cr, uid, result, context=context) res = calendar_event.create(cr, uid, result, context=context)
if context['curr_attendee']: if context['curr_attendee']:
self.pool.get('calendar.attendee').write(cr,uid,[context['curr_attendee']], {'oe_synchro_date':update_date,'google_internal_event_id': single_event_dict.get('id',False)},context) self.pool['calendar.attendee'].write(cr,uid,[context['curr_attendee']], {'oe_synchro_date':update_date,'google_internal_event_id': single_event_dict.get('id',False)},context)
return res return res
def synchronize_events(self, cr, uid, ids, context=None): def synchronize_events(self, cr, uid, ids, context=None):
gc_obj = self.pool.get('google.calendar') gc_obj = self.pool['google.calendar']
# Create all new events from OpenERP into Gmail, if that is not recurrent event
self.create_new_events(cr, uid, context=context) self.create_new_events(cr, uid, context=context)
self.bind_recurring_events_to_google(cr, uid, context) self.bind_recurring_events_to_google(cr, uid, context)
cr.commit()
res = self.update_events(cr, uid, context) res = self.update_events(cr, uid, context)
@ -279,10 +454,9 @@ class google_calendar(osv.AbstractModel):
"url" : '' "url" : ''
} }
def create_new_events(self, cr, uid, context): def create_new_events(self, cr, uid, context=None):
gc_pool = self.pool.get('google.calendar') gc_pool = self.pool['google.calendar']
ev_obj = self.pool['calendar.event']
calendar_event = self.pool['calendar.event']
att_obj = self.pool['calendar.attendee'] att_obj = self.pool['calendar.attendee']
user_obj = self.pool['res.users'] user_obj = self.pool['res.users']
myPartnerID = user_obj.browse(cr,uid,uid,context=context).partner_id.id myPartnerID = user_obj.browse(cr,uid,uid,context=context).partner_id.id
@ -290,58 +464,52 @@ class google_calendar(osv.AbstractModel):
context_norecurrent = context.copy() context_norecurrent = context.copy()
context_norecurrent['virtual_id'] = False context_norecurrent['virtual_id'] = False
my_att_ids = att_obj.search(cr, uid,[('partner_id', '=', myPartnerID),('google_internal_event_id', '=', False)], context=context_norecurrent) my_att_ids = att_obj.search(cr, uid,[ ('partner_id', '=', myPartnerID),
('google_internal_event_id', '=', False),
'|',
('event_id.date_deadline','>',self.get_start_time_to_synchro(cr,uid,context).strftime("%Y-%m-%d %H:%M:%S")),
('event_id.end_date','>',self.get_start_time_to_synchro(cr,uid,context).strftime("%Y-%m-%d %H:%M:%S")),
], context=context_norecurrent)
for att in att_obj.browse(cr,uid,my_att_ids,context=context): for att in att_obj.browse(cr,uid,my_att_ids,context=context):
if not att.event_id.recurrent_id or att.event_id.recurrent_id == 0: if not att.event_id.recurrent_id or att.event_id.recurrent_id == 0:
response = self.create_an_event(cr,uid,att.event_id,context=context) response = self.create_an_event(cr,uid,att.event_id,context=context)
update_date = datetime.strptime(response['updated'],"%Y-%m-%dT%H:%M:%S.%fz") update_date = datetime.strptime(response['updated'],"%Y-%m-%dT%H:%M:%S.%fz")
calendar_event.write(cr, uid, att.event_id.id, {'oe_update_date':update_date}) ev_obj.write(cr, uid, att.event_id.id, {'oe_update_date':update_date})
att_obj.write(cr, uid, [att.id], {'google_internal_event_id': response['id'], 'oe_synchro_date':update_date}) att_obj.write(cr, uid, [att.id], {'google_internal_event_id': response['id'], 'oe_synchro_date':update_date})
cr.commit() cr.commit()
return True
def get_empty_synchro_summarize(self) : def bind_recurring_events_to_google(self, cr, uid, context):
return { ev_obj = self.pool['calendar.event']
#OPENERP att_obj = self.pool['calendar.attendee']
'OE_event' : False, user_obj = self.pool['res.users']
'OE_found' : False, myPartnerID = user_obj.browse(cr,uid,uid,context=context).partner_id.id
'OE_event_id' : False,
'OE_isRecurrence':False,
'OE_isInstance':False,
'OE_update':False,
'OE_status':False,
'OE_attendee_id': False,
'OE_synchro':False,
#GOOGLE context_norecurrent = context.copy()
'GG_event' : False, context_norecurrent['virtual_id'] = False
'GG_found' : False, context_norecurrent['active_test'] = False
'GG_isRecurrence':False,
'GG_isInstance':False,
'GG_update':False,
'GG_status':False,
#TO_DO_IN_GOOGLE my_att_ids = att_obj.search(cr, uid,[('partner_id', '=', myPartnerID),('google_internal_event_id', '=', False)], context=context_norecurrent)
'td_action':'', # create, update, delete, None
#If 'td_action' in (create , update),
# If td_source == OE
# We create in google the event based on OpenERP
# If td_source == GG
# We create in OpenERP the event based on Gmail
#
#If 'td_action' in (delete),
# If td_source == OE
# We delete in OpenERP the event
# If td_source == GG
# We delete in Gmail the event
# If td_source == ALL
# We delete in openERP AND in Gmail the event
'td_source': '', # OE, GG, ALL
'td_comment':''
} for att in att_obj.browse(cr,uid,my_att_ids,context=context):
if att.event_id.recurrent_id and att.event_id.recurrent_id > 0:
new_google_internal_event_id = False
source_event_record = ev_obj.browse(cr, uid, att.event_id.recurrent_id, context)
source_attendee_record_id = att_obj.search(cr, uid, [('partner_id','=', myPartnerID), ('event_id','=',source_event_record.id)], context=context)
source_attendee_record = att_obj.browse(cr, uid, source_attendee_record_id, context)[0]
def update_events(self, cr, uid, context): if att.event_id.recurrent_id_date and source_event_record.allday and source_attendee_record.google_internal_event_id:
new_google_internal_event_id = source_attendee_record.google_internal_event_id +'_'+ att.event_id.recurrent_id_date.split(' ')[0].replace('-','')
elif att.event_id.recurrent_id_date and source_attendee_record.google_internal_event_id:
new_google_internal_event_id = source_attendee_record.google_internal_event_id +'_'+ att.event_id.recurrent_id_date.replace('-','').replace(' ','T').replace(':','') + 'Z'
if new_google_internal_event_id:
#TODO WARNING, NEED TO CHECK THAT EVENT and ALL instance NOT DELETE IN GMAIL BEFORE !
res = self.update_recurrent_event_exclu(cr, uid,new_google_internal_event_id, source_attendee_record.google_internal_event_id,att.event_id, context=context)
att_obj.write(cr, uid, [att.id], {'google_internal_event_id': new_google_internal_event_id}, context=context)
cr.commit()
def update_events(self, cr, uid, context=None):
if context is None: if context is None:
context = {} context = {}
@ -355,10 +523,14 @@ class google_calendar(osv.AbstractModel):
context_novirtual['active_test'] = False context_novirtual['active_test'] = False
all_event_from_google = self.get_event_dict(cr, uid, context=context) all_event_from_google = self.get_event_dict(cr, uid, context=context)
all_new_event_from_google = all_event_from_google.copy()
# Select all events from OpenERP which have been already synchronized in gmail # Select all events from OpenERP which have been already synchronized in gmail
my_att_ids = att_obj.search(cr, uid,[('partner_id', '=', myPartnerID),('google_internal_event_id', '!=', False)], context=context_novirtual) my_att_ids = att_obj.search(cr, uid,[ ('partner_id', '=', myPartnerID),
('google_internal_event_id', '!=', False),
'|',
('event_id.date_deadline','>',self.get_start_time_to_synchro(cr,uid,context).strftime("%Y-%m-%d %H:%M:%S")),
('event_id.end_date','>',self.get_start_time_to_synchro(cr,uid,context).strftime("%Y-%m-%d %H:%M:%S")),
], context=context_novirtual)
event_to_synchronize = {} event_to_synchronize = {}
for att in att_obj.browse(cr,uid,my_att_ids,context=context): for att in att_obj.browse(cr,uid,my_att_ids,context=context):
event = att.event_id event = att.event_id
@ -369,18 +541,19 @@ class google_calendar(osv.AbstractModel):
event_to_synchronize[base_event_id] = {} event_to_synchronize[base_event_id] = {}
if att.google_internal_event_id not in event_to_synchronize[base_event_id]: if att.google_internal_event_id not in event_to_synchronize[base_event_id]:
event_to_synchronize[base_event_id][att.google_internal_event_id] = self.get_empty_synchro_summarize() event_to_synchronize[base_event_id][att.google_internal_event_id] = SyncEvent()
event_to_synchronize[base_event_id][att.google_internal_event_id]['OE_attendee_id'] = att.id ev_to_sync = event_to_synchronize[base_event_id][att.google_internal_event_id]
event_to_synchronize[base_event_id][att.google_internal_event_id]['OE_event'] = event
event_to_synchronize[base_event_id][att.google_internal_event_id]['OE_found'] = True
event_to_synchronize[base_event_id][att.google_internal_event_id]['OE_event_id'] = event.id
event_to_synchronize[base_event_id][att.google_internal_event_id]['OE_isRecurrence'] = event.recurrency
event_to_synchronize[base_event_id][att.google_internal_event_id]['OE_isInstance'] = bool(event.recurrent_id and event.recurrent_id > 0)
event_to_synchronize[base_event_id][att.google_internal_event_id]['OE_update'] = event.oe_update_date
event_to_synchronize[base_event_id][att.google_internal_event_id]['OE_status'] = event.active
event_to_synchronize[base_event_id][att.google_internal_event_id]['OE_synchro'] = att.oe_synchro_date
ev_to_sync.OE.attendee_id = att.id
ev_to_sync.OE.event = event
ev_to_sync.OE.found = True
ev_to_sync.OE.event_id = event.id
ev_to_sync.OE.isRecurrence = event.recurrency
ev_to_sync.OE.isInstance = bool(event.recurrent_id and event.recurrent_id > 0)
ev_to_sync.OE.update = event.oe_update_date
ev_to_sync.OE.status = event.active
ev_to_sync.OE.synchro = att.oe_synchro_date
for event in all_event_from_google.values(): for event in all_event_from_google.values():
event_id = event.get('id') event_id = event.get('id')
@ -390,97 +563,27 @@ class google_calendar(osv.AbstractModel):
event_to_synchronize[base_event_id] = {} event_to_synchronize[base_event_id] = {}
if event_id not in event_to_synchronize[base_event_id]: if event_id not in event_to_synchronize[base_event_id]:
event_to_synchronize[base_event_id][event_id] = self.get_empty_synchro_summarize() event_to_synchronize[base_event_id][event_id] = SyncEvent()
event_to_synchronize[base_event_id][event_id]['GG_event'] = event ev_to_sync = event_to_synchronize[base_event_id][event_id]
event_to_synchronize[base_event_id][event_id]['GG_found'] = True
event_to_synchronize[base_event_id][event_id]['GG_isRecurrence'] = bool(event.get('recurrence',''))
event_to_synchronize[base_event_id][event_id]['GG_isInstance'] = bool(event.get('recurringEventId',0))
event_to_synchronize[base_event_id][event_id]['GG_update'] = event.get('updated',None) # if deleted, no date without browse event
if event_to_synchronize[base_event_id][event_id]['GG_update']:
event_to_synchronize[base_event_id][event_id]['GG_update'] =event_to_synchronize[base_event_id][event_id]['GG_update'].replace('T',' ').replace('Z','')
event_to_synchronize[base_event_id][event_id]['GG_status'] = (event.get('status') != 'cancelled')
ev_to_sync.GG.event = event
ev_to_sync.GG.found = True
ev_to_sync.GG.isRecurrence = bool(event.get('recurrence',''))
ev_to_sync.GG.isInstance = bool(event.get('recurringEventId',0))
ev_to_sync.GG.update = event.get('updated',None) # if deleted, no date without browse event
if ev_to_sync.GG.update:
ev_to_sync.GG.update = ev_to_sync.GG.update.replace('T',' ').replace('Z','')
ev_to_sync.GG.status = (event.get('status') != 'cancelled')
###################### ######################
# PRE-PROCESSING # # PRE-PROCESSING #
###################### ######################
for base_event in event_to_synchronize: for base_event in event_to_synchronize:
for current_event in event_to_synchronize[base_event]: for current_event in event_to_synchronize[base_event]:
event = event_to_synchronize[base_event][current_event] event_to_synchronize[base_event][current_event].compute_OP()
#print event_to_synchronize[base_event]
#If event are already in Gmail and in OpenERP #print "========================================================"
if event['OE_found'] and event['GG_found']:
#If the event has been deleted from one side, we delete on other side !
if event['OE_status'] != event['GG_status']:
event['td_action'] = "DELETE"
event['td_source'] = (event['OE_status'] and "OE") or (event['GG_status'] and "GG")
#If event is not deleted !
elif event['OE_status'] and event['GG_status']:
if event['OE_update'].split('.')[0] != event['GG_update'].split('.')[0]:
if event['OE_update'] < event['GG_update']:
event['td_source'] = 'GG'
elif event['OE_update'] > event['GG_update']:
event['td_source'] = 'OE'
if event['td_action'] != "None":
if event['%s_isRecurrence' % event['td_source']]:
if event['%s_status' % event['td_source']]:
event['td_action'] = "UPDATE"
event['td_comment'] = 'Only need to update, because i\'m active'
else:
event['td_action'] = "EXCLUDE"
event['td_comment'] = 'Need to Exclude (Me = First event from recurrence) from recurrence'
elif event['%s_isInstance' % event['td_source']]:
event['td_action'] = "UPDATE"
event['td_comment'] = 'Only need to update, because already an exclu'
else:
event['td_action'] = "UPDATE"
event['td_comment'] = 'Simply Update... I\'m a single event'
else:
if not event['OE_synchro'] or event['OE_synchro'].split('.')[0] < event['OE_update'].split('.')[0]:
event['td_source'] = 'OE'
event['td_action'] = "UPDATE"
event['td_comment'] = 'Event already updated by another user, but not synchro with my google calendar'
else:
event['td_action'] = "None"
event['td_comment'] = 'Not update needed'
else:
event['td_action'] = "None"
event['td_comment'] = "Both are already deleted"
# New in openERP... Create on create_events of synchronize function
elif event['OE_found'] and not event['GG_found']:
#Has been deleted from gmail
if event['OE_status']:
event['td_source'] = 'OE'
event['td_action'] = 'DELETE'
event['td_comment'] = 'Removed from GOOGLE ?'
else:
event['td_action'] = "None"
event['td_comment'] = "Already Deleted in gmail and unlinked in OpenERP"
elif event['GG_found'] and not event['OE_found']:
event['td_source'] = 'GG'
if not event['GG_status'] and not event['GG_isInstance']:
# don't need to make something... because event has been created and deleted before the synchronization
event['td_action'] = 'None'
event['td_comment'] = 'Nothing to do... Create and Delete directly'
else:
if event['GG_isInstance']:
if event['%s_status' % event['td_source']]:
event['td_action'] = "EXCLUDE"
event['td_comment'] = 'Need to create the new exclu'
else:
event['td_action'] = "EXCLUDE"
event['td_comment'] = 'Need to copy and Exclude'
else:
event['td_action'] = "CREATE"
event['td_comment'] = 'New EVENT CREATE from GMAIL'
###################### ######################
# DO ACTION # # DO ACTION #
@ -489,104 +592,61 @@ class google_calendar(osv.AbstractModel):
event_to_synchronize[base_event] = sorted(event_to_synchronize[base_event].iteritems(),key=operator.itemgetter(0)) event_to_synchronize[base_event] = sorted(event_to_synchronize[base_event].iteritems(),key=operator.itemgetter(0))
for current_event in event_to_synchronize[base_event]: for current_event in event_to_synchronize[base_event]:
cr.commit() cr.commit()
event = current_event[1] event = current_event[1] # event is an Sync Event !
#############
### DEBUG ###
#############
# if event['td_action'] and event['td_action'] != 'None':
# print " Real Event %s (%s)" % (current_event[0],event['OE_event_id'])
# print " Found OE:%5s vs GG: %5s" % (event['OE_found'],event['GG_found'])
# print " Recurrence OE:%5s vs GG: %5s" % (event['OE_isRecurrence'],event['GG_isRecurrence'])
# print " Instance OE:%5s vs GG: %5s" % (event['OE_isInstance'],event['GG_isInstance'])
# print " Synchro OE: %10s " % (event['OE_synchro'])
# print " Update OE: %10s " % (event['OE_update'])
# print " Update GG: %10s " % (event['GG_update'])
# print " Status OE:%5s vs GG: %5s" % (event['OE_status'],event['GG_status'])
# print " Action %s" % (event['td_action'])
# print " Source %s" % (event['td_source'])
# print " comment %s" % (event['td_comment'])
context['curr_attendee'] = event.get('OE_attendee_id',False) actToDo = event.OP
actSrc = event.OP.src
actToDo = event['td_action'] # if not isinstance(actToDo, NothingToDo):
actSrc = event['td_source'] # print event
if not actToDo:
raise ("#!? WHAT I NEED TO DO ????") context['curr_attendee'] = event.OE.attendee_id
else:
if actToDo == 'None': if isinstance(actToDo, NothingToDo):
continue continue
elif actToDo == 'CREATE': elif isinstance(actToDo, Create):
context_tmp = context.copy() context_tmp = context.copy()
context_tmp['NewMeeting'] = True context_tmp['NewMeeting'] = True
if actSrc == 'GG': if actSrc == 'GG':
res = self.update_from_google(cr, uid, False, event['GG_event'], "create", context=context_tmp) res = self.update_from_google(cr, uid, False, event.GG.event, "create", context=context_tmp)
event['OE_event_id'] = res event.OE.event_id = res
meeting = calendar_event.browse(cr,uid,res,context=context) meeting = calendar_event.browse(cr,uid,res,context=context)
attendee_record_id = att_obj.search(cr, uid, [('partner_id','=', myPartnerID), ('event_id','=',res)], context=context) attendee_record_id = att_obj.search(cr, uid, [('partner_id','=', myPartnerID), ('event_id','=',res)], context=context)
self.pool.get('calendar.attendee').write(cr,uid,attendee_record_id, {'oe_synchro_date':meeting.oe_update_date,'google_internal_event_id': event['GG_event']['id']},context=context_tmp) self.pool['calendar.attendee'].write(cr, uid, attendee_record_id, {'oe_synchro_date':meeting.oe_update_date, 'google_internal_event_id':event.GG.event['id']}, context=context_tmp)
elif actSrc == 'OE': elif actSrc == 'OE':
raise "Should be never here, creation for OE is done before update !" raise "Should be never here, creation for OE is done before update !"
#TODO Add to batch #TODO Add to batch
elif actToDo == 'UPDATE': elif isinstance(actToDo, Update):
if actSrc == 'GG': if actSrc == 'GG':
self.update_from_google(cr, uid, event['OE_event'], event['GG_event'], 'write', context) self.update_from_google(cr, uid, event.OE.event, event.GG.event, 'write', context)
elif actSrc == 'OE': elif actSrc == 'OE':
self.update_to_google(cr, uid, event['OE_event'], event['GG_event'], context) self.update_to_google(cr, uid, event.OE.event, event.GG.event, context)
elif actToDo == 'EXCLUDE' : elif isinstance(actToDo, Exclude):
if actSrc == 'OE': if actSrc == 'OE':
self.delete_an_event(cr,uid,current_event[0],context=context) self.delete_an_event(cr,uid,current_event[0],context=context)
elif actSrc == 'GG': elif actSrc == 'GG':
new_google_event_id = event['GG_event']['id'].split('_')[1] new_google_event_id = event.GG.event['id'].split('_')[1]
if 'T' in new_google_event_id: if 'T' in new_google_event_id:
new_google_event_id = new_google_event_id.replace('T','')[:-1] new_google_event_id = new_google_event_id.replace('T','')[:-1]
else: else:
new_google_event_id = new_google_event_id + "000000" new_google_event_id = new_google_event_id + "000000"
if event['GG_status']: if event.GG.status:
parent_event = {} parent_event = {}
parent_event['id'] = "%s-%s" % (event_to_synchronize[base_event][0][1].get('OE_event_id') , new_google_event_id) parent_event['id'] = "%s-%s" % (event_to_synchronize[base_event][0][1].OE.event_id , new_google_event_id)
res = self.update_from_google(cr, uid, parent_event, event['GG_event'], "copy", context) res = self.update_from_google(cr, uid, parent_event, event.GG.event, "copy", context)
else: else:
if event_to_synchronize[base_event][0][1].get('OE_event_id'): if event_to_synchronize[base_event][0][1].OE.event_id:
parent_oe_id = event_to_synchronize[base_event][0][1].get('OE_event_id') parent_oe_id = event_to_synchronize[base_event][0][1].OE.event_id
calendar_event.unlink(cr,uid,"%s-%s" % (parent_oe_id,new_google_event_id),unlink_level=1,context=context) calendar_event.unlink(cr,uid,"%s-%s" % (parent_oe_id,new_google_event_id),unlink_level=1,context=context)
elif actToDo == 'DELETE': elif isinstance(actToDo, Delete):
if actSrc == 'GG': if actSrc == 'GG':
self.delete_an_event(cr,uid,current_event[0],context=context) self.delete_an_event(cr,uid,current_event[0],context=context)
elif actSrc == 'OE': elif actSrc == 'OE':
calendar_event.unlink(cr,uid,event['OE_event_id'],unlink_level=0,context=context) calendar_event.unlink(cr,uid,event.OE.event_id,unlink_level=0,context=context)
return True return True
def bind_recurring_events_to_google(self, cr, uid, context):
calendar_event = self.pool['calendar.event']
att_obj = self.pool.get('calendar.attendee')
user_obj = self.pool['res.users']
myPartnerID = user_obj.browse(cr,uid,uid,context=context).partner_id.id
context_norecurrent = context.copy()
context_norecurrent['virtual_id'] = False
context_norecurrent['active_test'] = False
my_att_ids = att_obj.search(cr, uid,[('partner_id', '=', myPartnerID),('google_internal_event_id', '=', False)], context=context_norecurrent)
for att in att_obj.browse(cr,uid,my_att_ids,context=context):
if att.event_id.recurrent_id and att.event_id.recurrent_id > 0:
new_google_internal_event_id = False
source_event_record = calendar_event.browse(cr, uid, att.event_id.recurrent_id, context)
source_attendee_record_id = att_obj.search(cr, uid, [('partner_id','=', myPartnerID), ('event_id','=',source_event_record.id)], context=context)
source_attendee_record = att_obj.browse(cr, uid, source_attendee_record_id, context)
if source_attendee_record:
source_attendee_record = source_attendee_record[0]
if att.event_id.recurrent_id_date and source_event_record.allday and source_attendee_record.google_internal_event_id:
new_google_internal_event_id = source_attendee_record.google_internal_event_id +'_'+ att.event_id.recurrent_id_date.split(' ')[0].replace('-','')
elif event.recurrent_id_date and source_attendee_record.google_internal_event_id:
new_google_internal_event_id = source_attendee_record.google_internal_event_id +'_'+ att.event_id.recurrent_id_date.replace('-','').replace(' ','T').replace(':','') + 'Z'
if new_google_internal_event_id:
#TODO WARNING, NEED TO CHECK THAT EVENT and ALL instance NOT DELETE IN GMAIL BEFORE !
res = self.update_recurrent_event_exclu(cr,uid,new_google_internal_event_id,source_attendee_record.google_internal_event_id,att.event_id,context=context)
att_obj.write(cr, uid, [att.id], {'google_internal_event_id': new_google_internal_event_id})
def check_and_sync(self, cr, uid, oe_event, google_event, context): def check_and_sync(self, cr, uid, oe_event, google_event, context):
if datetime.strptime(oe_event.oe_update_date,"%Y-%m-%d %H:%M:%S.%f") > datetime.strptime(google_event['updated'],"%Y-%m-%dT%H:%M:%S.%fz"): if datetime.strptime(oe_event.oe_update_date,"%Y-%m-%d %H:%M:%S.%f") > datetime.strptime(google_event['updated'],"%Y-%m-%dT%H:%M:%S.%fz"):
@ -595,7 +655,7 @@ class google_calendar(osv.AbstractModel):
self.update_from_google(cr, uid, oe_event, google_event, 'write', context) self.update_from_google(cr, uid, oe_event, google_event, 'write', context)
def get_sequence(self,cr,uid,instance_id,context=None): def get_sequence(self,cr,uid,instance_id,context=None):
gs_pool = self.pool.get('google.service') gs_pool = self.pool['google.service']
params = { params = {
'fields': 'sequence', 'fields': 'sequence',
@ -613,7 +673,7 @@ class google_calendar(osv.AbstractModel):
################################# #################################
def get_token(self,cr,uid,context=None): def get_token(self,cr,uid,context=None):
current_user = self.pool.get('res.users').browse(cr,uid,uid,context=context) current_user = self.pool['res.users'].browse(cr,uid,uid,context=context)
if datetime.strptime(current_user.google_calendar_token_validity.split('.')[0], "%Y-%m-%d %H:%M:%S") < (datetime.now() + timedelta(minutes=1)): if datetime.strptime(current_user.google_calendar_token_validity.split('.')[0], "%Y-%m-%d %H:%M:%S") < (datetime.now() + timedelta(minutes=1)):
self.do_refresh_token(cr,uid,context=context) self.do_refresh_token(cr,uid,context=context)
@ -622,8 +682,8 @@ class google_calendar(osv.AbstractModel):
return current_user.google_calendar_token return current_user.google_calendar_token
def do_refresh_token(self,cr,uid,context=None): def do_refresh_token(self,cr,uid,context=None):
current_user = self.pool.get('res.users').browse(cr,uid,uid,context=context) current_user = self.pool['res.users'].browse(cr,uid,uid,context=context)
gs_pool = self.pool.get('google.service') gs_pool = self.pool['google.service']
refresh = current_user.google_calendar_rtoken refresh = current_user.google_calendar_rtoken
all_token = gs_pool._refresh_google_token_json(cr, uid, current_user.google_calendar_rtoken, self.STR_SERVICE, context=context) all_token = gs_pool._refresh_google_token_json(cr, uid, current_user.google_calendar_rtoken, self.STR_SERVICE, context=context)
@ -632,10 +692,10 @@ class google_calendar(osv.AbstractModel):
vals['google_%s_token_validity' % self.STR_SERVICE] = datetime.now() + timedelta(seconds=all_token.get('expires_in')) vals['google_%s_token_validity' % self.STR_SERVICE] = datetime.now() + timedelta(seconds=all_token.get('expires_in'))
vals['google_%s_token' % self.STR_SERVICE] = all_token.get('access_token') vals['google_%s_token' % self.STR_SERVICE] = all_token.get('access_token')
self.pool.get('res.users').write(cr,SUPERUSER_ID,uid,vals,context=context) self.pool['res.users'].write(cr,SUPERUSER_ID,uid,vals,context=context)
def need_authorize(self,cr,uid,context=None): def need_authorize(self,cr,uid,context=None):
current_user = self.pool.get('res.users').browse(cr,uid,uid,context=context) current_user = self.pool['res.users'].browse(cr,uid,uid,context=context)
return current_user.google_calendar_rtoken == False return current_user.google_calendar_rtoken == False
def get_calendar_scope(self,RO=False): def get_calendar_scope(self,RO=False):
@ -643,22 +703,30 @@ class google_calendar(osv.AbstractModel):
return 'https://www.googleapis.com/auth/calendar%s' % (readonly) return 'https://www.googleapis.com/auth/calendar%s' % (readonly)
def authorize_google_uri(self,cr,uid,from_url='http://www.openerp.com',context=None): def authorize_google_uri(self,cr,uid,from_url='http://www.openerp.com',context=None):
url = self.pool.get('google.service')._get_authorize_uri(cr,uid,from_url,self.STR_SERVICE,scope=self.get_calendar_scope(),context=context) url = self.pool['google.service']._get_authorize_uri(cr,uid,from_url,self.STR_SERVICE,scope=self.get_calendar_scope(),context=context)
return url return url
def can_authorize_google(self,cr,uid,context=None): def can_authorize_google(self,cr,uid,context=None):
return self.pool['res.users'].has_group(cr, uid, 'base.group_erp_manager') return self.pool['res.users'].has_group(cr, uid, 'base.group_erp_manager')
def set_all_tokens(self,cr,uid,authorization_code,context=None): def set_all_tokens(self,cr,uid,authorization_code,context=None):
gs_pool = self.pool.get('google.service') gs_pool = self.pool['google.service']
all_token = gs_pool._get_google_token_json(cr, uid, authorization_code,self.STR_SERVICE,context=context) all_token = gs_pool._get_google_token_json(cr, uid, authorization_code,self.STR_SERVICE,context=context)
vals = {} vals = {}
vals['google_%s_rtoken' % self.STR_SERVICE] = all_token.get('refresh_token') vals['google_%s_rtoken' % self.STR_SERVICE] = all_token.get('refresh_token')
vals['google_%s_token_validity' % self.STR_SERVICE] = datetime.now() + timedelta(seconds=all_token.get('expires_in')) vals['google_%s_token_validity' % self.STR_SERVICE] = datetime.now() + timedelta(seconds=all_token.get('expires_in'))
vals['google_%s_token' % self.STR_SERVICE] = all_token.get('access_token') vals['google_%s_token' % self.STR_SERVICE] = all_token.get('access_token')
self.pool.get('res.users').write(cr,SUPERUSER_ID,uid,vals,context=context) self.pool['res.users'].write(cr,SUPERUSER_ID,uid,vals,context=context)
def get_start_time_to_synchro(self, cr, uid, context=None) :
# WILL BE AN IR CONFIG PARAMETER - beginning from SAAS4
number_of_week = 13
return datetime.now()-timedelta(weeks=number_of_week)
def get_need_synchro_attendee(self, cr, uid, context=None):
# WILL BE AN IR CONFIG PARAMETER - beginning from SAAS4
return True
class res_users(osv.Model): class res_users(osv.Model):
_inherit = 'res.users' _inherit = 'res.users'
@ -718,7 +786,6 @@ class calendar_attendee(osv.Model):
# If attendees are updated, we need to specify that next synchro need an action # If attendees are updated, we need to specify that next synchro need an action
# Except if it come from an update_from_google # Except if it come from an update_from_google
if not context.get('curr_attendee', False) and not context.get('NewMeeting', False): if not context.get('curr_attendee', False) and not context.get('NewMeeting', False):
self.pool.get('calendar.event').write(cr, uid, ref, {'oe_update_date':datetime.now()},context) self.pool['calendar.event'].write(cr, uid, ref, {'oe_update_date':datetime.now()},context)
return super(calendar_attendee, self).write(cr, uid, ids, vals, context=context) return super(calendar_attendee, self).write(cr, uid, ids, vals, context=context)