From 9134c791759fe4c503db9e69778369b6db02556b Mon Sep 17 00:00:00 2001 From: jke-openerp Date: Mon, 9 Dec 2013 15:08:19 +0100 Subject: [PATCH] [REF] Synchro method create-delete-update, to replace with always active=False and pre-processing bzr revid: jke@openerp.com-20131209140819-v0njlfjvl2biep2m --- addons/base_calendar/base_calendar.py | 449 +++++++------- .../static/src/css/base_calender.css | 4 + .../google_base_account/controllers/main.py | 87 ++- .../google_base_account.py | 41 +- addons/google_calendar/__init__.py | 1 - addons/google_calendar/__init__.pyc | Bin 204 -> 179 bytes addons/google_calendar/__openerp__.py | 4 +- addons/google_calendar/google_calendar.py | 558 +++++++++++++++--- addons/google_calendar/google_calendar.pyc | Bin 10366 -> 22613 bytes .../google_calendar/google_calendar_data.xml | 19 +- .../google_calendar/google_calendar_view.xml | 65 -- .../static/src/js/calendar_sync.js | 22 +- .../static/src/xml/web_calendar.xml | 4 +- addons/google_calendar/wizard/__init__.py | 1 - addons/google_calendar/wizard/crm_meeting.py | 269 --------- .../wizard/crm_meeting_view.xml | 35 -- 16 files changed, 805 insertions(+), 754 deletions(-) delete mode 100644 addons/google_calendar/google_calendar_view.xml delete mode 100644 addons/google_calendar/wizard/__init__.py delete mode 100644 addons/google_calendar/wizard/crm_meeting.py delete mode 100644 addons/google_calendar/wizard/crm_meeting_view.xml diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py index c855e5ba882..ec83ba240ee 100644 --- a/addons/base_calendar/base_calendar.py +++ b/addons/base_calendar/base_calendar.py @@ -37,47 +37,6 @@ from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FO from openerp.tools.translate import _ -def get_recurrent_dates(rrulestring, startdate, exdate=None, tz=None, context=None): - """Get recurrent dates based on Rule string considering exdate and start date. - - All input dates and output dates are in UTC. Dates are infered - thanks to rules in the ``tz`` timezone if given, else it'll be in - the current local timezone as specified in the context. - - @param rrulestring: rulestring (ie: 'FREQ=DAILY;INTERVAL=1;COUNT=3') - @param exdate: string of dates separated by commas (ie: '20130506220000Z,20130507220000Z') - @param startdate: string start date for computing recurrent dates - @param tz: pytz timezone for computing recurrent dates - @return: list of Recurrent dates - - """ - - exdate = exdate.split(',') if exdate else [] - startdate = pytz.UTC.localize(datetime.strptime(startdate, "%Y-%m-%d %H:%M:%S")) - - def todate(date): - val = parser.parse(''.join((re.compile('\d')).findall(date))) - ## Dates are localized to saved timezone if any, else current timezone. - if not val.tzinfo: - val = pytz.UTC.localize(val) - return val.astimezone(timezone) - - timezone = pytz.timezone(tz or context.get('tz') or 'UTC') - - if not startdate: - startdate = datetime.now() - - ## Convert the start date to saved timezone (or context tz) as it'll - ## define the correct hour/day asked by the user to repeat for recurrence. - startdate = startdate.astimezone(timezone) - rset1 = rrule.rrulestr(str(rrulestring), dtstart=startdate, forceset=True) - for date in exdate: - datetime_obj = todate(date) - rset1._exdate.append(datetime_obj) - - print "CASE 1 ", [d.astimezone(pytz.UTC) for d in rset1] - print "CASE 2 ", [d for d in rset1] - return [d.astimezone(pytz.UTC) for d in rset1] def base_calendar_id2real_id(base_calendar_id=None, with_date=False): @@ -118,15 +77,15 @@ class calendar_attendee(osv.osv): _name = 'calendar.attendee' _description = 'Attendee information' - def _get_address(self, name=None, email=None): - """ - Gives email information in ical CAL-ADDRESS type format. - @param name: name for CAL-ADDRESS value - @param email: email address for CAL-ADDRESS value - """ - if name and email: - name += ':' - return (name or '') + (email and ('MAILTO:' + email) or '') +# def _get_address(self, name=None, email=None): +# """ +# Gives email information in ical CAL-ADDRESS type format. +# @param name: name for CAL-ADDRESS value +# @param email: email address for CAL-ADDRESS value +# """ +# if name and email: +# name += ':' +# return (name or '') + (email and ('MAILTO:' + email) or '') def _compute_data(self, cr, uid, ids, name, arg, context=None): """ @@ -148,17 +107,11 @@ class calendar_attendee(osv.osv): result[id][name] = attdata.email or '' if name == 'event_date': - if attdata.ref: - result[id][name] = attdata.ref.date - else: - result[id][name] = False - + result[id][name] = attdata.event_id.date + if name == 'event_end_date': - if attdata.ref: - result[id][name] = attdata.ref.date_deadline - else: - result[id][name] = False - + result[id][name] = attdata.event_id.date_deadline + return result _columns = { @@ -171,7 +124,7 @@ class calendar_attendee(osv.osv): 'event_end_date': fields.function(_compute_data, string='Event End Date', type="datetime", multi='event_end_date'), 'availability': fields.selection([('free', 'Free'), ('busy', 'Busy')], 'Free/Busy', readonly="True"), 'access_token':fields.char('Invitation Token', size=256), - 'ref': fields.many2one('crm.meeting','Meeting linked'), + 'event_id': fields.many2one('crm.meeting','Meeting linked'), } _defaults = { 'state': 'needs-action', @@ -275,39 +228,36 @@ class calendar_attendee(osv.osv): if not isinstance(ids, (tuple, list)): ids = [ids] - - - print "IDS to send = ", ids + for attendee in self.browse(cr, uid, ids, context=context): - res_obj = attendee.ref - if res_obj: - dummy,template_id = data_pool.get_object_reference(cr, uid, 'base_calendar', template_xmlid) - dummy,act_id = data_pool.get_object_reference(cr, uid, 'base_calendar', "view_crm_meeting_calendar") - body = template_pool.browse(cr, uid, template_id, context=context).body_html + + dummy,template_id = data_pool.get_object_reference(cr, uid, 'base_calendar', template_xmlid) + dummy,act_id = data_pool.get_object_reference(cr, uid, 'base_calendar', "view_crm_meeting_calendar") + body = template_pool.browse(cr, uid, template_id, context=context).body_html + + if attendee.email and email_from: + ics_file = self.get_ics_file(cr, uid, attendee.event_id, context=context) + local_context['att_obj'] = attendee + local_context['color'] = color + local_context['action_id'] = self.pool.get('ir.actions.act_window').search(cr, uid, [('view_id','=',act_id)], context=context)[0] + local_context['dbname'] = cr.dbname + local_context['base_url'] = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url', default='http://localhost:8069', context=context) + vals = template_pool.generate_email(cr, uid, template_id, attendee.event_id.id, context=local_context) - if attendee.email and email_from: - ics_file = self.get_ics_file(cr, uid, res_obj, context=context) - local_context['att_obj'] = attendee - local_context['color'] = color - local_context['action_id'] = self.pool.get('ir.actions.act_window').search(cr, uid, [('view_id','=',act_id)], context=context)[0] - local_context['dbname'] = cr.dbname - local_context['base_url'] = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url', default='http://localhost:8069', context=context) - vals = template_pool.generate_email(cr, uid, template_id, res_obj.id, context=local_context) - - if ics_file: - vals['attachment_ids'] = [(0,0,{'name': 'invitation.ics', - 'datas_fname': 'invitation.ics', - 'datas': str(ics_file).encode('base64')})] - - vals['model'] = None #We don't want to have the mail in the tchatter while in queue! - vals['auto_delete'] = True #We don't need mail after it has been sended ! - - if (vals['email_to']== attendee.partner_id.email): - vals['email_to'] = '' - vals['recipient_ids'] = [(4,attendee.partner_id.id),] - - if not attendee.partner_id.opt_out: - mail_id.append(mail_pool.create(cr, uid, vals, context=context)) + if ics_file: + vals['attachment_ids'] = [(0,0,{'name': 'invitation.ics', + 'datas_fname': 'invitation.ics', + 'datas': str(ics_file).encode('base64')})] + + vals['model'] = None #We don't want to have the mail in the tchatter while in queue! + vals['auto_delete'] = True #We don't need mail after it has been sended ! + + if (vals['email_to']== attendee.partner_id.email): + vals['email_to'] = '' + vals['recipient_ids'] = [(4,attendee.partner_id.id),] + + if not attendee.partner_id.opt_out: + mail_id.append(mail_pool.create(cr, uid, vals, context=context)) if mail_id: try: @@ -348,7 +298,7 @@ class calendar_attendee(osv.osv): res = self.write(cr, uid, ids, {'state': 'accepted'}, context) for attendee in self.browse(cr, uid, ids, context=context): if attendee.ref: - meeting_obj.message_post(cr, uid, attendee.ref.id, body=_(("%s has accepted invitation") % (attendee.cn)),subtype="base_calendar.subtype_invitation", context=context) + meeting_obj.message_post(cr, uid, attendee.event_id.id, body=_(("%s has accepted invitation") % (attendee.cn)),subtype="base_calendar.subtype_invitation", context=context) return res @@ -362,8 +312,7 @@ class calendar_attendee(osv.osv): meeting_obj = self.pool.get('crm.meeting') res = self.write(cr, uid, ids, {'state': 'declined'}, context) for attendee in self.browse(cr, uid, ids, context=context): - if attendee.ref: - meeting_obj.message_post(cr, uid, attendee.ref.id, body=_(("%s has declined invitation") % (attendee.cn)),subtype="base_calendar.subtype_invitation", context=context) + meeting_obj.message_post(cr, uid, attendee.event_id.id, body=_(("%s has declined invitation") % (attendee.cn)),subtype="base_calendar.subtype_invitation", context=context) return res def create(self, cr, uid, vals, context=None): @@ -410,7 +359,6 @@ class calendar_alarm_manager(osv.osv): def get_next_potential_limit_alarm(self,cr,uid,seconds, notif=True, mail=True, partner_id=None, context=None): res = {} - print "Search for partner: ", partner_id base_request = """ SELECT crm.id, @@ -465,7 +413,6 @@ class calendar_alarm_manager(osv.osv): #Add filter on hours tuple_params += (seconds,seconds,) - print(tuple_params) cr.execute(""" SELECT * @@ -489,8 +436,7 @@ class calendar_alarm_manager(osv.osv): res[event_id]['min_duration'] = min_duration res[event_id]['max_duration'] = max_duration res[event_id]['rrule'] = rrule - - print "All event from SQL : ",res + return res def do_check_alarm_for_one_date(self,cr,uid,one_date,event, event_maxdelta,in_the_next_X_seconds,after=False,notif=True, mail=True,context=None): @@ -525,7 +471,6 @@ class calendar_alarm_manager(osv.osv): else: print "Not in condition..." - print "DATE SERVER:", datetime.now(); return res def do_run_scheduler_mail(self,cr,uid,context=None): @@ -548,8 +493,7 @@ class calendar_alarm_manager(osv.osv): if not cron_interval: raise ("Cron delay for " + self._name + " not calculated :( !") - - print "Cron interval = ",cron_interval + all_events = self.get_next_potential_limit_alarm(cr,uid,cron_interval,notif=False,context=context) for event in all_events: #.values() @@ -558,7 +502,7 @@ class calendar_alarm_manager(osv.osv): if curEvent.recurrency: bFound = False LastFound = False - for one_date in get_recurrent_dates(curEvent.rrule, curEvent.date, curEvent.exdate, curEvent.vtimezone, context=context) : + for one_date in self.pool.get('crm.meeting').get_recurrent_date_by_event(cr,uid,curEvent, context=context) : in_date_format = datetime.strptime(one_date, '%Y-%m-%d %H:%M:%S'); LastFound = self.do_check_alarm_for_one_date(cr,uid,in_date_format,curEvent,max_delta,cron_interval,notif=False,context=context) if LastFound: @@ -582,8 +526,7 @@ class calendar_alarm_manager(osv.osv): ajax_check_every_seconds = 300 partner = self.pool.get('res.users').browse(cr,uid,uid,context=context).partner_id; - print "Last alert for partner : ",partner.cal_last_notif - + all_notif = [] all_events = self.get_next_potential_limit_alarm(cr,uid,ajax_check_every_seconds,partner_id=partner.id,mail=False,context=context) @@ -595,7 +538,7 @@ class calendar_alarm_manager(osv.osv): if curEvent.recurrency: bFound = False LastFound = False - for one_date in get_recurrent_dates(curEvent.rrule, curEvent.date, curEvent.exdate, curEvent.vtimezone, context=context) : + for one_date in self.pool.get("crm.meeting").get_recurrent_date_by_event(cr,uid,curEvent, context=context) : in_date_format = datetime.strptime(one_date, '%Y-%m-%d %H:%M:%S'); LastFound = self.do_check_alarm_for_one_date(cr,uid,in_date_format,curEvent,max_delta,ajax_check_every_seconds,after=partner.cal_last_notif,mail=False,context=context) if LastFound: @@ -608,7 +551,6 @@ class calendar_alarm_manager(osv.osv): else: in_date_format = datetime.strptime(curEvent.date, '%Y-%m-%d %H:%M:%S'); LastFound = self.do_check_alarm_for_one_date(cr,uid,in_date_format,curEvent,max_delta,ajax_check_every_seconds,partner.cal_last_notif,mail=False,context=context) - print "Lastfound = ",LastFound if LastFound: for alert in LastFound: all_notif.append(self.do_notif_reminder(cr,uid,alert,context=context)) @@ -616,7 +558,6 @@ class calendar_alarm_manager(osv.osv): return all_notif def do_mail_reminder(self,cr,uid,alert,context=None): - print 'in Do mail reminder' if context is None: context = {} res = False @@ -649,7 +590,7 @@ class calendar_alarm_manager(osv.osv): local_context['action_id'] = self.pool.get('ir.actions.act_window').search(cr, uid, [('view_id','=',act_id)], context=context)[0] local_context['dbname'] = cr.dbname local_context['base_url'] = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url', default='http://localhost:8069', context=context) - vals = template_pool.generate_email(cr, uid, template_id, attendee.ref.id, context=local_context) + vals = template_pool.generate_email(cr, uid, template_id, attendee.event_id.id, context=local_context) vals['model'] = None #We don't want to have the mail in the tchatter while in queue! vals['auto_delete'] = True #We don't need mail after it has been sended ! @@ -660,9 +601,6 @@ class calendar_alarm_manager(osv.osv): if not attendee.partner_id.opt_out: mail_ids.append(mail_pool.create(cr, uid, vals, context=local_context)) - else: - print "attendee no email or mail from not found", attendee.email - print 'Mail ids : ',mail_ids if mail_ids: try: res = mail_pool.send(cr, uid, mail_ids, context=local_context) @@ -701,30 +639,6 @@ class calendar_alarm_manager(osv.osv): print "SHOULD BE AN NOTIF ALARM :( FOR EVENT %s / ALARM %s" % (alert['event_id'],alert['alarm_id']) -# -# def do_run_stack_scheduler(self,cr,uid,context=None): -# all_events = self.get_next_potential_limit_alarm(cr,uid,self.EVENT_ALARM_STACK_HOURS,context=context) -# for event in all_events: #.values() -# max_delta = all_events[event]['max_duration']; -# curEvent = self.pool.get('crm.meeting').browse(cr,uid,event,context=context) -# if curEvent.recurrency: -# bFound = False -# bLastFournd = False -# for one_date in get_recurrent_dates(curEvent.rrule,curEvent.date) : -# in_date_format = datetime.strptime(one_date, '%Y-%m-%d %H:%M:%S'); -# bLastFound = self.do_check_alarm_for_one_date(cr,uid,in_date_format,curEvent,max_delta,context=context) -# if bLastFound and not bFound: #if it's the first alarm for this recurrent event -# bFound = True -# if bFound and not bLastFound: #if the precendent event had alarm but not this one, we can stop the search fot this event -# break -# else: -# in_date_format = datetime.strptime(curEvent.date, '%Y-%m-%d %H:%M:%S'); -# self.do_check_alarm_for_one_date(cr,uid,in_date_format,curEvent,max_delta,context=context) -# -# #Purge all done - - - class calendar_alarm(osv.osv): _name = 'calendar.alarm' _description = 'Event alarm' @@ -820,19 +734,6 @@ def exp_report(db, uid, object, ids, data=None, context=None): openerp.service.report.exp_report = exp_report - - - - -class ________OLD_CRM_MEETING(): - _name = 'TEMP' - - - - - - - class crm_meeting_type(osv.Model): _name = 'crm.meeting.type' _description = 'Meeting Type' @@ -840,6 +741,7 @@ class crm_meeting_type(osv.Model): 'name': fields.char('Name', size=64, required=True, translate=True), } + class crm_meeting(osv.Model): """ Model for CRM meetings """ _name = 'crm.meeting' @@ -850,6 +752,39 @@ class crm_meeting(osv.Model): def do_run_scheduler(self,cr,uid,id,context=None): self.pool.get('calendar.alarm_manager').do_run_scheduler(cr,uid,context=context) + def get_recurrent_date_by_event(self,cr,uid,event,context=None): + """Get recurrent dates based on Rule string and all event where recurrent_id is child + """ + + def todate(date): + val = parser.parse(''.join((re.compile('\d')).findall(date))) + ## Dates are localized to saved timezone if any, else current timezone. + if not val.tzinfo: + val = pytz.UTC.localize(val) + return val.astimezone(timezone) + + timezone = pytz.timezone(event.vtimezone or context.get('tz') or 'UTC') + + startdate = pytz.UTC.localize(datetime.strptime(event.date, "%Y-%m-%d %H:%M:%S")) #Add "+hh:mm" timezone + if not startdate: + startdate = datetime.now() + + ## Convert the start date to saved timezone (or context tz) as it'll + ## define the correct hour/day asked by the user to repeat for recurrence. + startdate = startdate.astimezone(timezone) #transform "+hh:mm" timezone + + rset1 = rrule.rrulestr(str(event.rrule), dtstart=startdate, forceset=True) + + ids_depending = self.search(cr,uid,[('recurrent_id','=',event.id),'|',('active','=',False),('active','=',True)],context=context) + all_events = self.browse(cr,uid,ids_depending,context=context) + + for ev in all_events: + rset1._exdate.append(todate(ev.recurrent_id_date)) + #rset1.rdate(pytz.UTC.localize(datetime.strptime(ev.date, "%Y-%m-%d %H:%M:%S"))) + + return [d.astimezone(pytz.UTC) for d in rset1] + + def _get_recurrency_end_date(self, data, context=None): if data.get('recurrency') and data.get('end_type') in ('count', unicode('count')): data_date_deadline = datetime.strptime(data.get('date_deadline'), '%Y-%m-%d %H:%M:%S') @@ -946,13 +881,17 @@ class crm_meeting(osv.Model): result[event] = "" return result - def _rrule_write(self, obj, cr, uid, ids, field_name, field_value, args, context=None): + def _rrule_write(self, cr, uid, ids, field_name, field_value, args, context=None): + if not isinstance(ids, list): + ids = [ids] data = self._get_empty_rrule_data() if field_value: + data['recurrency'] = True for event in self.browse(cr, uid, ids, context=context): - rdate = rule_date or event.date #TO CHECK :/ + rdate = event.date update_data = self._parse_rrule(field_value, dict(data), rdate) + print 'UPDATE_DATA = ',update_data data.update(update_data) self.write(cr, uid, ids, data, context=context) return True @@ -997,12 +936,12 @@ class crm_meeting(osv.Model): #'state': fields.selection([('tentative', 'Uncertain'),('cancelled', 'Cancelled'),('confirmed', 'Confirmed'),],'Status', readonly=True, track_visibility='onchange'), #FIELD FOR RECURRENCY - 'exdate': fields.text('Exception Date/Times', help="This property defines the list of date/time exceptions for a recurring calendar component."), + #'exdate': fields.text('Exception Date/Times', help="This property defines the list of date/time exceptions for a recurring calendar component."), 'rrule': fields.function(_get_rulestring, type='char', size=124, fnct_inv=_rrule_write, store=True, string='Recurrent Rule'), 'rrule_type': fields.selection([('daily', 'Day(s)'),('weekly', 'Week(s)'),('monthly', 'Month(s)'),('yearly', 'Year(s)')], 'Recurrency', states={'done': [('readonly', True)]}, help="Let the event automatically repeat at that interval"), 'recurrency': fields.boolean('Recurrent', help="Recurrent Meeting"), 'recurrent_id': fields.integer('Recurrent ID'), - #'recurrent_id_date': fields.datetime('Recurrent ID date'), + 'recurrent_id_date': fields.datetime('Recurrent ID date'), #'recurrence_end_date': fields.function(_get_recurrence_end_date, type='datetime', store=True, string='Recurrence end date',priority=30), 'vtimezone': fields.selection(_tz_get, size=64, string='Timezone'), 'end_type' : fields.selection([('count', 'Number of repetitions'), ('end_date','End date')], 'Recurrence Termination'), @@ -1027,7 +966,8 @@ class crm_meeting(osv.Model): 'active': fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the event alarm information without removing it."), 'categ_ids': fields.many2many('crm.meeting.type', 'meeting_category_rel', 'event_id', 'type_id', 'Tags'), - 'attendee_ids': fields.many2many('calendar.attendee', 'crmmeeting_attendee_rel', 'crmmeeting_id', 'attendee_id', 'Attendees'), + 'attendee_ids': fields.one2many('calendar.attendee', 'event_id', 'Attendees', ondelete='cascade'), + #'attendee_ids': fields.many2many('calendar.attendee', 'crmmeeting_attendee_rel', 'crmmeeting_id', 'attendee_id', 'Attendees', ondelete='cascade'), 'partner_ids': fields.many2many('res.partner', string='Attendees', states={'done': [('readonly', True)]}), 'alarm_ids': fields.many2many('calendar.alarm', string='Reminders'), } @@ -1073,8 +1013,9 @@ class crm_meeting(osv.Model): duration = 1.00 value['duration'] = duration - start = datetime.strptime(start_date, "%Y-%m-%d %H:%M:%S") + if allday: # For all day event + start = datetime.strptime(start_date.split(' ')[0].split('T')[0], "%Y-%m-%d") duration = 24.0 value['duration'] = duration # change start_date's time to 00:00:00 in the user's timezone @@ -1083,8 +1024,9 @@ class crm_meeting(osv.Model): start = pytz.utc.localize(start).astimezone(tz) # convert start in user's timezone #start = start.replace(hour=0, minute=0, second=0) # remove time start = start.astimezone(pytz.utc) # convert start back to utc - value['date'] = start.strftime("%Y-%m-%d %H:%M:%S") - + value['date'] = start.strftime("%Y-%m-%d") + ' 00:00:00' + else: + start = datetime.strptime(start_date, "%Y-%m-%d %H:%M:%S") if end_date and not duration: end = datetime.strptime(end_date, "%Y-%m-%d %H:%M:%S") @@ -1105,17 +1047,17 @@ class crm_meeting(osv.Model): return {'value': value} - def unlink_events(self, cr, uid, ids, context=None): - """ - This function deletes event which are linked with the event with recurrent_id - (Removes the events which refers to the same UID value) - """ - if context is None: - context = {} - for event_id in ids: - r_ids = self.search(cr,uid,[('recurrent_id','=',event_id)],context=context) - self.unlink(cr, uid, r_ids, context=context) - return True +# def unlink_events(self, cr, uid, ids, context=None): +# """ +# This function deletes event which are linked with the event with recurrent_id +# (Removes the events which refers to the same UID value) +# """ +# if context is None: +# context = {} +# for event_id in ids: +# r_ids = self.search(cr,uid,[('recurrent_id','=',event_id)],context=context) +# self.unlink(cr, uid, r_ids, context=context) +# return True def new_invitation_token(self, cr, uid, record, partner_id): db_uuid = self.pool.get('ir.config_parameter').get_param(cr, uid, 'database.uuid') @@ -1141,7 +1083,7 @@ class crm_meeting(osv.Model): att_id = self.pool.get('calendar.attendee').create(cr, uid, { 'partner_id': partner.id, 'user_id': partner.user_ids and partner.user_ids[0].id or False, - 'ref': event.id, + 'event_id': event.id, 'access_token': access_token, 'email': partner.email, }, context=context) @@ -1157,9 +1099,6 @@ class crm_meeting(osv.Model): print "Send mail... from ",mail_from, " to ",att_id if self.pool.get('calendar.attendee')._send_mail_to_attendees(cr, uid, att_id, email_from = mail_from, context=context): self.message_post(cr, uid, event.id, body=_("An invitation email has been sent to attendee %s") % (partner.name,),subtype="base_calendar.subtype_invitation", context=context) - else: - print "DON'T SEND MAIL TO MYSELF !" - if new_attendees: self.write(cr, uid, [event.id], {'attendee_ids': [(4, att) for att in new_attendees]},context=context) @@ -1175,7 +1114,7 @@ class crm_meeting(osv.Model): attendee_ids_to_remove = [] if partner_ids_to_remove: - attendee_ids_to_remove =self.pool.get("calendar.attendee").search(cr,uid,[('partner_id.id','in',partner_ids_to_remove),('ref.id','=',event.id)],context=context) + attendee_ids_to_remove =self.pool.get("calendar.attendee").search(cr,uid,[('partner_id.id','in',partner_ids_to_remove),('event_id.id','=',event.id)],context=context) if attendee_ids_to_remove: self.pool.get("calendar.attendee").unlink(cr, uid, attendee_ids_to_remove, context) ## NEED TO UNSUBSCRIBE ? @@ -1195,14 +1134,21 @@ class crm_meeting(osv.Model): if not context: context = {} + if isinstance(select, (str, int, long)): + ids_to_browse = [select] #keep select for return + else: + ids_to_browse = select + result = [] - for data in self.read(cr, uid, select, ['rrule', 'recurrency', 'exdate', 'date', 'vtimezone'], context=context): - if not data['recurrency'] or not data['rrule']: - result.append(data['id']) + for ev in self.browse(cr, uid, select, context=context): + if not ev.recurrency or not ev.rrule: + result.append(ev.id) continue # event_date = datetime.strptime(data['date'], "%Y-%m-%d %H:%M:%S") # event_date = pytz.UTC.localize(event_date) - rdates = get_recurrent_dates(data['rrule'], data['date'], data['exdate'], data['vtimezone'], context=context) + + rdates = self.get_recurrent_date_by_event(cr, uid, ev, context=context) + for r_date in rdates: # fix domain evaluation # step 1: check date and replace expression by True or False, replace other expressions by True @@ -1245,13 +1191,15 @@ class crm_meeting(osv.Model): if [True for item in new_pile if not item]: continue # idval = real_id2base_calendar_id(data['id'], r_date.strftime("%Y-%m-%d %H:%M:%S")) - idval = '%d-%s' % (data['id'], r_date.strftime("%Y%m%d%H%M%S")) + idval = '%d-%s' % (ev.id, r_date.strftime("%Y%m%d%H%M%S")) result.append(idval) + if isinstance(select, (str, int, long)): return ids and ids[0] or False else: ids = list(set(result)) + return ids def compute_rule_string(self, data): @@ -1360,6 +1308,7 @@ class crm_meeting(osv.Model): data['end_type'] = 'count' else: data['end_type'] = 'end_date' + return data #def _get_data(self, cr, uid, id, context=None): @@ -1497,8 +1446,7 @@ class crm_meeting(osv.Model): new_arg = (arg[0], arg[1], new_id) new_args.append(new_arg) #offset, limit and count must be treated separately as we may need to deal with virtual ids - print 'AFTER SEARCH',new_args - + res = super(crm_meeting,self).search(cr, uid, new_args, offset=0, limit=0, order=order, context=context, count=False) if context.get('virtual_id', True): @@ -1521,6 +1469,8 @@ class crm_meeting(osv.Model): return res def write(self, cr, uid, ids, values, context=None): + print "Write : ",ids + print values def _only_changes_to_apply_on_real_ids(field_names): ''' return True if changes are only to be made on the real ids''' for field in field_names: @@ -1535,9 +1485,10 @@ class crm_meeting(osv.Model): new_id = False # Special write of complex IDS - for event_id in ids[:]: + for event_id in ids: if len(str(event_id).split('-')) == 1: continue + ids.remove(event_id) real_event_id = base_calendar_id2real_id(event_id) @@ -1550,16 +1501,18 @@ class crm_meeting(osv.Model): #if edit one instance of a reccurrent id data = self.read(cr, uid, event_id, ['date', 'date_deadline', \ - 'rrule', 'duration', 'exdate']) + 'rrule', 'duration'])#, 'exdate']) if data.get('rrule'): data.update( values, recurrent_id=real_event_id, - #recurrent_id_date=data.get('date'), + recurrent_id_date=data.get('date'), rrule_type=False, rrule='', recurrency=False, + end_date = datetime.strptime(values.get('date',False) or data.get('date'),"%Y-%m-%d %H:%M:%S") + timedelta(hours=values.get('duration',False) or data.get('duration')) ) + #do not copy the id if data.get('id'): del(data['id']) @@ -1567,9 +1520,10 @@ class crm_meeting(osv.Model): date_new = event_id.split('-')[1] date_new = time.strftime("%Y%m%dT%H%M%SZ", time.strptime(date_new, "%Y%m%d%H%M%S")) - exdate = (data['exdate'] and (data['exdate'] + ',') or '') + date_new - res = super(crm_meeting, self).write(cr, uid, [real_event_id], {'exdate': exdate}) - + + #exdate = (data['exdate'] and (data['exdate'] + ',') or '') + date_new + #res = super(crm_meeting, self).write(cr, uid, [real_event_id], {'exdate': exdate}) + context.update({'active_id': new_id, 'active_ids': [new_id]}) continue @@ -1586,19 +1540,14 @@ class crm_meeting(osv.Model): if values.get('partner_ids', False): attendees_create = self.create_attendees(cr, uid, ids, context) - if values.get('date', False) and not context.get('install_mode',False): #Not send mail when install data - print 'Id notified (ids|new_id) : ',ids,"|",new_id + if values.get('date', False) and not context.get('install_mode',False) and values.get('active',True): #Not send mail when install data the_id = new_id or (ids and int(ids[0])); - print "Date has been changed !!!! --> SEND MAIL" if attendees_create: attendees_create = attendees_create[the_id] mail_to_ids = list(set(attendees_create['old_attendee_ids']) - set(attendees_create['removed_attendee_ids'])) - print 'xxxToSend to ', mail_to_ids else: - mail_to_ids = [att.id for att in self.browse(cr,uid,the_id,context=context).attendee_ids] - print 'yyyToSend to ', mail_to_ids if mail_to_ids: current_user = self.pool.get('res.users').browse(cr, uid, uid, context=context) @@ -1619,7 +1568,9 @@ class crm_meeting(osv.Model): if vals.get('recurrency', True) and vals.get('end_type', 'count') in ('count', unicode('count')) and \ (vals.get('rrule_type') or vals.get('count') or vals.get('date') or vals.get('date_deadline')): vals['end_date'] = self._get_recurrency_end_date(vals, context=context) - + + + print "CREATE WITH VALUES",vals res = super(crm_meeting, self).create(cr, uid, vals, context=context) #res = self.write(cr, uid, id_res,vals, context) @@ -1650,7 +1601,7 @@ class crm_meeting(osv.Model): context = {} fields2 = fields and fields[:] or None - EXTRAFIELDS = ('class','user_id','duration', 'date','rrule', 'vtimezone', 'exdate') + EXTRAFIELDS = ('class','user_id','duration', 'date','rrule', 'vtimezone')#, 'exdate') for f in EXTRAFIELDS: if fields and (f not in fields): fields2.append(f) @@ -1674,8 +1625,7 @@ class crm_meeting(osv.Model): res = real_data[real_id].copy() ls = base_calendar_id2real_id(base_calendar_id, with_date=res and res.get('duration', 0) or 0) if not isinstance(ls, (str, int, long)) and len(ls) >= 2: - recurrent_dates = [d.strftime("%Y-%m-%d %H:%M:%S") for d in get_recurrent_dates(res['rrule'], res['date'], res['exdate'],res['vtimezone'], context=context)] - + #recurrent_dates = [d.strftime("%Y-%m-%d %H:%M:%S") for d in get_recurrent_dates(res['rrule'], res['date'], res['exdate'],res['vtimezone'], context=context)] #if not (ls[1] in recurrent_dates or ls[1] in res['exdate']): #when update a recurrent event res['date'] = ls[1] @@ -1706,53 +1656,78 @@ class crm_meeting(osv.Model): return result and result[0] or False return result - def unlink(self, cr, uid, ids, context=None): + + def count_left_instance(self,cr,uid,event_id,context=None): + + event = self.browse(cr,uid,event_id,context=context) + if event.recurrent_id and event.recurrent_id > 0: + parent_event_id = event.recurrent_id + else: + parent_event_id = event.id + domain = ['|', ('id', '=', parent_event_id), ('recurrent_id', '=', parent_event_id)] + + count = self.search(cr, uid, domain, context=context) + print "Count = ",count + return len(count) + + def get_linked_ids(self,cr,uid,event_id,show_unactive=True,context=None): + event = self.browse(cr,uid,event_id,context=context) + if event.recurrent_id and event.recurrent_id > 0: + parent_event_id = event.recurrent_id + else: + parent_event_id = event.id + + domain = ['|', ('id', '=', parent_event_id), ('recurrent_id', '=', parent_event_id)] + + if show_unactive: + domain += ['|',('active', '=', True), ('active', '=', False)] + + return super(crm_meeting, self).search(cr, uid, domain, context=context) + + def delete(self,cr,uid,ids,context=None): + if not isinstance(ids, list): + ids = [ids] + all_ids = [] + for id_to_unlink in ids: + all_ids += self.get_linked_ids(cr, uid, id_to_unlink, context=context) + print "in deleTe functIon === ids : %s, all_ids : %s" % (ids,all_ids) + all_ids = list(set(all_ids)) + res = super(crm_meeting, self).unlink(cr, uid, all_ids, context=context) + return all_ids + + + def unlink(self, cr, uid, ids,unlink_level=0, context=None): + print "IN UNLINK !!!" if not isinstance(ids, list): ids = [ids] res = False - attendee_obj=self.pool.get('calendar.attendee') - for event_id in ids[:]: - if len(str(event_id).split('-')) == 1: - continue - real_event_id = base_calendar_id2real_id(event_id) - data = self.read(cr, uid, real_event_id, ['exdate'], context=context) - date_new = event_id.split('-')[1] - date_new = time.strftime("%Y%m%dT%H%M%S", time.strptime(date_new, "%Y%m%d%H%M%S")) - exdate = (data['exdate'] and (data['exdate'] + ',') or '') + date_new - self.write(cr, uid, [real_event_id], {'exdate': exdate}, context=context) - ids.remove(event_id) - for event in self.browse(cr, uid, ids, context=context): - if event.attendee_ids: - attendee_obj.unlink(cr, uid, [x.id for x in event.attendee_ids], context=context) + ids_to_exclure = [] + ids_to_unlink = [] + + #One time moved to google_Calendar, we can specify, an if not in google, and not rec or get_inst = 0, we delete it + for event_id in ids: + #if unlink_level == 1 and len(str(event_id).split('-')) == 1: ## if ID REAL + if unlink_level == 1 and len(str(event_id).split('-')) == 1: ## if ID REAL + if self.browse(cr,uid,event_id).recurrent_id: + print "Could not be deleted ! because instance of recursive" + ids_to_exclure.append(event_id) + else: + ids_to_unlink.append(event_id) + else: + print "Could not be deleted ! because instance virtual" + ids_to_exclure.append(event_id) + - res = super(crm_meeting, self).unlink(cr, uid, ids, context=context) - self.unlink_events(cr, uid, ids, context=context) + if ids_to_unlink: + res = super(crm_meeting, self).unlink(cr, uid, ids_to_unlink, context=context) + + if ids_to_exclure: + for id_to_exclure in ids_to_exclure: + res = self.write(cr, uid, id_to_exclure, {'active': False}, context=context) + return res - - - -# class mail_mail(osv.osv): -# _inherit = "mail.mail" -# -# _columns = { -# 'date_trigger': fields.datetime('date_trigger'), -# } -# -# def process_email_queue(self, cr, uid, ids=None, context=None): -# if context is None: -# context = {} -# import ipdb; ipdb.set_trace(); -# context['filters'] = (['|',('date_trigger', '=', False),('date_trigger', '>=', datetime.now().strftime("%Y-%m-%d %H:%M:%S"))]) #datetime.now().strftime("%Y-%m-%d %H:%M:%S") -# # ids_to_send = ids; -# # for mail in self.browse(cr,uid,ids,context=context): -# # if mail.date_trigger and datetime.strptime(mail.date_trigger, '%Y-%m-%d %H:%M:%S') > datetime.now(): -# # ids_to_send.remove(mail.id) -# # -# # return super(mail_mail, self).send(cr, uid, ids_to_send, auto_commit=auto_commit, raise_exception=raise_exception, context=context) -# return super(mail_mail, self).process_email_queue(cr, uid, ids=ids, context=context) - - + class mail_message(osv.osv): _inherit = "mail.message" diff --git a/addons/base_calendar/static/src/css/base_calender.css b/addons/base_calendar/static/src/css/base_calender.css index 2e3e963fb2c..f8858d8b88a 100644 --- a/addons/base_calendar/static/src/css/base_calender.css +++ b/addons/base_calendar/static/src/css/base_calender.css @@ -67,3 +67,7 @@ span.no-wrap { white-space:nowrap } + +.cal_tab { + margin: 20 0 20 0; +} diff --git a/addons/google_base_account/controllers/main.py b/addons/google_base_account/controllers/main.py index ce7909da6cf..cb729e10c79 100644 --- a/addons/google_base_account/controllers/main.py +++ b/addons/google_base_account/controllers/main.py @@ -16,54 +16,62 @@ class google_auth(http.Controller): state = simplejson.loads(kw['state']) - #action = state.get('a') - #menu = state.get('m') dbname = state.get('d') - #service = state.get('s') url_return = state.get('from') registry = openerp.modules.registry.RegistryManager.get(dbname) with registry.cursor() as cr: #TODO CHECK IF REQUEST OK registry.get('google.calendar').set_all_tokens(cr,request.session.uid,kw['code']) - registry.get('google.calendar').set_primary_id(cr,request.session.uid) + #registry.get('google.calendar').set_primary_id(cr,request.session.uid) return werkzeug.utils.redirect(url_return) - #@openerp.addons.web.http.route('/web_calendar_sync/sync_calendar/sync_data', type='json', auth='user') @http.route('/web_calendar_sync/sync_calendar/sync_data', type='json', auth='user') def sync_data(self, arch, fields, model,**kw): - calendar_info = { - 'field_data':{}, - 'date_start':arch['attrs'].get('date_start'), - 'date_stop':arch['attrs'].get('date_stop'), - 'calendar_string':arch['attrs'].get('string'), - 'model':model - } - for field, data in fields.items(): - calendar_info['field_data'][field] = { - 'type': data.get('type'), - 'string': data.get('string') - } + if model == 'crm.meeting': - model_obj = request.registry.get('crm.meeting.synchronize') + gs_obj = request.registry.get('google.service') gc_obj = request.registry.get('google.calendar') - - #We check that user has already accepted openerp to acces his calendar ! - if not gc_obj.get_refresh_token(request.cr, request.uid,context=kw.get('LocalContext')): + + #We check that admin has already configure api for google synchronization ! + client_id = gs_obj.get_client_id(request.cr, request.uid,'calendar',context=kw.get('LocalContext')) + + if not client_id or client_id == '': + return { + "status" : "NeedConfigFromAdmin", + "url" : '' + } + + #We check that user has already accepted openerp to access his calendar ! + if gc_obj.need_authorize(request.cr, request.uid,context=kw.get('LocalContext')): url = gc_obj.authorize_google_uri(request.cr, request.uid, from_url=kw.get('fromurl'),context=kw.get('LocalContext')) return { "status" : "NeedAuth", "url" : url } - #We lunch th synchronization - print "ORI COONTEXT = ",kw.get('LocalContext') - model_obj.synchronize_events(request.cr, request.uid, [], kw.get('LocalContext')) - else: - model_obj = request.registry.get('google.calendar') - model_obj.synchronize_calendar(request.cr, request.uid, calendar_info, kw.get('LocalContext')) + #We launch the synchronization + result = gc_obj.synchronize_events(request.cr, request.uid, [], kw.get('LocalContext')) + return result + else: + calendar_info = { + 'field_data':{}, + 'date_start':arch['attrs'].get('date_start'), + 'date_stop':arch['attrs'].get('date_stop'), + 'calendar_string':arch['attrs'].get('string'), + 'model':model + } + for field, data in fields.items(): + calendar_info['field_data'][field] = { + 'type': data.get('type'), + 'string': data.get('string') + } + + print "@@@@@@@@@@@@@@@@@ Is still used !!!!" + import ipdb; ipdb.set_trace() + gc_obj.synchronize_calendar(request.cr, request.uid, calendar_info, kw.get('LocalContext')) return { "status" : "SUCCESS" } @@ -90,6 +98,31 @@ class google_auth(http.Controller): + + @http.route('/gmail/delete_all', type='http', auth='user') + def delete_all(self, **kw): + gs_obj = request.registry.get('google.service') + gc_obj = request.registry.get('google.calendar') + + #We check that admin has already configure api for google synchronization ! + client_id = gs_obj.get_client_id(request.cr, request.uid,'calendar',context=kw.get('LocalContext')) + + if not client_id or client_id == '': + return { + "status" : "NeedConfigFromAdmin", + "url" : '' + } + + #We check that user has already accepted openerp to access his calendar ! + if gc_obj.need_authorize(request.cr, request.uid,context=kw.get('LocalContext')): + url = gc_obj.authorize_google_uri(request.cr, request.uid, from_url=kw.get('fromurl'),context=kw.get('LocalContext')) + return { + "status" : "NeedAuth", + "url" : url + } + + #We launch the synchronization + gc_obj.delete_all(request.cr, request.uid, kw.get('LocalContext')) diff --git a/addons/google_base_account/google_base_account.py b/addons/google_base_account/google_base_account.py index e45a599be51..a895c271314 100644 --- a/addons/google_base_account/google_base_account.py +++ b/addons/google_base_account/google_base_account.py @@ -65,14 +65,10 @@ class google_service(osv.osv_memory): #If no scope is passed, we use service by default to get a default scope - def _get_authorize_uri(self, cr, uid, from_url, service, scope = False, context=None): #authorize_API - if not service: - print 'please specify a service (Calendar for example)!' + def _get_authorize_uri(self, cr, uid, from_url, service, scope = False, context=None): state_obj = {} state_obj['d'] = cr.dbname - state_obj['a'] = request and request.params.get('action') or False - state_obj['m'] = request and request.params.get('menu_id') or False state_obj['s'] = service state_obj['from'] = from_url @@ -155,23 +151,32 @@ class google_service(osv.osv_memory): if type=='GET': print "### PARAMS : %s ###" % urllib.urlencode(params) else: - print "### PARAMS : %s ###" % (params) - + print "### PARAMS : %s ###" % (params) print "#########################################" try: - if type.upper() == 'GET': + if type.upper() == 'GET' or type.upper() == 'DELETE': data = urllib.urlencode(params) - req = urllib2.Request(self.get_uri_api() + uri + "?" + data)#,headers) - elif type.upper() == 'POST': - req = urllib2.Request(self.get_uri_api() + uri, params, headers) + req = urllib2.Request(self.get_uri_api() + uri + "?" + data) + elif type.upper() == 'POST' or type.upper() == 'PATCH' or type.upper() == 'PUT': + req = urllib2.Request(self.get_uri_api() + uri, params, headers) else: - raise ('Method not supported [GET or POST] not in [%s]!' % (type)) - - content = urllib2.urlopen(req).read() - res = simplejson.loads(content) + raise ('Method not supported [%s] not in [GET, POST, PUT or PATCH]!' % (type)) + req.get_method = lambda: type.upper() + req.add_header('Pragma', 'no-cache') + request = urllib2.urlopen(req) + + if request.getcode() == 204: + res = True + else: + content=request.read() + res = simplejson.loads(content) + print "RESPONSE" + print "==========" + print res + print "==========" except urllib2.HTTPError,e: - print e.read() + print "ERROR CATCHED : ",e.read() raise self.pool.get('res.config.settings').get_config_warning(cr, _("Something went wrong during your token generation. Maybe your Authorization Code is invalid or already expired"), context=context) return res @@ -180,10 +185,10 @@ class google_service(osv.osv_memory): return self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url',default='http://www.openerp.com?NoBaseUrl',context=context) def get_client_id(self, cr, uid, service, context=None): - return self.pool.get('ir.config_parameter').get_param(cr, uid, 'google_%s_client_id' % (service,),context=context) + return self.pool.get('ir.config_parameter').get_param(cr, uid, 'google_%s_client_id' % (service,),context=context).strip() def get_client_secret(self, cr, uid, service, context=None): - return self.pool.get('ir.config_parameter').get_param(cr, uid, 'google_%s_client_secret' % (service,),context=context) + return self.pool.get('ir.config_parameter').get_param(cr, uid, 'google_%s_client_secret' % (service,),context=context).strip() def get_uri_oauth(self,a=''): #a = optionnal action return "https://accounts.google.com/o/oauth2/%s" % (a,) diff --git a/addons/google_calendar/__init__.py b/addons/google_calendar/__init__.py index 0b6021f1d0d..721388873ae 100644 --- a/addons/google_calendar/__init__.py +++ b/addons/google_calendar/__init__.py @@ -1,2 +1 @@ import google_calendar -import wizard \ No newline at end of file diff --git a/addons/google_calendar/__init__.pyc b/addons/google_calendar/__init__.pyc index 82e16f37c14ee7daadd1e97f8226ca893b98fa26..f937a51b89dbb63efe648bcd740a3d3eca3904bd 100644 GIT binary patch delta 95 zcmX@ZxS27C`7>f10 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) + elif type == "copy": + result['write_type'] = "copy" + crm_meeting.write(cr, uid, event['id'], result, context=context) + elif type == "create": + crm_meeting.create(cr, uid, result, context=context) + + def synchronize_events(self, cr, uid, ids, context=None): + gc_obj = self.pool.get('google.calendar') + + self.create_new_events(cr, uid, context=context) + cr.commit() + + self.bind_recurring_events_to_google(cr, uid, context) + cr.commit() + + res = self.update_events(cr, uid, context) + + return { + "status" : res and "NeedRefresh" or "NoNewEventFromGoogle", + "url" : '' + } + + def create_new_events(self, cr, uid, context): + gc_pool = self.pool.get('google.calendar') + + 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_norecurrent = context.copy() + context_norecurrent['virtual_id'] = False + + 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): + 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}) + #Check that response OK and return according to that + + return True + + + 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, + } + + + def bind_recurring_events_to_google(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_norecurrent = context.copy() + context_norecurrent['virtual_id'] = False + + + new_events_ids = crm_meeting.search(cr, uid,[('partner_ids', 'in', myPartnerID),('google_internal_event_id', '=', False),('recurrent_id', '>', 0),'|',('active', '=', False),('active', '=', True)], context=context_norecurrent) + new_google_internal_event_id = False + + for event in crm_meeting.browse(cr, uid, new_events_ids, context): + source_record = crm_meeting.browse(cr, uid ,event.recurrent_id,context) + + if event.recurrent_id_date and source_record.allday and source_record.google_internal_event_id: + new_google_internal_event_id = source_record.google_internal_event_id +'_'+ event.recurrent_id_date.split(' ')[0].replace('-','') + elif event.recurrent_id_date and source_record.google_internal_event_id: + new_google_internal_event_id = source_record.google_internal_event_id +'_'+ event.recurrent_id_date.replace('-','').replace(' ','T').replace(':','') + 'Z' + + if new_google_internal_event_id: + crm_meeting.write(cr, uid, [event.id], {'google_internal_event_id': new_google_internal_event_id}) + #Create new event calendar with exlude recuureent_id on RecurringEventID + + #TODO WARNING, NEED TO CHECK THAT EVENT and ALl insatance NOT DELETE IN GMAIL BEFORE ! + self.update_recurrent_event_exclu(cr,uid,new_google_internal_event_id,source_record.google_internal_event_id,event,context=context) + + + def check_and_sync(self, cr, uid, oe_event, google_event, context): + if datetime.strptime(oe_event.oe_update_date,"%Y-%m-%d %H:%M:%S.%f") > datetime.strptime(google_event['updated'],"%Y-%m-%dT%H:%M:%S.%fz"): + self.update_to_google(cr, uid, oe_event, google_event, context) + elif datetime.strptime(oe_event.oe_update_date,"%Y-%m-%d %H:%M:%S.%f") < datetime.strptime(google_event['updated'],"%Y-%m-%dT%H:%M:%S.%fz"): + self.update_from_google(cr, uid, oe_event, google_event, 'write', context) + + def get_sequence(self,cr,uid,instance_id,context=None): + gs_pool = self.pool.get('google.service') + + params = { + 'fields': 'sequence', + 'access_token' : self.get_token(cr,uid,context) + } + + headers = {'Content-type': 'application/json'} + + url = "/calendar/v3/calendars/%s/events/%s" % ('primary',instance_id) + + 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): + 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 + + all_event_from_google = self.get_event_dict(cr,uid,context=context) + all_new_event_from_google = all_event_from_google.copy() + + events_ids = crm_meeting.search(cr, uid,[('partner_ids', 'in', myPartnerID),('google_internal_event_id', '!=', False),('oe_update_date','!=', False),'|',('active','=',False),('active','=',True)],order='google_internal_event_id',context=context_novirtual) #MORE ACTIVE = False + + 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 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 not event.recurrent_id or event.recurrent_id == 0: + print " __ !! Master Event (%s) has been deleted has been delete in google" % (event.google_internal_event_id) + ids_deleted = crm_meeting.delete(cr,uid,event.id,context=context) + print "IDS DELETED : ",ids_deleted + for id_deleted in [x for x in ids_deleted if x in events_ids]: + #if id_deleted in events_ids: + events_ids.remove(id_deleted) + else: # I 'm and 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 + +################################# +## MANAGE CONNEXION TO GMAIL ## +################################# + def get_token(self,cr,uid,context=None): current_user = self.pool.get('res.users').browse(cr,uid,uid,context=context) - if datetime.strptime(current_user.google_calendar_token_validity.split('.')[0], "%Y-%m-%d %H:%M:%S") < datetime.now() - timedelta(minutes=5): - print "NEED TO RENEW TOKEN",current_user.google_calendar_token_validity , "<", datetime.now() - timedelta(minutes=5) + + if datetime.strptime(current_user.google_calendar_token_validity.split('.')[0], "%Y-%m-%d %H:%M:%S") < (datetime.now() + timedelta(minutes=1)): + print "@@ REFRESH TOKEN NEEDED !!!!" self.do_refresh_token(cr,uid,context=context) + print "@@ REFRESH TOKEN DONE !!!!" current_user.refresh() else: - print "KEEP OLD TOKEN",current_user.google_calendar_token_validity , "<", datetime.now() - timedelta(minutes=5) + print "TOKEN OK : ",datetime.strptime(current_user.google_calendar_token_validity.split('.')[0], "%Y-%m-%d %H:%M:%S"), " > ", (datetime.now() - timedelta(minutes=1)) + return current_user.google_calendar_token def do_refresh_token(self,cr,uid,context=None): @@ -171,40 +567,44 @@ class google_calendar(osv.osv): vals['google_%s_token' % self.STR_SERVICE] = all_token.get('access_token') self.pool.get('res.users').write(cr,uid,uid,vals,context=context) - - def get_refresh_token(self,cr,uid,context=None): - current_user = self.pool.get('res.users').browse(cr,uid,uid,context=context) - return current_user.google_calendar_rtoken + def need_authorize(self,cr,uid,context=None): + current_user = self.pool.get('res.users').browse(cr,uid,uid,context=context) + return current_user.google_calendar_rtoken == False def get_calendar_scope(self,RO=False): readonly = RO and '.readonly' or '' return 'https://www.googleapis.com/auth/calendar%s' % (readonly) + def authorize_google_uri(self,cr,uid,from_url='http://www.openerp.com',context=None): + url = self.pool.get('google.service')._get_authorize_uri(cr,uid,from_url,self.STR_SERVICE,scope=self.get_calendar_scope(),context=context) + return url + + def set_all_tokens(self,cr,uid,authorization_code,context=None): + gs_pool = self.pool.get('google.service') + all_token = gs_pool._get_google_token_json(cr, uid, authorization_code,self.STR_SERVICE,context=context) + + vals = {} + vals['google_%s_rtoken' % self.STR_SERVICE] = all_token.get('refresh_token') + vals['google_%s_token_validity' % self.STR_SERVICE] = datetime.now() + timedelta(seconds=all_token.get('expires_in')) #NEED A CALCUL + vals['google_%s_token' % self.STR_SERVICE] = all_token.get('access_token') + self.pool.get('res.users').write(cr,uid,uid,vals,context=context) + class res_users(osv.osv): _inherit = 'res.users' _columns = { - 'google_calendar_id': fields.char('Primary Calendar ID'), 'google_calendar_rtoken': fields.char('Refresh Token'), 'google_calendar_token': fields.char('User token'), 'google_calendar_token_validity': fields.datetime('Token Validity'), } - def get_cal_token_info(self, cr, uid, partner_id=False, context=None): - if partner_id: - user = self.pool.get('res.partner').browse(cr,uid,partner_id,context=context).user_id - else: - user = self.pool.get('res.users').browse(cr,uid,uid,context=context) - - return dict(authcode=user.google_cal_authcode, token=user.google_cal_token, validity=user.google_cal_token_validity,) - - def update_cal_token(self,cr,uid,jsontoken,context=None): - print jsontoken - import ipdb; ipdb.set_trace(); - self.write(cr,uid,uid,{'xxx' : datetime.now() } ,context=context) - return "OK" - +# def get_cal_token_info(self, cr, uid, partner_id=False, context=None): +# if partner_id: +# user = self.pool.get('res.partner').browse(cr,uid,partner_id,context=context).user_id +# else: +# user = self.pool.get('res.users').browse(cr,uid,uid,context=context) +# return dict(authcode=user.google_cal_authcode, token=user.google_cal_token, validity=user.google_cal_token_validity,) class crm_meeting(osv.osv): @@ -214,6 +614,7 @@ class crm_meeting(osv.osv): sync_fields = set(['name', 'description', 'date', 'date_closed', 'date_deadline', 'attendee_ids', 'location', 'class']) if (set(vals.keys()) & sync_fields) and 'oe_update_date' not in vals.keys(): vals['oe_update_date'] = datetime.now() + return super(crm_meeting, self).write(cr, uid, ids, vals, context=context) def copy(self, cr, uid, id, default=None, context=None): @@ -233,18 +634,15 @@ class crm_meeting(osv.osv): 'google_internal_event_id': fields.char('Google Calendar Event Id', size=124), 'oe_update_date': fields.datetime('OpenERP Update Date'), } - + _sql_constraints = [('google_id_uniq','unique(google_internal_event_id)', 'Google ID must be unique!')] # If attendees are updated, we need to specify that next synchro need an action class calendar_attendee(osv.osv): _inherit = 'calendar.attendee' def write(self, cr, uid, ids, vals, context=None): - if isinstance(ids, list): - cr.execute("SELECT crmmeeting_id FROM crmmeeting_attendee_rel WHERE attendee_id = %s"%(ids[0])) - else: - cr.execute("SELECT crmmeeting_id FROM crmmeeting_attendee_rel WHERE attendee_id = %s"%(ids)) - event_id = cr.fetchone()[0] - if event_id: - self.pool.get('crm.meeting').write(cr, uid, event_id, {'oe_update_date':datetime.now()}) + 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()}) + 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 1a190173fc181bc8a6d94ffaecefd0c5c13da409..a323743f43b42695956349de190203e0a94a63d4 100644 GIT binary patch literal 22613 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 literal 10366 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 pqL>A@;G51fR|mR>Kdc#Amyn9P1> + - - \ No newline at end of file diff --git a/addons/google_calendar/google_calendar_view.xml b/addons/google_calendar/google_calendar_view.xml deleted file mode 100644 index e99826dae52..00000000000 --- a/addons/google_calendar/google_calendar_view.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - ir.attachment.google.spreadsheet.tree - ir.attachment - - - - - - - - - - ir.attachment.google.spreadsheet.form - ir.attachment - -
- - - - - - - - - - -
-
-
- - - Google Spreadsheets - ir.attachment - form - tree,form - {} - [('url', 'like', '/spreadsheet/')] - Google Spreadsheets - - - - - tree - - - - - - - form - - - - - -
-
\ No newline at end of file diff --git a/addons/google_calendar/static/src/js/calendar_sync.js b/addons/google_calendar/static/src/js/calendar_sync.js index 62639c6771f..76570caad4f 100644 --- a/addons/google_calendar/static/src/js/calendar_sync.js +++ b/addons/google_calendar/static/src/js/calendar_sync.js @@ -10,15 +10,17 @@ openerp.google_calendar = function(instance) { instance.web_calendar.FullCalendarView.include({ view_loading: function(r) { var self = this; - this.$el.on('click', 'div.oe_dhx_cal_sync_button', function() { + this.$el.on('click', 'div.oe_cal_sync_button', function() { + console.log("Launch synchro"); self.sync_calendar(r); }); return this._super(r); }, - sync_calendar: function(res) { + sync_calendar: function(res,button) { var self = this; var context = instance.web.pyeval.eval('context'); - console.log("Model is..." + res.model); + //$('div.oe_cal_sync_button').hide(); + $('div.oe_cal_sync_button').prop('disabled',true); self.rpc('/web_calendar_sync/sync_calendar/sync_data', { arch: res.arch, @@ -26,13 +28,21 @@ openerp.google_calendar = function(instance) { model:res.model, fromurl: window.location.href, LocalContext:context - }).always(function(o) { + }).done(function(o) { + console.log(o); + if (o.status == "NeedAuth") { alert(_t("You will be redirected on gmail to authorize your OpenErp to access your calendar !")); window.location = o.url; } - console.log(o); - //self.reload(); + else if (o.status == "NeedConfigFromAdmin") { + alert(_t("Admin need to configure Google Synchronization before to use it !")); + window.location = o.url; + } + else if (o.status == "NeedRefresh"){ + self.$calendar.fullCalendar('refetchEvents'); + } + $('div.oe_cal_sync_button').prop('disabled',false); }); } }); diff --git a/addons/google_calendar/static/src/xml/web_calendar.xml b/addons/google_calendar/static/src/xml/web_calendar.xml index 7baadaaf183..df09fac6da1 100644 --- a/addons/google_calendar/static/src/xml/web_calendar.xml +++ b/addons/google_calendar/static/src/xml/web_calendar.xml @@ -2,9 +2,9 @@ -
-
+
+