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 82e16f37c14..f937a51b89d 100644 Binary files a/addons/google_calendar/__init__.pyc and b/addons/google_calendar/__init__.pyc differ diff --git a/addons/google_calendar/__openerp__.py b/addons/google_calendar/__openerp__.py index c11cd989058..3295d86c50c 100644 --- a/addons/google_calendar/__openerp__.py +++ b/addons/google_calendar/__openerp__.py @@ -30,13 +30,11 @@ The module adds the possibility to synchronize Google Calendar with OpenERP """, 'author': 'OpenERP SA', 'website': 'http://www.openerp.com', - 'depends': ['base_calendar'], + 'depends': ['google_base_account','base_calendar'], 'js': ['static/src/js/*.js'], 'qweb': ['static/src/xml/*.xml'], 'data': [ - 'google_calendar_view.xml', 'google_calendar_data.xml', - 'wizard/crm_meeting_view.xml', ], 'demo': [], 'installable': True, diff --git a/addons/google_calendar/google_calendar.py b/addons/google_calendar/google_calendar.py index c3d343a70db..cc25b83f9d7 100644 --- a/addons/google_calendar/google_calendar.py +++ b/addons/google_calendar/google_calendar.py @@ -31,7 +31,8 @@ from openerp.addons.web.http import request import werkzeug.utils from datetime import datetime, timedelta, date - +from dateutil import parser +import pytz from openerp.osv import fields, osv from openerp.osv import osv @@ -55,42 +56,14 @@ class google_calendar(osv.osv): STR_SERVICE = 'calendar' - 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) - - def set_primary_id(self,cr,uid,context=None): - gs_pool = self.pool.get('google.service') - - params = { - 'fields': 'id', - 'access_token': self.get_token(cr, uid, context=context) - } - - cal = gs_pool._do_request(cr, uid, "/calendar/v3/calendars/primary/", params, type='GET', context=context) - - if cal.get('id',False): - vals = {} - vals['google_calendar_id']= cal.get('id') - self.pool.get('res.users').write(cr,uid,uid,vals,context=context) - return True - else: - return False +################################# +## DISCUSS WITH GMAIL ## +################################# def generate_data(self, cr, uid, event, context=None): if event.allday: - start_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.date, tools.DEFAULT_SERVER_DATETIME_FORMAT) + timedelta(hours=0), context=context).isoformat('T').split('T')[0] - end_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.date, tools.DEFAULT_SERVER_DATETIME_FORMAT) + timedelta(hours=24), context=context).isoformat('T').split('T')[0] + start_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.date, tools.DEFAULT_SERVER_DATETIME_FORMAT) , context=context).isoformat('T').split('T')[0] + end_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.date, tools.DEFAULT_SERVER_DATETIME_FORMAT) + timedelta(hours=event.duration), context=context).isoformat('T').split('T')[0] type = 'date' else: start_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.date, tools.DEFAULT_SERVER_DATETIME_FORMAT), context=context).isoformat('T') @@ -98,6 +71,8 @@ class google_calendar(osv.osv): type = 'dateTime' attendee_list = [] + print "att for event %s : %s" % (event.id,event.attendee_ids) + for attendee in event.attendee_ids: attendee_list.append({ 'email':attendee.email or 'NoEmail@mail.com', @@ -109,37 +84,29 @@ class google_calendar(osv.osv): "description": event.description or '', "start":{ type:start_date, - #'timeZone':context.get('tz') or 'UTC' + 'timeZone':'UTC' }, "end":{ type:end_date, - #'timeZone':context.get('tz') or 'UTC' + 'timeZone':'UTC' }, "attendees":attendee_list, "location":event.location or '', "visibility":event['class'] or 'public', } if event.recurrency and event.rrule: - data["recurrence"]= [] - if event.exdate: - data["recurrence"].append("EXDATE:"+event.exdate) - - data["recurrence"]+=["RRULE:"+event.rrule] - - - #if not recurrency and event.recurrent_id and event.recurrent_id != 0: ###" IMMUTABLE - # data["recurringEventId"] = event.recurrent_id - - print data + data["recurrence"]=["RRULE:"+event.rrule] + + if not event.active: + data["state"] = "cancelled" + return data - def create_event(self, cr, uid,event, context=None): + def create_an_event(self, cr, uid,event, context=None): gs_pool = self.pool.get('google.service') - print "CONTEXT : ",context data = self.generate_data(cr, uid,event, context=context) - url = "/calendar/v3/calendars/%s/events?fields=%s&access_token=%s" % ('primary',urllib.quote('id,updated'),self.get_token(cr,uid,context)) headers = {'Content-type': 'application/json', 'Accept': 'text/plain'} data_json = simplejson.dumps(data) @@ -149,14 +116,443 @@ class google_calendar(osv.osv): return response + def delete_an_event(self, cr, uid,event_id, context=None): + gs_pool = self.pool.get('google.service') + + params = { + 'access_token' : self.get_token(cr,uid,context) + } + headers = {'Content-type': 'application/json', 'Accept': 'text/plain'} + + url = "/calendar/v3/calendars/%s/events/%s" % ('primary',event_id) + + 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) + + gs_pool = self.pool.get('google.service') + + params = { + 'fields': 'items,nextPageToken', + 'access_token' : token + } + headers = {'Content-type': 'application/json', 'Accept': 'text/plain'} + + url = "/calendar/v3/calendars/%s/events" % 'primary' #?fields=%s&access_token=%s" % ('primary',urllib.quote('items,nextPageToken'), token) + if nextPageToken: + params['pageToken'] = nextPageToken + + + content = gs_pool._do_request(cr, uid, url, params, headers, type='GET', context=context) + + google_events_dict = {} + + print content['items'] + + + for google_event in content['items']: + google_events_dict[google_event['id']] = google_event + #if google_event.get('updated',False): +# if withInstance: +# for instance in self.get_instance_event(cr,uid,event_id,context): +# google_events_dict[instance['id']] = instance +# else: + + if content.get('nextPageToken', False): + google_events_dict.update(self.get_event_dict(cr,uid,token,content['nextPageToken'],context=context)) + return google_events_dict + + def update_to_google(self, cr, uid, oe_event, google_event, context): + crm_meeting = self.pool['crm.meeting'] + gs_pool = self.pool.get('google.service') + + + url = "/calendar/v3/calendars/%s/events/%s?fields=%s&access_token=%s" % ('primary', google_event['id'],'id,updated', self.get_token(cr,uid,context)) + headers = {'Content-type': 'application/json', 'Accept': 'text/plain'} + data = self.generate_data(cr,uid ,oe_event, context) + data['sequence'] = google_event.get('sequence', 0) + data_json = simplejson.dumps(data) + + + content = gs_pool._do_request(cr, uid, url, data_json, headers, type='PATCH', context=context) + + #except urllib2.HTTPError,e: + # error_message = json.loads(e.read()) + + update_date = datetime.strptime(content['updated'],"%Y-%m-%dT%H:%M:%S.%fz") + crm_meeting.write(cr, uid, [oe_event.id], {'oe_update_date':update_date}) + + def update_an_event(self, cr, uid,event, context=None): + gs_pool = self.pool.get('google.service') + + data = self.generate_data(cr, uid,event, context=context) + + url = "/calendar/v3/calendars/%s/events/%s" % ('primary', event.google_internal_event_id) + headers = {} + data['access_token'] = self.get_token(cr,uid,context) + + response = gs_pool._do_request(cr, uid, url, data, headers, type='GET', context=context) + + #TODO, il http fail, no event, do DELETE ! ? + + return response + + def update_recurrent_event_exclu(self, cr, uid,instance_id,event_ori_google_id,event_new, context=None): + gs_pool = self.pool.get('google.service') + + data = self.generate_data(cr, uid,event_new, context=context) + + data['recurringEventId'] = event_ori_google_id + data['originalStartTime'] = event_new.recurrent_id_date + + url = "/calendar/v3/calendars/%s/events/%s?access_token=%s" % ('primary', instance_id,self.get_token(cr,uid,context)) + headers = { 'Content-type': 'application/json'} + + data['sequence'] = self.get_sequence(cr, uid, instance_id, context) + + data_json = simplejson.dumps(data) + response = gs_pool._do_request(cr, uid, url, data_json, headers, type='PUT', context=context) + + #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): + crm_meeting = self.pool['crm.meeting'] + res_partner_obj = self.pool['res.partner'] + calendar_attendee_obj = self.pool['calendar.attendee'] + attendee_record= [] + 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']]}) + google_attendee['found'] = True + 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') + 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 + + 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") + result.update({ + 'attendee_ids': attendee_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), + 'class':single_event_dict.get('visibility','public'), + '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) + 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 1a190173fc1..a323743f43b 100644 Binary files a/addons/google_calendar/google_calendar.pyc and b/addons/google_calendar/google_calendar.pyc differ diff --git a/addons/google_calendar/google_calendar_data.xml b/addons/google_calendar/google_calendar_data.xml index dadfaa915e3..85e3ce5d5d5 100644 --- a/addons/google_calendar/google_calendar_data.xml +++ b/addons/google_calendar/google_calendar_data.xml @@ -1,14 +1,13 @@ - + - - \ 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 @@ -
-
+
+