2014-05-14 08:28:10 +00:00
# -*- coding: utf-8 -*-
2013-12-02 14:31:33 +00:00
2013-12-10 16:45:25 +00:00
import operator
2013-12-02 14:31:33 +00:00
import simplejson
2014-05-14 08:28:10 +00:00
import urllib2
2013-12-02 14:31:33 +00:00
2014-05-14 08:28:10 +00:00
import openerp
2013-12-02 14:31:33 +00:00
from openerp import tools
2013-12-18 17:49:31 +00:00
from openerp import SUPERUSER_ID
2014-10-03 15:52:31 +00:00
from openerp . tools import DEFAULT_SERVER_DATE_FORMAT , DEFAULT_SERVER_DATETIME_FORMAT , exception_to_unicode
2014-05-14 08:28:10 +00:00
from openerp . tools . translate import _
from openerp . http import request
2014-02-24 22:02:22 +00:00
from datetime import datetime , timedelta
2013-12-09 14:08:19 +00:00
from dateutil import parser
import pytz
2013-12-02 14:31:33 +00:00
from openerp . osv import fields , osv
2014-02-18 17:15:08 +00:00
import logging
_logger = logging . getLogger ( __name__ )
2014-05-14 08:28:10 +00:00
def status_response ( status , substr = False ) :
if substr :
return int ( str ( status ) [ 0 ] )
else :
return status_response ( status , substr = True ) == 2
2014-02-18 17:15:08 +00:00
class Meta ( type ) :
2014-02-24 22:02:22 +00:00
""" This Meta class allow to define class as a structure, and so instancied variable
2014-02-18 17:15:08 +00:00
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 )
2014-02-24 22:02:22 +00:00
2014-02-18 17:15:08 +00:00
class Struct ( object ) :
__metaclass__ = Meta
2014-02-24 22:02:22 +00:00
2014-02-18 17:15:08 +00:00
class OpenerpEvent ( Struct ) :
event = False
found = False
event_id = False
isRecurrence = False
isInstance = False
update = False
status = False
attendee_id = False
synchro = False
2014-02-24 22:02:22 +00:00
2014-02-18 17:15:08 +00:00
class GmailEvent ( Struct ) :
event = False
found = False
isRecurrence = False
isInstance = False
update = False
status = False
2014-02-24 22:02:22 +00:00
2014-02-18 17:15:08 +00:00
class SyncEvent ( object ) :
def __init__ ( self ) :
self . OE = OpenerpEvent ( )
2014-02-24 22:02:22 +00:00
self . GG = GmailEvent ( )
2014-02-18 17:15:08 +00:00
self . OP = None
2014-02-24 22:02:22 +00:00
def __getitem__ ( self , key ) :
return getattr ( self , key )
2014-02-18 17:15:08 +00:00
2014-05-14 08:28:10 +00:00
def compute_OP ( self , modeFull = True ) :
2014-02-24 22:02:22 +00:00
#If event are already in Gmail and in OpenERP
2014-02-18 17:15:08 +00:00
if self . OE . found and self . GG . found :
2015-06-11 11:55:10 +00:00
is_owner = self . OE . event . env . user . id == self . OE . event . user_id . id
2014-02-18 17:15:08 +00:00
#If the event has been deleted from one side, we delete on other side !
2015-06-02 13:04:00 +00:00
if self . OE . status != self . GG . status and is_owner :
2014-02-18 17:15:08 +00:00
self . OP = Delete ( ( self . OE . status and " OE " ) or ( self . GG . status and " GG " ) ,
2014-02-24 22:02:22 +00:00
' The event has been deleted from one side, we delete on other side ! ' )
#If event is not deleted !
2015-06-02 13:04:00 +00:00
elif self . OE . status and ( self . GG . status or not is_owner ) :
2014-02-18 17:15:08 +00:00
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 '
2014-02-24 22:02:22 +00:00
assert tmpSrc in [ ' GG ' , ' OE ' ]
2014-02-18 17:15:08 +00:00
#if self.OP.action == None:
if self [ tmpSrc ] . isRecurrence :
if self [ tmpSrc ] . status :
2014-02-24 22:02:22 +00:00
self . OP = Update ( tmpSrc , ' Only need to update, because i \' m active ' )
2014-02-18 17:15:08 +00:00
else :
self . OP = Exclude ( tmpSrc , ' Need to Exclude (Me = First event from recurrence) from recurrence ' )
elif self [ tmpSrc ] . isInstance :
2014-02-24 22:02:22 +00:00
self . OP = Update ( tmpSrc , ' Only need to update, because already an exclu ' )
2014-02-18 17:15:08 +00:00
else :
2014-02-24 22:02:22 +00:00
self . OP = Update ( tmpSrc , ' Simply Update... I \' m a single event ' )
2014-02-18 17:15:08 +00:00
else :
if not self . OE . synchro or self . OE . synchro . split ( ' . ' ) [ 0 ] < self . OE . update . split ( ' . ' ) [ 0 ] :
2014-02-24 22:02:22 +00:00
self . OP = Update ( ' OE ' , ' Event already updated by another user, but not synchro with my google calendar ' )
2014-02-18 17:15:08 +00:00
else :
2014-02-24 22:02:22 +00:00
self . OP = NothingToDo ( " " , ' Not update needed ' )
2014-02-18 17:15:08 +00:00
else :
2014-02-24 22:02:22 +00:00
self . OP = NothingToDo ( " " , " Both are already deleted " )
2014-02-18 17:15:08 +00:00
# New in openERP... Create on create_events of synchronize function
elif self . OE . found and not self . GG . found :
if self . OE . status :
2014-05-14 08:28:10 +00:00
self . OP = Delete ( ' OE ' , ' Update or delete from GOOGLE ' )
2014-02-18 17:15:08 +00:00
else :
2014-05-14 08:28:10 +00:00
if not modeFull :
2014-07-09 11:39:38 +00:00
self . OP = Delete ( ' GG ' , ' Deleted from Odoo, need to delete it from Gmail if already created ' )
2014-05-14 08:28:10 +00:00
else :
2014-07-09 11:39:38 +00:00
self . OP = NothingToDo ( " " , " Already Deleted in gmail and unlinked in Odoo " )
2014-02-18 17:15:08 +00:00
elif self . GG . found and not self . OE . found :
tmpSrc = ' GG '
if not self . GG . status and not self . GG . isInstance :
2014-02-24 22:02:22 +00:00
# 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 ' )
2014-02-18 17:15:08 +00:00
else :
2014-02-24 22:02:22 +00:00
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 ' )
2014-02-18 17:15:08 +00:00
def __str__ ( self ) :
return self . __repr__ ( )
def __repr__ ( self ) :
2014-05-14 08:28:10 +00:00
myPrint = " \n \n ---- A SYNC EVENT --- "
2014-02-24 22:02:22 +00:00
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 ) )
2014-05-14 08:28:10 +00:00
myPrint + = " \n Name OE: %s " % ( self . OE . event and self . OE . event . name . encode ( ' utf8 ' ) )
myPrint + = " \n Name GG: %s " % ( self . GG . event and self . GG . event . get ( ' summary ' , ' ' ) . encode ( ' utf8 ' ) )
2014-02-24 22:02:22 +00:00
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 )
2014-02-18 17:15:08 +00:00
if ( self . OP is None ) :
2014-02-24 22:02:22 +00:00
myPrint + = " \n Action %s " % " ---!!!---NONE---!!!--- "
2014-02-18 17:15:08 +00:00
else :
2014-02-24 22:02:22 +00:00
myPrint + = " \n Action %s " % type ( self . OP ) . __name__
myPrint + = " \n Source %s " % ( self . OP . src )
myPrint + = " \n comment %s " % ( self . OP . info )
2014-02-18 17:15:08 +00:00
return myPrint
class SyncOperation ( object ) :
2014-02-24 22:02:22 +00:00
def __init__ ( self , src , info , * * kw ) :
2014-02-18 17:15:08 +00:00
self . src = src
self . info = info
2014-02-24 22:02:22 +00:00
for k , v in kw . items ( ) :
setattr ( self , k , v )
2014-02-18 17:15:08 +00:00
def __str__ ( self ) :
return ' in__STR__ '
2014-02-24 22:02:22 +00:00
2014-02-18 17:15:08 +00:00
class Create ( SyncOperation ) :
pass
2014-02-24 22:02:22 +00:00
2014-02-18 17:15:08 +00:00
class Update ( SyncOperation ) :
pass
2014-02-24 22:02:22 +00:00
2014-02-18 17:15:08 +00:00
class Delete ( SyncOperation ) :
pass
2014-02-24 22:02:22 +00:00
2014-02-18 17:15:08 +00:00
class NothingToDo ( SyncOperation ) :
pass
2014-02-24 22:02:22 +00:00
2014-02-18 17:15:08 +00:00
class Exclude ( SyncOperation ) :
pass
2013-12-02 14:31:33 +00:00
2014-01-13 17:41:57 +00:00
class google_calendar ( osv . AbstractModel ) :
2013-12-02 14:31:33 +00:00
STR_SERVICE = ' calendar '
2013-12-13 10:35:17 +00:00
_name = ' google. %s ' % STR_SERVICE
2014-05-14 08:28:10 +00:00
def generate_data ( self , cr , uid , event , isCreating = False , context = None ) :
2015-06-26 09:14:59 +00:00
if not context :
context = { }
2013-12-02 14:31:33 +00:00
if event . allday :
2014-05-14 08:28:10 +00:00
start_date = fields . datetime . context_timestamp ( cr , uid , datetime . strptime ( event . start , tools . DEFAULT_SERVER_DATETIME_FORMAT ) , context = context ) . isoformat ( ' T ' ) . split ( ' T ' ) [ 0 ]
[FIX] google_calendar: all day event stop date
For an event during all day, during 2 days,
e.g. September 9th and September 10th,
Google expects as start date the first day, and as
stop date the day after the last day.
e.g.
start 2015-09-09
stop 2015-09-11
Even if, afterwise, in the Google Agenda interface, it will
be correctly displayed 2015-09-10 as end date.
This must be applied at the event creation AND at the event
update. It was not the case until this revision.
Besides, we now use the event `stop_date` in Odoo, instead
of the duration, in case the duration has been incorrectly
computed.
opw-648867
2015-09-08 15:15:49 +00:00
final_date = fields . datetime . context_timestamp ( cr , uid , datetime . strptime ( event . stop , tools . DEFAULT_SERVER_DATETIME_FORMAT ) + timedelta ( days = 1 ) , context = context ) . isoformat ( ' T ' ) . split ( ' T ' ) [ 0 ]
2013-12-02 14:31:33 +00:00
type = ' date '
2014-02-18 17:15:08 +00:00
vstype = ' dateTime '
2013-12-02 14:31:33 +00:00
else :
2014-05-14 08:28:10 +00:00
start_date = fields . datetime . context_timestamp ( cr , uid , datetime . strptime ( event . start , tools . DEFAULT_SERVER_DATETIME_FORMAT ) , context = context ) . isoformat ( ' T ' )
final_date = fields . datetime . context_timestamp ( cr , uid , datetime . strptime ( event . stop , tools . DEFAULT_SERVER_DATETIME_FORMAT ) , context = context ) . isoformat ( ' T ' )
2013-12-02 14:31:33 +00:00
type = ' dateTime '
2014-02-18 17:15:08 +00:00
vstype = ' date '
2013-12-02 14:31:33 +00:00
attendee_list = [ ]
for attendee in event . attendee_ids :
2015-08-04 16:51:22 +00:00
email = tools . email_split ( attendee . email )
email = email [ 0 ] if email else ' NoEmail@mail.com '
2013-12-02 14:31:33 +00:00
attendee_list . append ( {
2015-08-04 16:51:22 +00:00
' email ' : email ,
2014-02-24 22:02:22 +00:00
' displayName ' : attendee . partner_id . name ,
' responseStatus ' : attendee . state or ' needsAction ' ,
2013-12-02 14:31:33 +00:00
} )
2015-02-12 21:16:41 +00:00
reminders = [ ]
for alarm in event . alarm_ids :
reminders . append ( {
" method " : " email " if alarm . type == " email " else " popup " ,
" minutes " : alarm . duration_minutes
} )
2013-12-02 14:31:33 +00:00
data = {
" summary " : event . name or ' ' ,
" description " : event . description or ' ' ,
2014-02-24 22:02:22 +00:00
" start " : {
type : start_date ,
vstype : None ,
2015-12-18 13:30:07 +00:00
' timeZone ' : context . get ( ' tz ' ) or ' UTC ' ,
2014-02-24 22:02:22 +00:00
} ,
" end " : {
2014-05-14 08:28:10 +00:00
type : final_date ,
2014-02-24 22:02:22 +00:00
vstype : None ,
2015-12-18 13:30:07 +00:00
' timeZone ' : context . get ( ' tz ' ) or ' UTC ' ,
2014-02-24 22:02:22 +00:00
} ,
" attendees " : attendee_list ,
2015-02-13 15:09:18 +00:00
" reminders " : {
" overrides " : reminders ,
" useDefault " : " false "
} ,
2014-02-24 22:02:22 +00:00
" location " : event . location or ' ' ,
" visibility " : event [ ' class ' ] or ' public ' ,
2013-12-02 14:31:33 +00:00
}
if event . recurrency and event . rrule :
2014-02-24 22:02:22 +00:00
data [ " recurrence " ] = [ " RRULE: " + event . rrule ]
2013-12-09 14:08:19 +00:00
if not event . active :
data [ " state " ] = " cancelled "
2014-01-14 13:37:36 +00:00
2014-02-24 22:02:22 +00:00
if not self . get_need_synchro_attendee ( cr , uid , context = context ) :
2014-02-18 17:15:08 +00:00
data . pop ( " attendees " )
2015-09-01 15:36:52 +00:00
if isCreating :
other_google_ids = [ other_att . google_internal_event_id for other_att in event . attendee_ids if other_att . google_internal_event_id ]
if other_google_ids :
data [ " id " ] = other_google_ids [ 0 ]
2013-12-02 14:31:33 +00:00
return data
2014-01-14 13:37:36 +00:00
2014-02-24 22:02:22 +00:00
def create_an_event ( self , cr , uid , event , context = None ) :
2014-02-18 17:15:08 +00:00
gs_pool = self . pool [ ' google.service ' ]
2014-05-14 08:28:10 +00:00
data = self . generate_data ( cr , uid , event , isCreating = True , context = context )
2014-01-14 13:37:36 +00:00
2014-05-14 08:28:10 +00:00
url = " /calendar/v3/calendars/ %s /events?fields= %s &access_token= %s " % ( ' primary ' , urllib2 . quote ( ' id,updated ' ) , self . get_token ( cr , uid , context ) )
2013-12-02 14:31:33 +00:00
headers = { ' Content-type ' : ' application/json ' , ' Accept ' : ' text/plain ' }
data_json = simplejson . dumps ( data )
2014-01-14 13:37:36 +00:00
2013-12-11 13:06:35 +00:00
return gs_pool . _do_request ( cr , uid , url , data_json , headers , type = ' POST ' , context = context )
2014-01-14 13:37:36 +00:00
2014-02-24 22:02:22 +00:00
def delete_an_event ( self , cr , uid , event_id , context = None ) :
2014-02-18 17:15:08 +00:00
gs_pool = self . pool [ ' google.service ' ]
2014-01-14 13:37:36 +00:00
2013-12-09 14:08:19 +00:00
params = {
2014-02-24 22:02:22 +00:00
' access_token ' : self . get_token ( cr , uid , context )
}
2013-12-09 14:08:19 +00:00
headers = { ' Content-type ' : ' application/json ' , ' Accept ' : ' text/plain ' }
2014-02-24 22:02:22 +00:00
url = " /calendar/v3/calendars/ %s /events/ %s " % ( ' primary ' , event_id )
2013-12-13 10:35:17 +00:00
return gs_pool . _do_request ( cr , uid , url , params , headers , type = ' DELETE ' , context = context )
2014-01-14 13:37:36 +00:00
2014-05-14 08:28:10 +00:00
def get_calendar_primary_id ( self , cr , uid , context = None ) :
params = {
' fields ' : ' id ' ,
' access_token ' : self . get_token ( cr , uid , context )
}
headers = { ' Content-type ' : ' application/json ' , ' Accept ' : ' text/plain ' }
url = " /calendar/v3/calendars/primary "
try :
2014-08-05 08:59:02 +00:00
st , content , ask_time = self . pool [ ' google.service ' ] . _do_request ( cr , uid , url , params , headers , type = ' GET ' , context = context )
2014-05-14 08:28:10 +00:00
except Exception , e :
if ( e . code == 401 ) : # Token invalid / Acces unauthorized
error_msg = " Your token is invalid or has been revoked ! "
registry = openerp . modules . registry . RegistryManager . get ( request . session . db )
with registry . cursor ( ) as cur :
2015-02-16 13:54:52 +00:00
self . pool [ ' res.users ' ] . write ( cur , SUPERUSER_ID , [ uid ] , { ' google_calendar_token ' : False , ' google_calendar_token_validity ' : False } , context = context )
2014-05-14 08:28:10 +00:00
raise self . pool . get ( ' res.config.settings ' ) . get_config_warning ( cr , _ ( error_msg ) , context = context )
raise
2014-08-05 08:59:02 +00:00
return ( status_response ( st ) , content [ ' id ' ] or False , ask_time )
2014-05-14 08:28:10 +00:00
def get_event_synchro_dict ( self , cr , uid , lastSync = False , token = False , nextPageToken = False , context = None ) :
2013-12-09 14:08:19 +00:00
if not token :
2014-02-24 22:02:22 +00:00
token = self . get_token ( cr , uid , context )
2014-01-14 13:37:36 +00:00
2013-12-09 14:08:19 +00:00
params = {
2014-02-24 22:02:22 +00:00
' fields ' : ' items,nextPageToken ' ,
' access_token ' : token ,
' maxResults ' : 1000 ,
2014-05-14 08:28:10 +00:00
#'timeMin': self.get_minTime(cr, uid, context=context).strftime("%Y-%m-%dT%H:%M:%S.%fz"),
2013-12-20 14:18:55 +00:00
}
2014-05-14 08:28:10 +00:00
if lastSync :
params [ ' updatedMin ' ] = lastSync . strftime ( " % Y- % m- %d T % H: % M: % S. %f z " )
params [ ' showDeleted ' ] = True
else :
params [ ' timeMin ' ] = self . get_minTime ( cr , uid , context = context ) . strftime ( " % Y- % m- %d T % H: % M: % S. %f z " )
2013-12-09 14:08:19 +00:00
headers = { ' Content-type ' : ' application/json ' , ' Accept ' : ' text/plain ' }
2014-01-14 13:37:36 +00:00
url = " /calendar/v3/calendars/ %s /events " % ' primary '
2013-12-09 14:08:19 +00:00
if nextPageToken :
params [ ' pageToken ' ] = nextPageToken
2014-01-14 13:37:36 +00:00
2014-08-05 08:59:02 +00:00
status , content , ask_time = self . pool [ ' google.service ' ] . _do_request ( cr , uid , url , params , headers , type = ' GET ' , context = context )
2014-01-14 13:37:36 +00:00
2013-12-09 14:08:19 +00:00
google_events_dict = { }
for google_event in content [ ' items ' ] :
google_events_dict [ google_event [ ' id ' ] ] = google_event
2013-12-13 10:35:17 +00:00
2014-05-14 08:28:10 +00:00
if content . get ( ' nextPageToken ' ) :
google_events_dict . update (
self . get_event_synchro_dict ( cr , uid , lastSync = lastSync , token = token , nextPageToken = content [ ' nextPageToken ' ] , context = context )
)
2014-02-24 22:02:22 +00:00
return google_events_dict
2014-01-14 13:37:36 +00:00
2014-05-14 08:28:10 +00:00
def get_one_event_synchro ( self , cr , uid , google_id , context = None ) :
token = self . get_token ( cr , uid , context )
params = {
' access_token ' : token ,
' maxResults ' : 1000 ,
' showDeleted ' : True ,
}
headers = { ' Content-type ' : ' application/json ' , ' Accept ' : ' text/plain ' }
url = " /calendar/v3/calendars/ %s /events/ %s " % ( ' primary ' , google_id )
try :
2014-08-05 08:59:02 +00:00
status , content , ask_time = self . pool [ ' google.service ' ] . _do_request ( cr , uid , url , params , headers , type = ' GET ' , context = context )
2014-05-14 08:28:10 +00:00
except :
_logger . info ( " Calendar Synchro - In except of get_one_event_synchro " )
pass
return status_response ( status ) and content or False
2013-12-09 14:08:19 +00:00
def update_to_google ( self , cr , uid , oe_event , google_event , context ) :
2014-01-15 09:38:05 +00:00
calendar_event = self . pool [ ' calendar.event ' ]
2014-01-14 13:37:36 +00:00
2014-02-24 22:02:22 +00:00
url = " /calendar/v3/calendars/ %s /events/ %s ?fields= %s &access_token= %s " % ( ' primary ' , google_event [ ' id ' ] , ' id,updated ' , self . get_token ( cr , uid , context ) )
2013-12-09 14:08:19 +00:00
headers = { ' Content-type ' : ' application/json ' , ' Accept ' : ' text/plain ' }
2015-06-26 09:14:59 +00:00
data = self . generate_data ( cr , uid , oe_event , context = context )
2013-12-09 14:08:19 +00:00
data [ ' sequence ' ] = google_event . get ( ' sequence ' , 0 )
data_json = simplejson . dumps ( data )
2014-01-14 13:37:36 +00:00
2014-08-05 08:59:02 +00:00
status , content , ask_time = self . pool [ ' google.service ' ] . _do_request ( cr , uid , url , data_json , headers , type = ' PATCH ' , context = context )
2014-01-14 13:37:36 +00:00
2014-02-24 22:02:22 +00:00
update_date = datetime . strptime ( content [ ' updated ' ] , " % Y- % m- %d T % H: % M: % S. %f z " )
calendar_event . write ( cr , uid , [ oe_event . id ] , { ' oe_update_date ' : update_date } )
2014-01-14 13:37:36 +00:00
2013-12-17 20:42:38 +00:00
if context [ ' curr_attendee ' ] :
2014-02-24 22:02:22 +00:00
self . pool [ ' calendar.attendee ' ] . write ( cr , uid , [ context [ ' curr_attendee ' ] ] , { ' oe_synchro_date ' : update_date } , context )
2014-01-14 13:37:36 +00:00
2014-02-24 22:02:22 +00:00
def update_an_event ( self , cr , uid , event , context = None ) :
data = self . generate_data ( cr , uid , event , context = context )
2014-01-14 13:37:36 +00:00
2013-12-09 14:08:19 +00:00
url = " /calendar/v3/calendars/ %s /events/ %s " % ( ' primary ' , event . google_internal_event_id )
headers = { }
2014-02-24 22:02:22 +00:00
data [ ' access_token ' ] = self . get_token ( cr , uid , context )
2014-01-14 13:37:36 +00:00
2014-08-05 08:59:02 +00:00
status , response , ask_time = self . pool [ ' google.service ' ] . _do_request ( cr , uid , url , data , headers , type = ' GET ' , context = context )
2013-12-20 14:18:55 +00:00
#TO_CHECK : , if http fail, no event, do DELETE ?
2013-12-09 14:08:19 +00:00
return response
2014-01-14 13:37:36 +00:00
2014-02-24 22:02:22 +00:00
def update_recurrent_event_exclu ( self , cr , uid , instance_id , event_ori_google_id , event_new , context = None ) :
2014-02-18 17:15:08 +00:00
gs_pool = self . pool [ ' google.service ' ]
2014-01-14 13:37:36 +00:00
2014-02-24 22:02:22 +00:00
data = self . generate_data ( cr , uid , event_new , context = context )
2014-01-14 13:37:36 +00:00
2013-12-09 14:08:19 +00:00
data [ ' recurringEventId ' ] = event_ori_google_id
data [ ' originalStartTime ' ] = event_new . recurrent_id_date
2014-01-14 13:37:36 +00:00
2014-02-24 22:02:22 +00:00
url = " /calendar/v3/calendars/ %s /events/ %s ?access_token= %s " % ( ' primary ' , instance_id , self . get_token ( cr , uid , context ) )
headers = { ' Content-type ' : ' application/json ' }
2014-01-14 13:37:36 +00:00
data [ ' sequence ' ] = self . get_sequence ( cr , uid , instance_id , context )
2013-12-09 14:08:19 +00:00
data_json = simplejson . dumps ( data )
2013-12-13 10:35:17 +00:00
return gs_pool . _do_request ( cr , uid , url , data_json , headers , type = ' PUT ' , context = context )
2014-01-14 13:37:36 +00:00
[FIX] google_calendar: user invited to one recurring event occurence only
When a Google user was invited to one occurrence of a recurring event,
but not to the recurring event itself (and the other occurrences, therefore),
and the user owner of the recurring event did not sync his calendar in Odoo,
the event occurrence could not be synced in Odoo, because it attempted
to attach it to the parent/main recurring event, which was not present
in Odoo.
In such a case, Odoo now syncs the event occurrence as a simple classic
event. In addition, if the owner of the event sync his calendar with Odoo
afterwards, or if the user is invited later to the main/parent recurring event
and then sync again his calendar,
it then attach the event occurrence that was previously
synced to this main event, to avoid events duplication.
opw-676535
2016-05-09 09:31:45 +00:00
def create_from_google ( self , cr , uid , event , partner_id , context = None ) :
context_tmp = dict ( context , NewMeeting = True )
res = self . update_from_google ( cr , uid , False , event . GG . event , " create " , context = context_tmp )
event . OE . event_id = res
meeting = self . pool [ ' calendar.event ' ] . browse ( cr , uid , res , context = context )
attendee_record_id = self . pool [ ' calendar.attendee ' ] . search ( cr , uid , [ ( ' partner_id ' , ' = ' , partner_id ) , ( ' event_id ' , ' = ' , res ) ] , context = context )
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 )
if meeting . recurrency :
attendee_ids = self . pool [ ' calendar.attendee ' ] . search ( cr , SUPERUSER_ID , [ ( ' google_internal_event_id ' , ' =ilike ' , ' %s \ _ %% ' % event . GG . event [ ' id ' ] ) ] , context = context )
attendees = self . pool [ ' calendar.attendee ' ] . browse ( cr , SUPERUSER_ID , attendee_ids , context = context )
excluded_recurrent_event_ids = set ( attendee . event_id for attendee in attendees )
for event in excluded_recurrent_event_ids :
event . write ( { ' recurrent_id ' : meeting . id , ' recurrent_id_date ' : event . start , ' user_id ' : meeting . user_id . id } )
return event
2013-12-09 14:08:19 +00:00
def update_from_google ( self , cr , uid , event , single_event_dict , type , context ) :
2013-12-10 16:45:25 +00:00
if context is None :
2014-02-24 22:02:22 +00:00
context = [ ]
2014-01-14 13:37:36 +00:00
2014-01-15 09:38:05 +00:00
calendar_event = self . pool [ ' calendar.event ' ]
2013-12-09 14:08:19 +00:00
res_partner_obj = self . pool [ ' res.partner ' ]
calendar_attendee_obj = self . pool [ ' calendar.attendee ' ]
2015-02-12 21:16:41 +00:00
calendar_alarm_obj = self . pool [ ' calendar.alarm ' ]
2014-02-18 17:15:08 +00:00
user_obj = self . pool [ ' res.users ' ]
2014-02-24 22:02:22 +00:00
myPartnerID = user_obj . browse ( cr , uid , uid , context ) . partner_id . id
2013-12-10 16:45:25 +00:00
attendee_record = [ ]
2015-05-15 12:03:48 +00:00
alarm_record = set ( )
2014-02-24 22:02:22 +00:00
partner_record = [ ( 4 , myPartnerID ) ]
2013-12-09 14:08:19 +00:00
result = { }
2013-12-10 16:45:25 +00:00
2015-02-12 21:16:41 +00:00
if self . get_need_synchro_attendee ( cr , uid , context = context ) :
for google_attendee in single_event_dict . get ( ' attendees ' , [ ] ) :
2015-07-22 11:22:35 +00:00
partner_email = google_attendee . get ( ' email ' , False )
2013-12-09 14:08:19 +00:00
if type == " write " :
for oe_attendee in event [ ' attendee_ids ' ] :
2015-07-22 11:22:35 +00:00
if oe_attendee . email == partner_email :
[FIX] google_calendar: events disappearing
This rev. is related to a9e3d74713b6882c64617345696ad326d75a4745
This new revision is about the same use case than above, except
that both Google users login doesn't match the Odoo login email.
e.g.
User A: A@agrolait.com in Odoo, A@gmail.com in Google
User B: B@agrolait.com in Odoo, B@gmail.com in Google.
When A creates an event, with B in the attendees, and
syncs his calendar to Google, B is not automatically invited
Google side, as his attendee email is B@agrolait.com, which
doesn't match any existing Google User (doesn't match B@gmail.com)
While the revision mentioned above, a9e3d74713b6882c64617345696ad326d75a4745,
expected the attendee to be automatically invited Google side, and therefore
expected the event to already exists in B's calendar.
Therefore, when B syncs his calendar in Odoo, as the event
was there in his Odoo calendar, but not in his Google Calendar,
the code actually think it's no - longer - there, and take the assumption
the event has been deleted Google side. So, it deletes the event
in Odoo side as well, for both users A & B.
To overcome this new issue, when the Google & Odoo users emails
do not match, while keeping the compatibility when the Google & Odoo
emails do match (and therefore the invitation is automatically sent
Google side, as the email matches an existing Google account, and
the event is automatically created in B's calendar without needing the
sync in Odoo), we now force the Google internal id to be the same
for all attendees of an event, event by Google side.
opw-645745
2015-09-01 15:03:47 +00:00
calendar_attendee_obj . write ( cr , uid , [ oe_attendee . id ] , { ' state ' : google_attendee [ ' responseStatus ' ] } , context = context )
2013-12-09 14:08:19 +00:00
google_attendee [ ' found ' ] = True
2013-12-10 16:45:25 +00:00
continue
2014-01-14 13:37:36 +00:00
2015-02-12 21:16:41 +00:00
if google_attendee . get ( ' found ' ) :
2013-12-09 14:08:19 +00:00
continue
2015-02-12 21:16:41 +00:00
2015-07-22 11:22:35 +00:00
attendee_id = res_partner_obj . search ( cr , uid , [ ( ' email ' , ' = ' , partner_email ) ] , context = context )
2015-02-12 21:16:41 +00:00
if not attendee_id :
data = {
2015-07-22 11:22:35 +00:00
' email ' : partner_email ,
2015-02-12 21:16:41 +00:00
' customer ' : False ,
2015-07-22 11:22:35 +00:00
' name ' : google_attendee . get ( " displayName " , False ) or partner_email
2015-02-12 21:16:41 +00:00
}
attendee_id = [ res_partner_obj . create ( cr , uid , data , context = context ) ]
attendee = res_partner_obj . read ( cr , uid , attendee_id [ 0 ] , [ ' email ' ] , context = context )
partner_record . append ( ( 4 , attendee . get ( ' id ' ) ) )
attendee [ ' partner_id ' ] = attendee . pop ( ' id ' )
attendee [ ' state ' ] = google_attendee [ ' responseStatus ' ]
attendee_record . append ( ( 0 , 0 , attendee ) )
for google_alarm in single_event_dict . get ( ' reminders ' , { } ) . get ( ' overrides ' , [ ] ) :
alarm_id = calendar_alarm_obj . search (
cr ,
uid ,
[
( ' type ' , ' = ' , google_alarm [ ' method ' ] if google_alarm [ ' method ' ] == ' email ' else ' notification ' ) ,
( ' duration_minutes ' , ' = ' , google_alarm [ ' minutes ' ] )
] ,
context = context
)
if not alarm_id :
data = {
' type ' : google_alarm [ ' method ' ] if google_alarm [ ' method ' ] == ' email ' else ' notification ' ,
' duration ' : google_alarm [ ' minutes ' ] ,
' interval ' : ' minutes ' ,
' name ' : " %s minutes - %s " % ( google_alarm [ ' minutes ' ] , google_alarm [ ' method ' ] )
}
alarm_id = [ calendar_alarm_obj . create ( cr , uid , data , context = context ) ]
2015-05-15 12:03:48 +00:00
alarm_record . add ( alarm_id [ 0 ] )
2014-02-24 22:02:22 +00:00
2013-12-10 16:45:25 +00:00
UTC = pytz . timezone ( ' UTC ' )
2014-02-24 22:02:22 +00:00
if single_event_dict . get ( ' start ' ) and single_event_dict . get ( ' end ' ) : # If not cancelled
2014-05-14 08:28:10 +00:00
2014-02-24 22:02:22 +00:00
if single_event_dict [ ' start ' ] . get ( ' dateTime ' , False ) and single_event_dict [ ' end ' ] . get ( ' dateTime ' , False ) :
2013-12-10 16:45:25 +00:00
date = parser . parse ( single_event_dict [ ' start ' ] [ ' dateTime ' ] )
2014-05-14 08:28:10 +00:00
stop = parser . parse ( single_event_dict [ ' end ' ] [ ' dateTime ' ] )
2013-12-10 16:45:25 +00:00
date = str ( date . astimezone ( UTC ) ) [ : - 6 ]
2014-05-14 08:28:10 +00:00
stop = str ( stop . astimezone ( UTC ) ) [ : - 6 ]
2013-12-10 16:45:25 +00:00
allday = False
2014-01-14 13:37:36 +00:00
else :
2014-05-14 08:28:10 +00:00
date = ( single_event_dict [ ' start ' ] [ ' date ' ] )
stop = ( single_event_dict [ ' end ' ] [ ' date ' ] )
d_end = datetime . strptime ( stop , DEFAULT_SERVER_DATE_FORMAT )
2013-12-10 16:45:25 +00:00
allday = True
2014-05-14 08:28:10 +00:00
d_end = d_end + timedelta ( days = - 1 )
stop = d_end . strftime ( DEFAULT_SERVER_DATE_FORMAT )
2014-01-14 13:37:36 +00:00
2014-02-24 22:02:22 +00:00
update_date = datetime . strptime ( single_event_dict [ ' updated ' ] , " % Y- % m- %d T % H: % M: % S. %f z " )
2013-12-10 16:45:25 +00:00
result . update ( {
2014-05-14 08:28:10 +00:00
' start ' : date ,
' stop ' : stop ,
2013-12-10 16:45:25 +00:00
' allday ' : allday
} )
2013-12-09 14:08:19 +00:00
result . update ( {
' attendee_ids ' : attendee_record ,
2013-12-10 16:45:25 +00:00
' partner_ids ' : list ( set ( partner_record ) ) ,
2015-05-15 12:03:48 +00:00
' alarm_ids ' : [ ( 6 , 0 , list ( alarm_record ) ) ] ,
2013-12-10 16:45:25 +00:00
2014-02-24 22:02:22 +00:00
' name ' : single_event_dict . get ( ' summary ' , ' Event ' ) ,
' description ' : single_event_dict . get ( ' description ' , False ) ,
' location ' : single_event_dict . get ( ' location ' , False ) ,
' class ' : single_event_dict . get ( ' visibility ' , ' public ' ) ,
' oe_update_date ' : update_date ,
2013-12-09 14:08:19 +00:00
} )
2014-01-14 13:37:36 +00:00
2014-02-24 22:02:22 +00:00
if single_event_dict . get ( " recurrence " , False ) :
2013-12-09 14:08:19 +00:00
rrule = [ rule for rule in single_event_dict [ " recurrence " ] if rule . startswith ( " RRULE: " ) ] [ 0 ] [ 6 : ]
2014-02-24 22:02:22 +00:00
result [ ' rrule ' ] = rrule
2014-01-14 13:37:36 +00:00
2015-02-24 17:18:25 +00:00
context = dict ( context or { } , no_mail_to_attendees = True )
2013-12-09 14:08:19 +00:00
if type == " write " :
2014-01-15 09:38:05 +00:00
res = calendar_event . write ( cr , uid , event [ ' id ' ] , result , context = context )
2013-12-09 14:08:19 +00:00
elif type == " copy " :
2013-12-10 16:45:25 +00:00
result [ ' recurrence ' ] = True
2014-01-15 09:38:05 +00:00
res = calendar_event . write ( cr , uid , [ event [ ' id ' ] ] , result , context = context )
2013-12-13 16:27:52 +00:00
elif type == " create " :
2014-01-15 09:38:05 +00:00
res = calendar_event . create ( cr , uid , result , context = context )
2014-01-14 13:37:36 +00:00
2013-12-13 16:27:52 +00:00
if context [ ' curr_attendee ' ] :
2014-02-24 22:02:22 +00:00
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 )
2014-01-14 13:37:36 +00:00
return res
2014-05-14 08:28:10 +00:00
def remove_references ( self , cr , uid , context = None ) :
2014-09-24 13:30:11 +00:00
current_user = self . pool [ ' res.users ' ] . browse ( cr , SUPERUSER_ID , uid , context = context )
2014-05-14 08:28:10 +00:00
reset_data = {
' google_calendar_rtoken ' : False ,
' google_calendar_token ' : False ,
' google_calendar_token_validity ' : False ,
' google_calendar_last_sync_date ' : False ,
' google_calendar_cal_id ' : False ,
}
all_my_attendees = self . pool [ ' calendar.attendee ' ] . search ( cr , uid , [ ( ' partner_id ' , ' = ' , current_user . partner_id . id ) ] , context = context )
self . pool [ ' calendar.attendee ' ] . write ( cr , uid , all_my_attendees , { ' oe_synchro_date ' : False , ' google_internal_event_id ' : False } , context = context )
2014-11-13 11:30:26 +00:00
current_user . write ( reset_data )
2014-05-14 08:28:10 +00:00
return True
2014-10-03 15:52:31 +00:00
def synchronize_events_cron ( self , cr , uid , context = None ) :
ids = self . pool [ ' res.users ' ] . search ( cr , uid , [ ( ' google_calendar_last_sync_date ' , ' != ' , False ) ] , context = context )
_logger . info ( " Calendar Synchro - Started by cron " )
for user_to_sync in ids :
_logger . info ( " Calendar Synchro - Starting synchronization for a new user [ %s ] " % user_to_sync )
try :
2015-02-18 12:00:39 +00:00
resp = self . synchronize_events ( cr , user_to_sync , False , lastSync = True , context = None )
2014-10-03 15:52:31 +00:00
if resp . get ( " status " ) == " need_reset " :
_logger . info ( " [ %s ] Calendar Synchro - Failed - NEED RESET ! " % user_to_sync )
else :
_logger . info ( " [ %s ] Calendar Synchro - Done with status : %s ! " % ( user_to_sync , resp . get ( " status " ) ) )
except Exception , e :
2014-10-06 12:32:28 +00:00
_logger . info ( " [ %s ] Calendar Synchro - Exception : %s ! " % ( user_to_sync , exception_to_unicode ( e ) ) )
2014-10-03 15:52:31 +00:00
_logger . info ( " Calendar Synchro - Ended by cron " )
2014-05-14 08:28:10 +00:00
def synchronize_events ( self , cr , uid , ids , lastSync = True , context = None ) :
if context is None :
context = { }
# def isValidSync(syncToken):
# gs_pool = self.pool['google.service']
# params = {
# 'maxResults': 1,
# 'fields': 'id',
# 'access_token': self.get_token(cr, uid, context),
# 'syncToken': syncToken,
# }
# url = "/calendar/v3/calendars/primary/events"
# status, response = gs_pool._do_request(cr, uid, url, params, type='GET', context=context)
# return int(status) != 410
2014-01-14 13:37:36 +00:00
2014-10-03 15:52:31 +00:00
user_to_sync = ids and ids [ 0 ] or uid
current_user = self . pool [ ' res.users ' ] . browse ( cr , SUPERUSER_ID , user_to_sync , context = context )
2014-05-14 08:28:10 +00:00
2015-02-18 12:00:39 +00:00
st , current_google , ask_time = self . get_calendar_primary_id ( cr , user_to_sync , context = context )
2014-05-14 08:28:10 +00:00
if current_user . google_calendar_cal_id :
if current_google != current_user . google_calendar_cal_id :
return {
" status " : " need_reset " ,
" info " : {
" old_name " : current_user . google_calendar_cal_id ,
" new_name " : current_google
} ,
" url " : ' '
}
2015-02-18 12:00:39 +00:00
if lastSync and self . get_last_sync_date ( cr , user_to_sync , context = context ) and not self . get_disable_since_synchro ( cr , user_to_sync , context = context ) :
lastSync = self . get_last_sync_date ( cr , user_to_sync , context )
2014-10-03 15:52:31 +00:00
_logger . info ( " [ %s ] Calendar Synchro - MODE SINCE_MODIFIED : %s ! " % ( user_to_sync , lastSync . strftime ( DEFAULT_SERVER_DATETIME_FORMAT ) ) )
2014-05-14 08:28:10 +00:00
else :
lastSync = False
2014-10-03 15:52:31 +00:00
_logger . info ( " [ %s ] Calendar Synchro - MODE FULL SYNCHRO FORCED " % user_to_sync )
2014-05-14 08:28:10 +00:00
else :
2014-11-13 11:30:26 +00:00
current_user . write ( { ' google_calendar_cal_id ' : current_google } )
2014-05-14 08:28:10 +00:00
lastSync = False
2014-10-03 15:52:31 +00:00
_logger . info ( " [ %s ] Calendar Synchro - MODE FULL SYNCHRO - NEW CAL ID " % user_to_sync )
2014-05-14 08:28:10 +00:00
new_ids = [ ]
2015-02-18 12:00:39 +00:00
new_ids + = self . create_new_events ( cr , user_to_sync , context = context )
new_ids + = self . bind_recurring_events_to_google ( cr , user_to_sync , context )
2014-05-14 08:28:10 +00:00
2015-02-18 12:00:39 +00:00
res = self . update_events ( cr , user_to_sync , lastSync , context )
2014-05-14 08:28:10 +00:00
2014-11-13 11:30:26 +00:00
current_user . write ( { ' google_calendar_last_sync_date ' : ask_time } )
2013-12-09 14:08:19 +00:00
return {
2015-02-18 12:00:39 +00:00
" status " : res and " need_refresh " or " no_new_event_from_google " ,
2014-02-24 22:02:22 +00:00
" url " : ' '
}
2014-01-14 13:37:36 +00:00
2014-02-18 17:15:08 +00:00
def create_new_events ( self , cr , uid , context = None ) :
2014-05-14 08:28:10 +00:00
if context is None :
context = { }
new_ids = [ ]
2014-02-18 17:15:08 +00:00
ev_obj = self . pool [ ' calendar.event ' ]
2013-12-13 16:27:52 +00:00
att_obj = self . pool [ ' calendar.attendee ' ]
2013-12-09 14:08:19 +00:00
user_obj = self . pool [ ' res.users ' ]
2014-02-24 22:02:22 +00:00
myPartnerID = user_obj . browse ( cr , uid , uid , context = context ) . partner_id . id
2014-01-14 13:37:36 +00:00
2013-12-09 14:08:19 +00:00
context_norecurrent = context . copy ( )
context_norecurrent [ ' virtual_id ' ] = False
2014-02-24 22:02:22 +00:00
my_att_ids = att_obj . search ( cr , uid , [ ( ' partner_id ' , ' = ' , myPartnerID ) ,
( ' google_internal_event_id ' , ' = ' , False ) ,
' | ' ,
2014-05-14 08:28:10 +00:00
( ' event_id.stop ' , ' > ' , self . get_minTime ( cr , uid , context = context ) . strftime ( DEFAULT_SERVER_DATETIME_FORMAT ) ) ,
( ' event_id.final_date ' , ' > ' , self . get_minTime ( cr , uid , context = context ) . strftime ( DEFAULT_SERVER_DATETIME_FORMAT ) ) ,
2014-02-24 22:02:22 +00:00
] , context = context_norecurrent )
for att in att_obj . browse ( cr , uid , my_att_ids , context = context ) :
[FIX] google_calendar: events disappearing
This rev. is related to a9e3d74713b6882c64617345696ad326d75a4745
This new revision is about the same use case than above, except
that both Google users login doesn't match the Odoo login email.
e.g.
User A: A@agrolait.com in Odoo, A@gmail.com in Google
User B: B@agrolait.com in Odoo, B@gmail.com in Google.
When A creates an event, with B in the attendees, and
syncs his calendar to Google, B is not automatically invited
Google side, as his attendee email is B@agrolait.com, which
doesn't match any existing Google User (doesn't match B@gmail.com)
While the revision mentioned above, a9e3d74713b6882c64617345696ad326d75a4745,
expected the attendee to be automatically invited Google side, and therefore
expected the event to already exists in B's calendar.
Therefore, when B syncs his calendar in Odoo, as the event
was there in his Odoo calendar, but not in his Google Calendar,
the code actually think it's no - longer - there, and take the assumption
the event has been deleted Google side. So, it deletes the event
in Odoo side as well, for both users A & B.
To overcome this new issue, when the Google & Odoo users emails
do not match, while keeping the compatibility when the Google & Odoo
emails do match (and therefore the invitation is automatically sent
Google side, as the email matches an existing Google account, and
the event is automatically created in B's calendar without needing the
sync in Odoo), we now force the Google internal id to be the same
for all attendees of an event, event by Google side.
opw-645745
2015-09-01 15:03:47 +00:00
other_google_ids = [ other_att . google_internal_event_id for other_att in att . event_id . attendee_ids if other_att . google_internal_event_id and other_att . id != att . id ]
for other_google_id in other_google_ids :
if self . get_one_event_synchro ( cr , uid , other_google_id , context = context ) :
att_obj . write ( cr , uid , [ att . id ] , { ' google_internal_event_id ' : other_google_id } )
break
else :
if not att . event_id . recurrent_id or att . event_id . recurrent_id == 0 :
st , response , ask_time = self . create_an_event ( cr , uid , att . event_id , context = context )
if status_response ( st ) :
update_date = datetime . strptime ( response [ ' updated ' ] , " % Y- % m- %d T % H: % M: % S. %f z " )
ev_obj . write ( cr , uid , att . event_id . id , { ' oe_update_date ' : update_date } )
new_ids . append ( response [ ' id ' ] )
att_obj . write ( cr , uid , [ att . id ] , { ' google_internal_event_id ' : response [ ' id ' ] , ' oe_synchro_date ' : update_date } )
cr . commit ( )
else :
_logger . warning ( " Impossible to create event %s . [ %s ] " % ( att . event_id . id , st ) )
_logger . warning ( " Response : %s " % response )
2014-05-14 08:28:10 +00:00
return new_ids
2014-01-14 13:37:36 +00:00
2014-05-14 08:28:10 +00:00
def get_context_no_virtual ( self , context ) :
context_norecurrent = context . copy ( )
context_norecurrent [ ' virtual_id ' ] = False
context_norecurrent [ ' active_test ' ] = False
return context_norecurrent
def bind_recurring_events_to_google ( self , cr , uid , context = None ) :
if context is None :
context = { }
new_ids = [ ]
2014-02-18 17:15:08 +00:00
ev_obj = self . pool [ ' calendar.event ' ]
att_obj = self . pool [ ' calendar.attendee ' ]
user_obj = self . pool [ ' res.users ' ]
2014-02-24 22:02:22 +00:00
myPartnerID = user_obj . browse ( cr , uid , uid , context = context ) . partner_id . id
2014-01-14 13:37:36 +00:00
2014-05-14 08:28:10 +00:00
context_norecurrent = self . get_context_no_virtual ( context )
2014-02-24 22:02:22 +00:00
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 ) :
2014-02-18 17:15:08 +00:00
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 )
2014-02-24 22:02:22 +00:00
source_attendee_record_id = att_obj . search ( cr , uid , [ ( ' partner_id ' , ' = ' , myPartnerID ) , ( ' event_id ' , ' = ' , source_event_record . id ) ] , context = context )
2014-12-09 15:34:35 +00:00
if not source_attendee_record_id :
continue
2014-02-18 17:15:08 +00:00
source_attendee_record = att_obj . browse ( cr , uid , source_attendee_record_id , context ) [ 0 ]
2014-02-24 22:02:22 +00:00
2014-02-18 17:15:08 +00:00
if att . event_id . recurrent_id_date and source_event_record . allday and source_attendee_record . google_internal_event_id :
2014-02-24 22:02:22 +00:00
new_google_internal_event_id = source_attendee_record . google_internal_event_id + ' _ ' + att . event_id . recurrent_id_date . split ( ' ' ) [ 0 ] . replace ( ' - ' , ' ' )
2014-02-18 17:15:08 +00:00
elif att . event_id . recurrent_id_date and source_attendee_record . google_internal_event_id :
2014-02-24 22:02:22 +00:00
new_google_internal_event_id = source_attendee_record . google_internal_event_id + ' _ ' + att . event_id . recurrent_id_date . replace ( ' - ' , ' ' ) . replace ( ' ' , ' T ' ) . replace ( ' : ' , ' ' ) + ' Z '
2014-02-18 17:15:08 +00:00
if new_google_internal_event_id :
#TODO WARNING, NEED TO CHECK THAT EVENT and ALL instance NOT DELETE IN GMAIL BEFORE !
2014-05-14 08:28:10 +00:00
try :
2014-08-05 08:59:02 +00:00
st , response , ask_time = self . update_recurrent_event_exclu ( cr , uid , new_google_internal_event_id , source_attendee_record . google_internal_event_id , att . event_id , context = context )
2014-05-14 08:28:10 +00:00
if status_response ( st ) :
att_obj . write ( cr , uid , [ att . id ] , { ' google_internal_event_id ' : new_google_internal_event_id } , context = context )
new_ids . append ( new_google_internal_event_id )
cr . commit ( )
else :
_logger . warning ( " Impossible to create event %s . [ %s ] " % ( att . event_id . id , st ) )
_logger . warning ( " Response : %s " % response )
except :
pass
return new_ids
2014-02-18 17:15:08 +00:00
2014-05-14 08:28:10 +00:00
def update_events ( self , cr , uid , lastSync = False , context = None ) :
2014-07-06 14:44:26 +00:00
context = dict ( context or { } )
2014-01-14 13:37:36 +00:00
2014-01-15 09:38:05 +00:00
calendar_event = self . pool [ ' calendar.event ' ]
2013-12-10 16:45:25 +00:00
user_obj = self . pool [ ' res.users ' ]
2013-12-13 16:27:52 +00:00
att_obj = self . pool [ ' calendar.attendee ' ]
2014-02-18 17:15:08 +00:00
myPartnerID = user_obj . browse ( cr , uid , uid , context = context ) . partner_id . id
2014-05-14 08:28:10 +00:00
context_novirtual = self . get_context_no_virtual ( context )
if lastSync :
try :
all_event_from_google = self . get_event_synchro_dict ( cr , uid , lastSync = lastSync , context = context )
except urllib2 . HTTPError , e :
if e . code == 410 : # GONE, Google is lost.
# we need to force the rollback from this cursor, because it locks my res_users but I need to write in this tuple before to raise.
cr . rollback ( )
registry = openerp . modules . registry . RegistryManager . get ( request . session . db )
with registry . cursor ( ) as cur :
2015-02-16 13:54:52 +00:00
self . pool [ ' res.users ' ] . write ( cur , SUPERUSER_ID , [ uid ] , { ' google_calendar_last_sync_date ' : False } , context = context )
2014-12-10 16:29:14 +00:00
error_key = simplejson . loads ( str ( e ) )
2014-05-14 08:28:10 +00:00
error_key = error_key . get ( ' error ' , { } ) . get ( ' message ' , ' nc ' )
2014-12-10 16:30:34 +00:00
error_msg = " Google is lost... the next synchro will be a full synchro. \n \n %s " % error_key
2014-05-14 08:28:10 +00:00
raise self . pool . get ( ' res.config.settings ' ) . get_config_warning ( cr , _ ( error_msg ) , context = context )
my_google_att_ids = att_obj . search ( cr , uid , [
( ' partner_id ' , ' = ' , myPartnerID ) ,
( ' google_internal_event_id ' , ' in ' , all_event_from_google . keys ( ) )
] , context = context_novirtual )
my_openerp_att_ids = att_obj . search ( cr , uid , [
( ' partner_id ' , ' = ' , myPartnerID ) ,
( ' event_id.oe_update_date ' , ' > ' , lastSync and lastSync . strftime ( DEFAULT_SERVER_DATETIME_FORMAT ) or self . get_minTime ( cr , uid , context ) . strftime ( DEFAULT_SERVER_DATETIME_FORMAT ) ) ,
( ' google_internal_event_id ' , ' != ' , False ) ,
] , context = context_novirtual )
my_openerp_googleinternal_ids = att_obj . read ( cr , uid , my_openerp_att_ids , [ ' google_internal_event_id ' , ' event_id ' ] , context = context_novirtual )
if self . get_print_log ( cr , uid , context = context ) :
_logger . info ( " Calendar Synchro - \n \n UPDATE IN GOOGLE \n %s \n \n RETRIEVE FROM OE \n %s \n \n UPDATE IN OE \n %s \n \n RETRIEVE FROM GG \n %s \n \n " % ( all_event_from_google , my_google_att_ids , my_openerp_att_ids , my_openerp_googleinternal_ids ) )
for giid in my_openerp_googleinternal_ids :
active = True # if not sure, we request google
if giid . get ( ' event_id ' ) :
active = calendar_event . browse ( cr , uid , int ( giid . get ( ' event_id ' ) [ 0 ] ) , context = context_novirtual ) . active
if giid . get ( ' google_internal_event_id ' ) and not all_event_from_google . get ( giid . get ( ' google_internal_event_id ' ) ) and active :
one_event = self . get_one_event_synchro ( cr , uid , giid . get ( ' google_internal_event_id ' ) , context = context )
if one_event :
all_event_from_google [ one_event [ ' id ' ] ] = one_event
my_att_ids = list ( set ( my_google_att_ids + my_openerp_att_ids ) )
2014-01-14 13:37:36 +00:00
2014-05-14 08:28:10 +00:00
else :
domain = [
( ' partner_id ' , ' = ' , myPartnerID ) ,
( ' google_internal_event_id ' , ' != ' , False ) ,
' | ' ,
( ' event_id.stop ' , ' > ' , self . get_minTime ( cr , uid , context ) . strftime ( DEFAULT_SERVER_DATETIME_FORMAT ) ) ,
( ' event_id.final_date ' , ' > ' , self . get_minTime ( cr , uid , context ) . strftime ( DEFAULT_SERVER_DATETIME_FORMAT ) ) ,
]
# Select all events from OpenERP which have been already synchronized in gmail
my_att_ids = att_obj . search ( cr , uid , domain , context = context_novirtual )
all_event_from_google = self . get_event_synchro_dict ( cr , uid , lastSync = False , context = context )
2014-02-24 22:02:22 +00:00
2013-12-10 16:45:25 +00:00
event_to_synchronize = { }
2014-02-24 22:02:22 +00:00
for att in att_obj . browse ( cr , uid , my_att_ids , context = context ) :
2013-12-13 16:27:52 +00:00
event = att . event_id
2014-01-14 13:37:36 +00:00
2014-06-13 15:57:01 +00:00
base_event_id = att . google_internal_event_id . rsplit ( ' _ ' , 1 ) [ 0 ]
2014-01-14 13:37:36 +00:00
2013-12-10 16:45:25 +00:00
if base_event_id not in event_to_synchronize :
event_to_synchronize [ base_event_id ] = { }
2014-01-14 13:37:36 +00:00
2013-12-13 16:27:52 +00:00
if att . google_internal_event_id not in event_to_synchronize [ base_event_id ] :
2014-02-18 17:15:08 +00:00
event_to_synchronize [ base_event_id ] [ att . google_internal_event_id ] = SyncEvent ( )
ev_to_sync = event_to_synchronize [ base_event_id ] [ att . google_internal_event_id ]
2014-02-24 22:02:22 +00:00
2014-02-18 17:15:08 +00:00
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
2014-01-14 13:37:36 +00:00
2013-12-10 16:45:25 +00:00
for event in all_event_from_google . values ( ) :
event_id = event . get ( ' id ' )
2014-06-13 15:57:01 +00:00
base_event_id = event_id . rsplit ( ' _ ' , 1 ) [ 0 ]
2014-01-14 13:37:36 +00:00
2013-12-10 16:45:25 +00:00
if base_event_id not in event_to_synchronize :
event_to_synchronize [ base_event_id ] = { }
2014-01-14 13:37:36 +00:00
2013-12-10 16:45:25 +00:00
if event_id not in event_to_synchronize [ base_event_id ] :
2014-02-18 17:15:08 +00:00
event_to_synchronize [ base_event_id ] [ event_id ] = SyncEvent ( )
ev_to_sync = event_to_synchronize [ base_event_id ] [ event_id ]
2014-02-24 22:02:22 +00:00
2014-02-18 17:15:08 +00:00
ev_to_sync . GG . event = event
ev_to_sync . GG . found = True
2014-02-24 22:02:22 +00:00
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
2014-02-18 17:15:08 +00:00
if ev_to_sync . GG . update :
2014-02-24 22:02:22 +00:00
ev_to_sync . GG . update = ev_to_sync . GG . update . replace ( ' T ' , ' ' ) . replace ( ' Z ' , ' ' )
2014-02-18 17:15:08 +00:00
ev_to_sync . GG . status = ( event . get ( ' status ' ) != ' cancelled ' )
2014-02-24 22:02:22 +00:00
######################
2013-12-13 16:27:52 +00:00
# PRE-PROCESSING #
######################
2013-12-10 16:45:25 +00:00
for base_event in event_to_synchronize :
for current_event in event_to_synchronize [ base_event ] :
2014-05-14 08:28:10 +00:00
event_to_synchronize [ base_event ] [ current_event ] . compute_OP ( modeFull = not lastSync )
if self . get_print_log ( cr , uid , context = context ) :
if not isinstance ( event_to_synchronize [ base_event ] [ current_event ] . OP , NothingToDo ) :
_logger . info ( event_to_synchronize [ base_event ] )
2014-02-24 22:02:22 +00:00
2013-12-13 16:27:52 +00:00
######################
# DO ACTION #
2014-02-24 22:02:22 +00:00
######################
2013-12-10 16:45:25 +00:00
for base_event in event_to_synchronize :
2014-02-24 22:02:22 +00:00
event_to_synchronize [ base_event ] = sorted ( event_to_synchronize [ base_event ] . iteritems ( ) , key = operator . itemgetter ( 0 ) )
2013-12-10 16:45:25 +00:00
for current_event in event_to_synchronize [ base_event ] :
2013-12-13 10:35:17 +00:00
cr . commit ( )
2014-02-24 22:02:22 +00:00
event = current_event [ 1 ] # event is an Sync Event !
2014-02-18 17:15:08 +00:00
actToDo = event . OP
actSrc = event . OP . src
2013-12-09 14:08:19 +00:00
2014-02-18 17:15:08 +00:00
context [ ' curr_attendee ' ] = event . OE . attendee_id
2014-01-14 13:37:36 +00:00
2014-02-18 17:15:08 +00:00
if isinstance ( actToDo , NothingToDo ) :
continue
elif isinstance ( actToDo , Create ) :
2014-02-24 22:02:22 +00:00
if actSrc == ' GG ' :
[FIX] google_calendar: user invited to one recurring event occurence only
When a Google user was invited to one occurrence of a recurring event,
but not to the recurring event itself (and the other occurrences, therefore),
and the user owner of the recurring event did not sync his calendar in Odoo,
the event occurrence could not be synced in Odoo, because it attempted
to attach it to the parent/main recurring event, which was not present
in Odoo.
In such a case, Odoo now syncs the event occurrence as a simple classic
event. In addition, if the owner of the event sync his calendar with Odoo
afterwards, or if the user is invited later to the main/parent recurring event
and then sync again his calendar,
it then attach the event occurrence that was previously
synced to this main event, to avoid events duplication.
opw-676535
2016-05-09 09:31:45 +00:00
self . create_from_google ( cr , uid , event , myPartnerID , context = context )
2014-02-24 22:02:22 +00:00
elif actSrc == ' OE ' :
2014-02-18 17:15:08 +00:00
raise " Should be never here, creation for OE is done before update ! "
#TODO Add to batch
elif isinstance ( actToDo , Update ) :
2014-02-24 22:02:22 +00:00
if actSrc == ' GG ' :
2014-02-18 17:15:08 +00:00
self . update_from_google ( cr , uid , event . OE . event , event . GG . event , ' write ' , context )
2014-02-24 22:02:22 +00:00
elif actSrc == ' OE ' :
2014-02-18 17:15:08 +00:00
self . update_to_google ( cr , uid , event . OE . event , event . GG . event , context )
elif isinstance ( actToDo , Exclude ) :
if actSrc == ' OE ' :
2014-02-24 22:02:22 +00:00
self . delete_an_event ( cr , uid , current_event [ 0 ] , context = context )
elif actSrc == ' GG ' :
2014-06-19 14:13:35 +00:00
new_google_event_id = event . GG . event [ ' id ' ] . rsplit ( ' _ ' , 1 ) [ 1 ]
2014-05-14 08:28:10 +00:00
if ' T ' in new_google_event_id :
new_google_event_id = new_google_event_id . replace ( ' T ' , ' ' ) [ : - 1 ]
else :
new_google_event_id = new_google_event_id + " 000000 "
2014-01-14 13:37:36 +00:00
2014-05-14 08:28:10 +00:00
if event . GG . status :
parent_event = { }
if not event_to_synchronize [ base_event ] [ 0 ] [ 1 ] . OE . event_id :
2014-06-19 14:13:35 +00:00
main_ev = att_obj . search_read ( cr , uid , [ ( ' google_internal_event_id ' , ' = ' , event . GG . event [ ' id ' ] . rsplit ( ' _ ' , 1 ) [ 0 ] ) ] , fields = [ ' event_id ' ] , context = context_novirtual )
[FIX] google_calendar: user invited to one recurring event occurence only
When a Google user was invited to one occurrence of a recurring event,
but not to the recurring event itself (and the other occurrences, therefore),
and the user owner of the recurring event did not sync his calendar in Odoo,
the event occurrence could not be synced in Odoo, because it attempted
to attach it to the parent/main recurring event, which was not present
in Odoo.
In such a case, Odoo now syncs the event occurrence as a simple classic
event. In addition, if the owner of the event sync his calendar with Odoo
afterwards, or if the user is invited later to the main/parent recurring event
and then sync again his calendar,
it then attach the event occurrence that was previously
synced to this main event, to avoid events duplication.
opw-676535
2016-05-09 09:31:45 +00:00
event_to_synchronize [ base_event ] [ 0 ] [ 1 ] . OE . event_id = main_ev [ 0 ] . get ( ' event_id ' ) [ 0 ] if main_ev else None
if event_to_synchronize [ base_event ] [ 0 ] [ 1 ] . OE . 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 )
else :
self . create_from_google ( cr , uid , event , myPartnerID , context = context )
2014-05-14 08:28:10 +00:00
else :
parent_oe_id = event_to_synchronize [ base_event ] [ 0 ] [ 1 ] . OE . event_id
2014-12-09 16:13:26 +00:00
if parent_oe_id :
calendar_event . unlink ( cr , uid , " %s - %s " % ( parent_oe_id , new_google_event_id ) , can_be_deleted = True , context = context )
2014-02-18 17:15:08 +00:00
elif isinstance ( actToDo , Delete ) :
if actSrc == ' GG ' :
2014-05-14 08:28:10 +00:00
try :
self . delete_an_event ( cr , uid , current_event [ 0 ] , context = context )
2015-10-16 07:52:42 +00:00
except urllib2 . HTTPError , e :
2014-05-14 08:28:10 +00:00
# if already deleted from gmail or never created
2015-10-16 07:52:42 +00:00
if e . code in ( 404 , 410 , ) :
2014-05-14 08:28:10 +00:00
pass
else :
raise e
2014-02-24 22:02:22 +00:00
elif actSrc == ' OE ' :
2014-04-30 09:36:13 +00:00
calendar_event . unlink ( cr , uid , event . OE . event_id , can_be_deleted = False , context = context )
2014-02-18 17:15:08 +00:00
return True
2014-01-14 13:37:36 +00:00
2013-12-09 14:08:19 +00:00
def check_and_sync ( self , cr , uid , oe_event , google_event , context ) :
2014-02-24 22:02:22 +00:00
if datetime . strptime ( oe_event . oe_update_date , " % Y- % m- %d % H: % M: % S. %f " ) > datetime . strptime ( google_event [ ' updated ' ] , " % Y- % m- %d T % H: % M: % S. %f z " ) :
2013-12-09 14:08:19 +00:00
self . update_to_google ( cr , uid , oe_event , google_event , context )
2014-02-24 22:02:22 +00:00
elif datetime . strptime ( oe_event . oe_update_date , " % Y- % m- %d % H: % M: % S. %f " ) < datetime . strptime ( google_event [ ' updated ' ] , " % Y- % m- %d T % H: % M: % S. %f z " ) :
2013-12-09 14:08:19 +00:00
self . update_from_google ( cr , uid , oe_event , google_event , ' write ' , context )
2014-01-14 13:37:36 +00:00
2014-02-24 22:02:22 +00:00
def get_sequence ( self , cr , uid , instance_id , context = None ) :
2014-02-18 17:15:08 +00:00
gs_pool = self . pool [ ' google.service ' ]
2014-01-14 13:37:36 +00:00
params = {
2014-02-24 22:02:22 +00:00
' fields ' : ' sequence ' ,
' access_token ' : self . get_token ( cr , uid , context )
}
2014-01-14 13:37:36 +00:00
headers = { ' Content-type ' : ' application/json ' }
2014-02-24 22:02:22 +00:00
url = " /calendar/v3/calendars/ %s /events/ %s " % ( ' primary ' , instance_id )
2014-01-14 13:37:36 +00:00
2014-08-05 08:59:02 +00:00
st , content , ask_time = gs_pool . _do_request ( cr , uid , url , params , headers , type = ' GET ' , context = context )
2014-02-24 22:02:22 +00:00
return content . get ( ' sequence ' , 0 )
#################################
2013-12-09 14:08:19 +00:00
## MANAGE CONNEXION TO GMAIL ##
#################################
2014-01-14 13:37:36 +00:00
2014-02-24 22:02:22 +00:00
def get_token ( self , cr , uid , context = None ) :
current_user = self . pool [ ' res.users ' ] . browse ( cr , uid , uid , context = context )
2014-05-14 08:28:10 +00:00
if not current_user . google_calendar_token_validity or \
datetime . strptime ( current_user . google_calendar_token_validity . split ( ' . ' ) [ 0 ] , DEFAULT_SERVER_DATETIME_FORMAT ) < ( datetime . now ( ) + timedelta ( minutes = 1 ) ) :
2014-02-24 22:02:22 +00:00
self . do_refresh_token ( cr , uid , context = context )
2013-12-02 14:31:33 +00:00
current_user . refresh ( )
return current_user . google_calendar_token
2014-05-14 08:28:10 +00:00
def get_last_sync_date ( self , cr , uid , context = None ) :
current_user = self . pool [ ' res.users ' ] . browse ( cr , uid , uid , context = context )
return current_user . google_calendar_last_sync_date and datetime . strptime ( current_user . google_calendar_last_sync_date , DEFAULT_SERVER_DATETIME_FORMAT ) + timedelta ( minutes = 0 ) or False
2014-02-24 22:02:22 +00:00
def do_refresh_token ( self , cr , uid , context = None ) :
current_user = self . pool [ ' res.users ' ] . browse ( cr , uid , uid , context = context )
2014-02-18 17:15:08 +00:00
gs_pool = self . pool [ ' google.service ' ]
2014-01-14 13:37:36 +00:00
2014-02-18 17:15:08 +00:00
all_token = gs_pool . _refresh_google_token_json ( cr , uid , current_user . google_calendar_rtoken , self . STR_SERVICE , context = context )
2014-01-14 13:37:36 +00:00
2013-12-02 14:31:33 +00:00
vals = { }
2014-01-14 13:37:36 +00:00
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 ' )
2014-02-24 22:02:22 +00:00
self . pool [ ' res.users ' ] . write ( cr , SUPERUSER_ID , uid , vals , context = context )
2013-12-02 14:31:33 +00:00
2014-02-24 22:02:22 +00:00
def need_authorize ( self , cr , uid , context = None ) :
current_user = self . pool [ ' res.users ' ] . browse ( cr , uid , uid , context = context )
return current_user . google_calendar_rtoken is False
2014-01-14 13:37:36 +00:00
2014-02-24 22:02:22 +00:00
def get_calendar_scope ( self , RO = False ) :
2014-01-14 13:37:36 +00:00
readonly = RO and ' .readonly ' or ' '
return ' https://www.googleapis.com/auth/calendar %s ' % ( readonly )
2013-12-02 14:31:33 +00:00
2014-02-24 22:02:22 +00:00
def authorize_google_uri ( self , cr , uid , from_url = ' http://www.openerp.com ' , context = None ) :
url = self . pool [ ' google.service ' ] . _get_authorize_uri ( cr , uid , from_url , self . STR_SERVICE , scope = self . get_calendar_scope ( ) , context = context )
2014-01-14 13:37:36 +00:00
return url
2014-02-24 22:02:22 +00:00
def can_authorize_google ( self , cr , uid , context = None ) :
2013-12-19 16:50:11 +00:00
return self . pool [ ' res.users ' ] . has_group ( cr , uid , ' base.group_erp_manager ' )
2014-01-14 13:37:36 +00:00
2014-02-24 22:02:22 +00:00
def set_all_tokens ( self , cr , uid , authorization_code , context = None ) :
2014-02-18 17:15:08 +00:00
gs_pool = self . pool [ ' google.service ' ]
2014-02-24 22:02:22 +00:00
all_token = gs_pool . _get_google_token_json ( cr , uid , authorization_code , self . STR_SERVICE , context = context )
2014-01-14 13:37:36 +00:00
2013-12-09 14:08:19 +00:00
vals = { }
vals [ ' google_ %s _rtoken ' % self . STR_SERVICE ] = all_token . get ( ' refresh_token ' )
2013-12-19 14:25:14 +00:00
vals [ ' google_ %s _token_validity ' % self . STR_SERVICE ] = datetime . now ( ) + timedelta ( seconds = all_token . get ( ' expires_in ' ) )
2014-01-14 13:37:36 +00:00
vals [ ' google_ %s _token ' % self . STR_SERVICE ] = all_token . get ( ' access_token ' )
2014-02-24 22:02:22 +00:00
self . pool [ ' res.users ' ] . write ( cr , SUPERUSER_ID , uid , vals , context = context )
2014-01-14 13:37:36 +00:00
2014-05-14 08:28:10 +00:00
def get_minTime ( self , cr , uid , context = None ) :
2015-05-28 14:01:42 +00:00
number_of_week = int ( self . pool [ ' ir.config_parameter ' ] . get_param ( cr , uid , ' calendar.week_synchro ' , default = 13 ) )
2014-02-24 22:02:22 +00:00
return datetime . now ( ) - timedelta ( weeks = number_of_week )
2014-02-18 17:15:08 +00:00
def get_need_synchro_attendee ( self , cr , uid , context = None ) :
2014-05-14 08:28:10 +00:00
return self . pool [ ' ir.config_parameter ' ] . get_param ( cr , uid , ' calendar.block_synchro_attendee ' , default = True )
def get_disable_since_synchro ( self , cr , uid , context = None ) :
return self . pool [ ' ir.config_parameter ' ] . get_param ( cr , uid , ' calendar.block_since_synchro ' , default = False )
def get_print_log ( self , cr , uid , context = None ) :
return self . pool [ ' ir.config_parameter ' ] . get_param ( cr , uid , ' calendar.debug_print ' , default = False )
2014-01-14 13:37:36 +00:00
2014-02-24 22:02:22 +00:00
class res_users ( osv . Model ) :
2013-12-02 14:31:33 +00:00
_inherit = ' res.users '
2014-01-14 13:37:36 +00:00
2013-12-02 14:31:33 +00:00
_columns = {
2016-05-10 14:05:47 +00:00
' google_calendar_rtoken ' : fields . char ( ' Refresh Token ' , copy = False ) ,
' google_calendar_token ' : fields . char ( ' User token ' , copy = False ) ,
' google_calendar_token_validity ' : fields . datetime ( ' Token Validity ' , copy = False ) ,
' google_calendar_last_sync_date ' : fields . datetime ( ' Last synchro date ' , copy = False ) ,
2014-05-14 08:28:10 +00:00
' google_calendar_cal_id ' : fields . char ( ' Calendar ID ' , help = ' Last Calendar ID who has been synchronized. If it is changed, we remove \
2016-05-10 14:05:47 +00:00
all links between GoogleID and Odoo Google Internal ID ' , copy=False)
2014-02-24 22:02:22 +00:00
}
2013-12-02 14:31:33 +00:00
2014-01-15 09:38:05 +00:00
class calendar_event ( osv . Model ) :
_inherit = " calendar.event "
2013-12-20 16:08:18 +00:00
2014-05-14 08:28:10 +00:00
def get_fields_need_update_google ( self , cr , uid , context = None ) :
2016-01-08 17:08:35 +00:00
recurrent_fields = self . _get_recurrent_fields ( cr , uid , context = context )
return recurrent_fields + [ ' name ' , ' description ' , ' allday ' , ' start ' , ' date_end ' , ' stop ' ,
' attendee_ids ' , ' alarm_ids ' , ' location ' , ' class ' , ' active ' ,
' start_date ' , ' start_datetime ' , ' stop_date ' , ' stop_datetime ' ]
2014-05-14 08:28:10 +00:00
2013-12-02 14:31:33 +00:00
def write ( self , cr , uid , ids , vals , context = None ) :
2013-12-20 09:57:20 +00:00
if context is None :
2014-02-24 22:02:22 +00:00
context = { }
2014-05-14 08:28:10 +00:00
sync_fields = set ( self . get_fields_need_update_google ( cr , uid , context ) )
2013-12-20 09:57:20 +00:00
if ( set ( vals . keys ( ) ) & sync_fields ) and ' oe_update_date ' not in vals . keys ( ) and ' NewMeeting ' not in context :
2013-12-02 14:31:33 +00:00
vals [ ' oe_update_date ' ] = datetime . now ( )
2013-12-20 16:08:18 +00:00
2014-01-15 09:38:05 +00:00
return super ( calendar_event , self ) . write ( cr , uid , ids , vals , context = context )
2014-01-14 13:37:36 +00:00
2013-12-02 14:31:33 +00:00
def copy ( self , cr , uid , id , default = None , context = None ) :
default = default or { }
if default . get ( ' write_type ' , False ) :
del default [ ' write_type ' ]
elif default . get ( ' recurrent_id ' , False ) :
default [ ' oe_update_date ' ] = datetime . now ( )
else :
default [ ' oe_update_date ' ] = False
2014-01-15 09:38:05 +00:00
return super ( calendar_event , self ) . copy ( cr , uid , id , default , context )
2014-01-14 13:37:36 +00:00
2014-04-30 09:36:13 +00:00
def unlink ( self , cr , uid , ids , can_be_deleted = False , context = None ) :
return super ( calendar_event , self ) . unlink ( cr , uid , ids , can_be_deleted = can_be_deleted , context = context )
2014-01-14 13:37:36 +00:00
_columns = {
2014-07-09 11:39:38 +00:00
' oe_update_date ' : fields . datetime ( ' Odoo Update Date ' ) ,
2013-12-02 14:31:33 +00:00
}
2014-01-14 13:37:36 +00:00
2014-01-13 17:41:57 +00:00
class calendar_attendee ( osv . Model ) :
2013-12-02 14:31:33 +00:00
_inherit = ' calendar.attendee '
2014-01-14 13:37:36 +00:00
2013-12-13 16:27:52 +00:00
_columns = {
2014-05-14 08:28:10 +00:00
' google_internal_event_id ' : fields . char ( ' Google Calendar Event Id ' ) ,
2014-07-09 11:39:38 +00:00
' oe_synchro_date ' : fields . datetime ( ' Odoo Synchro Date ' ) ,
2013-12-13 16:27:52 +00:00
}
2014-02-24 22:02:22 +00:00
_sql_constraints = [ ( ' google_id_uniq ' , ' unique(google_internal_event_id,partner_id,event_id) ' , ' Google ID should be unique! ' ) ]
2014-01-14 13:37:36 +00:00
2013-12-02 14:31:33 +00:00
def write ( self , cr , uid , ids , vals , context = None ) :
2013-12-13 16:27:52 +00:00
if context is None :
context = { }
2014-01-14 13:37:36 +00:00
2013-12-09 14:08:19 +00:00
for id in ids :
2014-02-24 22:02:22 +00:00
ref = vals . get ( ' event_id ' , self . browse ( cr , uid , id , context = context ) . event_id . id )
2014-01-14 13:37:36 +00:00
2013-12-20 16:08:18 +00:00
# If attendees are updated, we need to specify that next synchro need an action
2014-01-14 13:37:36 +00:00
# Except if it come from an update_from_google
2013-12-20 09:57:20 +00:00
if not context . get ( ' curr_attendee ' , False ) and not context . get ( ' NewMeeting ' , False ) :
2014-02-24 22:02:22 +00:00
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 )