From 654f9275b957df11976f9ff702a9fdda53802431 Mon Sep 17 00:00:00 2001 From: jke-openerp Date: Tue, 10 Dec 2013 17:56:09 +0100 Subject: [PATCH] [REF] Refactoring complete of synchro calendar with pre-processing bzr revid: jke@openerp.com-20131210165609-72tc122gwgxm0p5u --- addons/base_calendar/base_calendar.py | 5 +- .../google_base_account/controllers/main.py | 1 - addons/google_calendar/google_calendar.py | 501 ++++++++++++++++-- addons/google_calendar/google_calendar.pyc | Bin 22613 -> 30952 bytes .../google_calendar/static/src/css/Makefile | 4 + .../static/src/css/google_calendar.css | 4 + .../static/src/css/google_calendar.sass | 6 + 7 files changed, 464 insertions(+), 57 deletions(-) create mode 100755 addons/google_calendar/static/src/css/Makefile create mode 100644 addons/google_calendar/static/src/css/google_calendar.css create mode 100644 addons/google_calendar/static/src/css/google_calendar.sass diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py index ec83ba240ee..f118c810aac 100644 --- a/addons/base_calendar/base_calendar.py +++ b/addons/base_calendar/base_calendar.py @@ -1108,8 +1108,9 @@ class crm_meeting(osv.Model): # We remove old attendees who are not in partner_ids now. all_partner_ids = [part.id for part in event.partner_ids] - all_attendee_ids = [att.partner_id.id for att in event.attendee_ids] - partner_ids_to_remove = map(lambda x: x, set(all_attendee_ids + new_att_partner_ids) - set(all_partner_ids)) + all_part_attendee_ids = [att.partner_id.id for att in event.attendee_ids] + all_attendee_ids = [att.id for att in event.attendee_ids] + partner_ids_to_remove = map(lambda x: x, set(all_part_attendee_ids + new_att_partner_ids) - set(all_partner_ids)) attendee_ids_to_remove = [] diff --git a/addons/google_base_account/controllers/main.py b/addons/google_base_account/controllers/main.py index cb729e10c79..dd5464d7a42 100644 --- a/addons/google_base_account/controllers/main.py +++ b/addons/google_base_account/controllers/main.py @@ -70,7 +70,6 @@ class google_auth(http.Controller): } print "@@@@@@@@@@@@@@@@@ Is still used !!!!" - import ipdb; ipdb.set_trace() gc_obj.synchronize_calendar(request.cr, request.uid, calendar_info, kw.get('LocalContext')) diff --git a/addons/google_calendar/google_calendar.py b/addons/google_calendar/google_calendar.py index cc25b83f9d7..84477dbfdb8 100644 --- a/addons/google_calendar/google_calendar.py +++ b/addons/google_calendar/google_calendar.py @@ -18,11 +18,12 @@ # ############################################################################## +import operator import simplejson import re import urllib import urllib2 - +import warnings from openerp import tools from openerp.tools.translate import _ @@ -129,8 +130,7 @@ class google_calendar(osv.osv): response = gs_pool._do_request(cr, uid, url, params, headers, type='DELETE', context=context) print "@@@RESPONSE",response return response - - + def get_event_dict(self,cr,uid,token=False,nextPageToken=False,context=None): if not token: token = self.get_token(cr,uid,context) @@ -139,7 +139,8 @@ class google_calendar(osv.osv): params = { 'fields': 'items,nextPageToken', - 'access_token' : token + 'access_token' : token, +# 'orderBy' : 'id', #Allow to create the main recurrence event, before instance of it ! } headers = {'Content-type': 'application/json', 'Accept': 'text/plain'} @@ -221,57 +222,73 @@ class google_calendar(osv.osv): #TODO, il http fail, no event, do DELETE ! ? return response -################################# -## MANAGE SYNCHRO TO GMAIL ## -################################# - + def update_from_google(self, cr, uid, event, single_event_dict, type, context): + if context is None: + context= [] + context_UFG = context.copy() + context_UFG['UpdateFromGoogle'] = True + crm_meeting = self.pool['crm.meeting'] res_partner_obj = self.pool['res.partner'] calendar_attendee_obj = self.pool['calendar.attendee'] - attendee_record= [] + user_obj = self.pool.get('res.users') + myPartnerID = user_obj.browse(cr,uid,uid,context).partner_id.id + attendee_record = [] + partner_record = [(4,myPartnerID)] result = {} - + if single_event_dict.get('attendees',False): for google_attendee in single_event_dict['attendees']: if type == "write": for oe_attendee in event['attendee_ids']: - if calendar_attendee_obj.browse(cr, uid ,oe_attendee,context=context).email == google_attendee['email']: - calendar_attendee_obj.write(cr, uid,[oe_attendee] ,{'state' : oe_state_mapping[google_attendee['responseStatus']]}) + if oe_attendee.email == google_attendee['email']: + calendar_attendee_obj.write(cr, uid,[oe_attendee.id] ,{'state' : oe_state_mapping[google_attendee['responseStatus']]},context=context) google_attendee['found'] = True + continue + if google_attendee.get('found',False): continue attendee_id = res_partner_obj.search(cr, uid,[('email', '=', google_attendee['email'])], context=context) if not attendee_id: attendee_id = [res_partner_obj.create(cr, uid,{'email': google_attendee['email'], '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['partner_id'] = attendee.pop('id') + partner_record.append((4, attendee.get('id'))) + attendee['partner_id'] = attendee.pop('id') attendee['state'] = oe_state_mapping[google_attendee['responseStatus']] - attendee_record.append((0, 0, attendee)) - UTC = pytz.timezone('UTC') - if single_event_dict['start'].get('dateTime',False) and single_event_dict['end'].get('dateTime',False): - date = parser.parse(single_event_dict['start']['dateTime']) - date_deadline = parser.parse(single_event_dict['end']['dateTime']) - delta = date_deadline.astimezone(UTC) - date.astimezone(UTC) - date = str(date.astimezone(UTC))[:-6] - date_deadline = str(date_deadline.astimezone(UTC))[:-6] - allday = False - else: - date = (single_event_dict['start']['date'] + ' 00:00:00') - date_deadline = (single_event_dict['end']['date'] + ' 00:00:00') - d_start = datetime.strptime(date, "%Y-%m-%d %H:%M:%S") - d_end = datetime.strptime(date_deadline, "%Y-%m-%d %H:%M:%S") - delta = (d_end - d_start) - allday = True + attendee_record.append((0, 0, attendee)) + UTC = pytz.timezone('UTC') + 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): + date = parser.parse(single_event_dict['start']['dateTime']) + date_deadline = parser.parse(single_event_dict['end']['dateTime']) + delta = date_deadline.astimezone(UTC) - date.astimezone(UTC) + date = str(date.astimezone(UTC))[:-6] + date_deadline = str(date_deadline.astimezone(UTC))[:-6] + allday = False + else: + date = (single_event_dict['start']['date'] + ' 00:00:00') + date_deadline = (single_event_dict['end']['date'] + ' 00:00:00') + d_start = datetime.strptime(date, "%Y-%m-%d %H:%M:%S") + d_end = datetime.strptime(date_deadline, "%Y-%m-%d %H:%M:%S") + delta = (d_end - d_start) + allday = True - result['duration'] = (delta.seconds / 60) / 60.0 + delta.days *24 + result['duration'] = (delta.seconds / 60) / 60.0 + delta.days *24 - update_date = datetime.strptime(single_event_dict['updated'],"%Y-%m-%dT%H:%M:%S.%fz") + update_date = datetime.strptime(single_event_dict['updated'],"%Y-%m-%dT%H:%M:%S.%fz") + result.update({ + 'date': date, + 'date_deadline': date_deadline, + 'allday': allday + }) result.update({ 'attendee_ids': attendee_record, - 'date': date, - 'date_deadline': date_deadline, - 'allday': allday, + 'partner_ids': list(set(partner_record)), + +# 'date': date, +# 'date_deadline': date_deadline, +# 'allday': allday, 'name': single_event_dict.get('summary','Event'), 'description': single_event_dict.get('description',False), 'location':single_event_dict.get('location',False), @@ -279,20 +296,23 @@ class google_calendar(osv.osv): 'oe_update_date':update_date, 'google_internal_event_id': single_event_dict.get('id',False), }) - print "Location = <%s> vs <%s>" % (single_event_dict.get('location'),result['location']) - #import ipdb; ipdb.set_trace() + if single_event_dict.get("recurrence",False): rrule = [rule for rule in single_event_dict["recurrence"] if rule.startswith("RRULE:")][0][6:] result['rrule']=rrule if type == "write": - crm_meeting.write(cr, uid, event['id'], result, context=context) + return crm_meeting.write(cr, uid, event['id'], result, context=context) elif type == "copy": - result['write_type'] = "copy" - crm_meeting.write(cr, uid, event['id'], result, context=context) + #result['write_type'] = "copy" + result['recurrence'] = True + return crm_meeting.write(cr, uid, [event['id']], result, context=context) elif type == "create": - crm_meeting.create(cr, uid, result, context=context) - + return crm_meeting.create(cr, uid, result, context=context) +################################# +## MANAGE SYNCHRO TO GMAIL ## +################################# + def synchronize_events(self, cr, uid, ids, context=None): gc_obj = self.pool.get('google.calendar') @@ -322,6 +342,7 @@ class google_calendar(osv.osv): new_events_ids = crm_meeting.search(cr, uid,[('partner_ids', 'in', myPartnerID),('google_internal_event_id', '=', False),'|',('recurrent_id', '=', 0),('recurrent_id', '=', False)], context=context_norecurrent) for event in crm_meeting.browse(cr, uid, list(set(new_events_ids)), context): + #TODO rpelace it by a batch response = self.create_an_event(cr,uid,event,context=context) update_date = datetime.strptime(response['updated'],"%Y-%m-%dT%H:%M:%S.%fz") crm_meeting.write(cr, uid, event.id, {'google_internal_event_id': response['id'], 'oe_update_date':update_date}) @@ -332,18 +353,389 @@ class google_calendar(osv.osv): def get_empty_synchro_summarize(self) : return { - 'oe_event_id' : False, - 'oe_isRecurrence':False, - 'oe_isInstance':False, - 'oe_update':False, - 'oe_status':False, - - 'gg_isRecurrence':False, - 'gg_isInstance':False, - 'gg_update':False, - 'gg_status':False, + #OPENERP + 'OE_event' : False, + 'OE_found' : False, + 'OE_event_id' : False, + 'OE_isRecurrence':False, + 'OE_isInstance':False, + 'OE_update':False, + 'OE_status':False, + + #GOOGLE + 'GG_event' : False, + 'GG_found' : False, + 'GG_isRecurrence':False, + 'GG_isInstance':False, + 'GG_update':False, + 'GG_status':False, + + + #TO_DO_IN_GOOGLE + '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':'' + } + def update_events(self, cr, uid, context): + + + crm_meeting = self.pool['crm.meeting'] + user_obj = self.pool['res.users'] + myPartnerID = user_obj.browse(cr,uid,uid,context=context).partner_id.id + + context_novirtual = context.copy() + context_novirtual['virtual_id'] = False + context_novirtual['active_test'] = False + + 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 + events_ids = crm_meeting.search(cr, uid,[('partner_ids', 'in', myPartnerID),('google_internal_event_id', '!=', False),('oe_update_date','!=', False)],order='google_internal_event_id',context=context_novirtual) + + + event_to_synchronize = {} + for event in crm_meeting.browse(cr, uid, events_ids, context): + base_event_id = event.google_internal_event_id.split('_')[0] + + if base_event_id not in event_to_synchronize: + event_to_synchronize[base_event_id] = {} + + if event.google_internal_event_id not in event_to_synchronize[base_event_id]: + event_to_synchronize[base_event_id][event.google_internal_event_id] = self.get_empty_synchro_summarize() + + event_to_synchronize[base_event_id][event.google_internal_event_id]['OE_event'] = event + event_to_synchronize[base_event_id][event.google_internal_event_id]['OE_found'] = True + event_to_synchronize[base_event_id][event.google_internal_event_id]['OE_event_id'] = event.id + event_to_synchronize[base_event_id][event.google_internal_event_id]['OE_isRecurrence'] = event.recurrency + event_to_synchronize[base_event_id][event.google_internal_event_id]['OE_isInstance'] = bool(event.recurrent_id and event.recurrent_id > 0) + event_to_synchronize[base_event_id][event.google_internal_event_id]['OE_update'] = event.oe_update_date + event_to_synchronize[base_event_id][event.google_internal_event_id]['OE_status'] = event.active + + + for event in all_event_from_google.values(): + event_id = event.get('id') + base_event_id = event_id.split('_')[0] + + if base_event_id not in event_to_synchronize: + 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]['GG_event'] = event + 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') + + + + print " $ Event IN Google " + print " $-----------------" + for ev in all_event_from_google: + print ' $ %s (%s) [%s]' % (all_event_from_google[ev].get('id'), all_event_from_google[ev].get('sequence'),all_event_from_google[ev].get('status')) + print " $-----------------" + print "" + print " $ Event IN OPENERP " + print " $------------------" + for event in crm_meeting.browse(cr, uid, events_ids, context): + print ' $ %s (%s) [%s]' % (event.google_internal_event_id, event.id,event.active) + print " $------------------" + + + for base_event in event_to_synchronize: + for current_event in event_to_synchronize[base_event]: + event = event_to_synchronize[base_event][current_event] + + #If event are already in Gmail and in OpenERP + 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 not event['GG_update']: + print "### Should never be here : L462" + raise("error L 462") + + if event['OE_update'] != event['GG_update']: + if event['OE_update'] < event['GG_update']: + event['td_source'] = 'GG' + elif event['OE_update'] > event['GG_update']: + event['td_source'] = 'OE' + else: + 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 a exclu' + else: + event['td_action'] = "UPDATE" + event['td_comment'] = 'Simply Update... I\'m a single event' + + 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']: + print "### Should never be here !!" + raise("error L 487") + 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' + + print " $ Event Merged " + print " $-----------------" + for base_event in event_to_synchronize: + print "Base Event : %s " % base_event + 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]: + event = current_event[1] + print " Real Event %s (%s)" % (current_event[0],event['OE_event_id']) + 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 " 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']) + + + actToDo = event['td_action'] + actSrc = event['td_source'] + if not actToDo: + raise ("#!? WHAT I NEED TO DO ????") + else: + if actToDo == 'None': + continue + elif actToDo == 'CREATE': + if actSrc == 'GG': + res = self.update_from_google(cr, uid, False, event['GG_event'], "create", context) + event['OE_event_id'] = res + elif actSrc == 'OE': + raise "Should be never here, creation for OE is done before update !" + #Add to batch + elif actToDo == 'UPDATE': + if actSrc == 'GG': + self.update_from_google(cr, uid, event['OE_event'], event['GG_event'], 'write', context) + elif actSrc == 'OE': + self.update_to_google(cr, uid, event['OE_event'], event['GG_event'], context) + elif actToDo == 'EXCLUDE' : + if actSrc == 'OE': + self.delete_an_event(cr,uid,current_event[0],context=context) + elif actSrc == 'GG': + print "NEED TO EXLUDE FROM GMAIL !!!!" + new_google_event_id = event['GG_event']['id'].split('_')[1] + 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" + + if event['GG_status']: + parent_event = {} + parent_event['id'] = "%s-%s" % (event_to_synchronize[base_event][0][1].get('OE_event_id') , new_google_event_id) + res = self.update_from_google(cr, uid, parent_event, event['GG_event'], "copy", context) + print res + else: + if event_to_synchronize[base_event][0][1].get('OE_event_id'): + parent_oe_id = event_to_synchronize[base_event][0][1].get('OE_event_id') + crm_meeting.unlink(cr,uid,"%s-%s" % (parent_oe_id,new_google_event_id),unlink_level=1,context=context) + else: + raise "Need to delete !" + + elif actToDo == 'DELETE': + if actSrc == 'GG': + self.delete_an_event(cr,uid,current_event[0],context=context) + elif actSrc == 'OE': + crm_meeting.unlink(cr,uid,event['OE_event_id'],unlink_level=0,context=context) + return True +# +# 'oe_event_id' : False, +# 'oe_isRecurrence':False, +# 'oe_isInstance':False, +# 'oe_update':False, +# 'oe_status':False, +# +# #GOOGLE +# 'GG_isRecurrence':False, +# 'GG_isInstance':False, +# 'GG_update':False, +# 'GG_status':False, +# + + + #For each Event in MY CALENDAR (ALL has been already create in GMAIL in the past) + + # WARNING, NEED TO KEEP IDS SORTED !!! + # AS THAT, WE THREAT ALWAYS THE PARENT BEFORE THE RECURRENT + + for event_id in events_ids: + event = crm_meeting.browse(cr, uid, event_id, context) + cr.commit() + + # IF I HAVE BEEN DELETED FROM GOOGLE + if event.google_internal_event_id not in all_event_from_google: + print " __ !! OERP %s (%s) NOT IN google" % (event.google_internal_event_id,event.id) + + #If m the parent, we delete all all recurrence + if recurrency: + print "Master Event" + #If single i can delete + elif not event.recurrent_id or event.recurrent_id == 0: + print " __ !! Single Event (%s) has been delete in google" % (event.google_internal_event_id) + ids_deleted = crm_meeting.delete(cr,uid,event.id,context=context) + #ids should be alway single + assert len(ids_deleted)==1,"Warning, recurrent event (%s) deleted as a single event" % event.google_internal_event_id + print "IDS DELETED : ",ids_deleted + for id_deleted in [x for x in ids_deleted if x in events_ids]: + events_ids.remove(id_deleted) + #elif recurrency not event.recurrent_id or event.recurrent_id == 0: + + else: # I 'm a recurrence, removed from gmail + print "Unlink me simply ? Where i m passed ?" + raise "Unlink me simply ? Where i m passed ?" + + + else: + print " __ OERP %s (%s) IN google" % (event.google_internal_event_id,event.id) + + if event.active == False: + if all_event_from_google[event.google_internal_event_id].get('status')!='cancelled': + print " __ !! Event (%s) has been removed from OPENERP" % (event.google_internal_event_id) + #if len(crm_meeting.get_linked_ids(cr,uid,event.id,show_unactive=False,context=context)) == 1: #IF I'M ALONE + if crm_meeting.count_left_instance(cr,uid,event.id,context=context)==0: + print "COUNT LEFT INTANCE===" + print crm_meeting.count_left_instance(cr,uid,event.id,context=context) + temp = crm_meeting.get_linked_ids(cr,uid,event.id,show_unactive=False,context=context) + print "IDS LINKEND : IM ALONE = ",temp + print "@1___DELETE FROM GOOGLE THE EVENT AND DELETE FROM OPENERP : ",event.id + print "delete event from google : ",event.google_internal_event_id.split('_')[0] + print "delete event from openerp : ",event.id + + content = self.delete_an_event(cr,uid,event.google_internal_event_id.split('_')[0],context=context_novirtual) + ids_deleted = crm_meeting.delete(cr,uid,event.id,context=context_novirtual) + print "IDS DELETED : ",ids_deleted + for id_deleted in ids_deleted: + if id_deleted in events_ids: + events_ids.remove(id_deleted) + else : + print "@2___DELETE FROM GOOGLE THE EVENT AND HIDE FROM OPENERP : %s [%s]" % (event.id,event.google_internal_event_id) + content = self.delete_an_event(cr,uid,event.google_internal_event_id,context=context_novirtual) + crm_meeting.unlink(cr,uid,event.id,unlink_level=0,context=context) + + elif all_event_from_google[event.google_internal_event_id].get('status')=='cancelled': + print "@3___HAS BEEN REMOVED IN GOOGLE, HIDE IT IN OPENERP : ",event.id + crm_meeting.unlink(cr,uid,event.id,unlink_level=1,context=context) #Try to delete really in db if not recurrent + else: + print "@4___NEED UPDATE : %s " % (event.id) + self.check_and_sync(cr, uid, event, all_event_from_google[event.google_internal_event_id], context) + + if event.google_internal_event_id in all_new_event_from_google: + del all_new_event_from_google[event.google_internal_event_id] + + #FOR EACH EVENT CREATE IN GOOGLE, WE ADD THEM IN OERP + print " $ New Event IN Google " + print " $-----------------" + for ev in all_new_event_from_google: + print ' $ %s (%s) [%s]' % (all_new_event_from_google[ev].get('id'), all_new_event_from_google[ev].get('sequence'),all_new_event_from_google[ev].get('status')) + print " $-----------------" + print "" + + for new_google_event in all_new_event_from_google.values(): + if new_google_event.get('status','') == 'cancelled': + continue +# print "#### IN FOR #########" + elif new_google_event.get('recurringEventId',False): + + reccurent_event = crm_meeting.search(cr, uid, [('google_internal_event_id', '=', new_google_event['recurringEventId'])]) + + new_google_event_id = new_google_event['id'].split('_')[1] + 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" + print "#############rec_event : ",reccurent_event + print "Google id : %s [%s]" % (new_google_event_id,new_google_event['id']) + for event_id in reccurent_event: + print "EVENT_ID = %s (%s)" % (event_id,event_id.split('-')[1]) + + if isinstance(event_id, str) and len(event_id.split('-'))>1 and event_id.split('-')[1] == new_google_event_id: + reccurnt_event_id = int(event_id.split('-')[0].strip()) + parent_event = crm_meeting.read(cr,uid, reccurnt_event_id, [], context) + parent_event['id'] = event_id + #recurrent update from google + + if new_google_event.get('status','') == 'cancelled': + print 'unlink -> cancelled in google' + crm_meeting.unlink(cr,uid,event_id,context) + else: + print "DO COPY?" + self.update_from_google(cr, uid, parent_event, new_google_event, "copy", context) + else: + print "ELSE" + elif new_google_event.get('recurrence',False) != False: #If was origin event from recurrent: + print "NEED TO CHECK IF AN INSTANCE ACTIVE..." + if True: #if a instance exist + self.update_from_google(cr, uid, False, new_google_event, "create", context) + # + else: + self.delete_an_event(cr, uid, new_google_event, context) + print ''#ELSE WE DELETE THE ORIGIN EVENT + else : + print "@and not recurring event" + #new event from google + self.update_from_google(cr, uid, False, new_google_event, "create", context) + # del google_events_dict[new_google_event['id']] + return True + def bind_recurring_events_to_google(self, cr, uid, context): crm_meeting = self.pool['crm.meeting'] @@ -395,7 +787,7 @@ class google_calendar(osv.osv): content = gs_pool._do_request(cr, uid, url, params, headers, type='GET', context=context) return content.get('sequence',0) - def update_events(self, cr, uid, context): + def update_events_ORI(self, cr, uid, context): crm_meeting = self.pool['crm.meeting'] user_obj = self.pool['res.users'] myPartnerID = user_obj.browse(cr,uid,uid,context=context).partner_id.id @@ -641,8 +1033,9 @@ class calendar_attendee(osv.osv): def write(self, cr, uid, ids, vals, context=None): for id in ids: - ref = vals.get('event_id',self.browse(cr,uid,id,context=context).event_id) - self.pool.get('crm.meeting').write(cr, uid, ref, {'oe_update_date':datetime.now()}) + ref = vals.get('event_id',self.browse(cr,uid,id,context=context).event_id.id) + #ToDo pass value in context to not force update when attendee come from update_from_google + self.pool.get('crm.meeting').write(cr, uid, ref, {'oe_update_date':datetime.now()},context) return super(calendar_attendee, self).write(cr, uid, ids, vals, context=context) diff --git a/addons/google_calendar/google_calendar.pyc b/addons/google_calendar/google_calendar.pyc index a323743f43b42695956349de190203e0a94a63d4..0f8fa4b4387a1353353b59c7c4a89efdf5ad9a06 100644 GIT binary patch delta 11225 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 delta 4123 zcmaJETW}j!_1x9Vl4V(gzAXx`!UdVbOj<5mZ4Ulbwc%vof1g#0OK8X8j zdVYxeg`Nwv0A!mX-VC8^5aK~gq)w1&eE#h|7UD71rM7_51Zog6L6~Hq_~0zSGQd6Y zFev_2j6jXi3QF@TMzF?+fD&58XsI#U%FnW9R? zu9zEA^9y1~;5b!`1`~tyW`T!=dz>lKk!XqG{3M9uq>&O9thVxH+nWw{YxxEDYZ6PB zFM4l~*h2YdjUzTDm3;x(#=cNagOB%*j=c-aojL<6W-52LeL!2i)4&dV!;tgi<7I?Nt~TnQOgdHG-&Lu{gI8C^AHqIh7m;DHRrfdip{p`$dz8Pe3v2FRfG0MUv* zS}rWD2rXH#R87Z+B_f9^Chgu(t2xR>p{6eXvUC)9kH** z@l}O4V7=oyEB)0y*ej|8WABB?qy#N{@2L2^v7(}{vE$aI?A<8#Upo|Aq0kB$Y$OAu ztY5L=@Pq`jS8Spn2Vre70tNh|*&!IE!maJ*{q}+jGPOO4+u8>a6129kov~a}h;I~| z|EyivDC}&)k|o81)#`sI&6v>KEHs}Mj;h;k#e)q!V7mgCh;6|ZHqKvII~jt}HhNi&_#MYl&sdyO5@c|$yTXIIZQ z>XHk3+Ef$f(u|5*5Fn+iNmGqQ$kOcuwh}moK(J5h`2|DeAMA<_Vq=BF`kbX^s7XC_ zO2$qLCNa>8V$#7qlb?|{;*G0Lb+9IWXHRdZi@9)YT`m@u z)}Y>2)*yM=I@B&d(sP}$Soz`gW!7odqk|cYC#UL(v|`}q1W4y(4IlC%zblqti~LKm z*1;kXHW3&ka32B6iTnTpF<~ujm}0_)YVtqDcJY_GJNaneL)$-!65H^kHd+w@7LaH@ zT^Nl=+9UO|cGkj%Y$+4~x+!Ji+#-;6Ke}OOX(C2x8yB(W)r2~)=1dG0+Z6zg(}t|3 z=5$@nrBv*S723WW=9wsNi!wK(;IdXn$TQ~*VPR_Ozbyz_)xsK~grrp_aAcX_GySJK z#%Oj_iok4``^qI*&+^s%L8vbN zVwU|?>dk^0k5R%5F9N-i16 z>E88>AKQJNpE|DjP0GYvPD|&e6B<^E#(#eN{qqsj}b$xsS`0p)l^gE7xoS(!W>Tf_$? zesS^xE|JKqz;B!CVpsU-{zLq^sep8gRDN;F!=zg!{^L_G*8hQY|BN8!)%M38rIpX~uxHdiO6>^jV89l!`{ch)LgkKY8&uD?Ry*O`!iV*t@_82E?V*_}P z$J+Tb+J**F7mGcf&#C;^THme*kDpC{sil>)xg`GvNio`s@^u1#2YxYk#`#ag4`FihXISX-h>ICbt4oGl z&CKPQe%IrqaSb?|O-ri8wb}2w64pze&Hi*nL8HOh2BT9 lwAwPQq?La+KbSqjA6*Q1DKamf(|FnVbBhCxj)*_f@o#4?KFa_A diff --git a/addons/google_calendar/static/src/css/Makefile b/addons/google_calendar/static/src/css/Makefile new file mode 100755 index 00000000000..2071c694b4c --- /dev/null +++ b/addons/google_calendar/static/src/css/Makefile @@ -0,0 +1,4 @@ +google_calendar.css: google_calendar.sass + sass --trace -t expanded google_calendar.sass google_calendar.css + + \ No newline at end of file diff --git a/addons/google_calendar/static/src/css/google_calendar.css b/addons/google_calendar/static/src/css/google_calendar.css new file mode 100644 index 00000000000..36e102f2101 --- /dev/null +++ b/addons/google_calendar/static/src/css/google_calendar.css @@ -0,0 +1,4 @@ +@charset "utf-8"; +.openerp .oe_cal_sync_button { + margin: 20 0 20 0; +} diff --git a/addons/google_calendar/static/src/css/google_calendar.sass b/addons/google_calendar/static/src/css/google_calendar.sass new file mode 100644 index 00000000000..8a07766e740 --- /dev/null +++ b/addons/google_calendar/static/src/css/google_calendar.sass @@ -0,0 +1,6 @@ +@charset "utf-8" + +.openerp + .oe_cal_sync_button + margin: 20 0 20 0 + text-align:center \ No newline at end of file