[REF] Synchro method create-delete-update, to replace with always active=False and pre-processing

bzr revid: jke@openerp.com-20131209140819-v0njlfjvl2biep2m
This commit is contained in:
jke-openerp 2013-12-09 15:08:19 +01:00
parent 7c33148ceb
commit 9134c79175
16 changed files with 805 additions and 754 deletions

View File

@ -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"

View File

@ -67,3 +67,7 @@
span.no-wrap {
white-space:nowrap
}
.cal_tab {
margin: 20 0 20 0;
}

View File

@ -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'))

View File

@ -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,)

View File

@ -1,2 +1 @@
import google_calendar
import wizard

Binary file not shown.

View File

@ -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,

View File

@ -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)

View File

@ -1,14 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0"?>
<openerp>
<data>
<!--
<record id="google_calendar_template" model="google.drive.config">
<field name="name">Base Spreadsheet Template</field>
<field name="model_id" ref="base.model_res_partner"/>
<field name="google_drive_template_url">https://docs.google.com/spreadsheet/ccc?key=0ApGVjjwUC-ygdDZ0TG5EQnRlLVFQNlFGdFN5b1ZrY1E</field>
<field name="name_template">Reporting %(name)s</field>
<field name="active" eval="0" />
<data noupdate="1">
<record id="config_calendar_id" model="ir.config_parameter">
<field name="key">google_calendar_client_id</field>
<field name="value"> </field>
</record>
<record id="config_calendar_secret" model="ir.config_parameter">
<field name="key">google_calendar_client_secret</field>
<field name="value"> </field>
</record>
-->
</data>
</openerp>

View File

@ -1,65 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- add google drive config field in user form -->
<record model="ir.ui.view" id="view_ir_attachment_google_spreadsheet_tree">
<field name="name">ir.attachment.google.spreadsheet.tree</field>
<field name="model">ir.attachment</field>
<field name="arch" type="xml">
<tree string="Google Spreadsheets" version="7.0">
<field name="name" string="Name"/>
<field name="url" />
</tree>
</field>
</record>
<record model="ir.ui.view" id="view_ir_attachment_google_spreadsheet_form">
<field name="name">ir.attachment.google.spreadsheet.form</field>
<field name="model">ir.attachment</field>
<field name="arch" type="xml">
<form string="Google Spreadsheets" version="7.0">
<sheet>
<group>
<group>
<field name="name" string="Name"/>
<field name="url" widget="url"/>
</group>
<group colspan="2">
<label for="description" colspan="2"/>
<field name="description" nolabel="1" colspan="2"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_ir_attachment_google_spreadsheet_tree" model="ir.actions.act_window">
<field name="name">Google Spreadsheets</field>
<field name="res_model">ir.attachment</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="context">{}</field>
<field name="domain">[('url', 'like', '/spreadsheet/')]</field>
<field name="help">Google Spreadsheets</field>
</record>
<record id="action_ir_attachment_google_spreadsheet_tree_view" model="ir.actions.act_window.view">
<field eval="1" name="sequence"/>
<field name="view_mode">tree</field>
<field name="view_id" ref="view_ir_attachment_google_spreadsheet_tree"/>
<field name="act_window_id" ref="action_ir_attachment_google_spreadsheet_tree"/>
</record>
<record id="action_ir_attachment_google_spreadsheet_form_view" model="ir.actions.act_window.view">
<field eval="2" name="sequence"/>
<field name="view_mode">form</field>
<field name="view_id" ref="view_ir_attachment_google_spreadsheet_form"/>
<field name="act_window_id" ref="action_ir_attachment_google_spreadsheet_tree"/>
</record>
<menuitem id="menu_reporting_dashboard_google_spreadsheets" parent="base.menu_reporting_dashboard" action="action_ir_attachment_google_spreadsheet_tree"/>
</data>
</openerp>

View File

@ -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);
});
}
});

View File

@ -2,9 +2,9 @@
<t t-extend="CalendarView.sidebar">
<t t-jquery="div.oe_calendar_mini" t-operation="after">
<div id="sync" class="oe_dhx_cal_sync_button dhx_cal_tab " >
<br/>
<div id="sync" class="oe_cal_sync_button cal_tab " >
<center>
<br/>
<button class="oe_button">
<span>
<img src="/google_calendar/static/src/img/calendar_32.png"/> Sync with <b>Google</b>

View File

@ -1 +0,0 @@
import crm_meeting

View File

@ -1,269 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.osv import osv, fields
from openerp import SUPERUSER_ID
from openerp import tools
from openerp.tools.translate import _
from datetime import datetime
from dateutil import parser
import pytz
import urllib
import urllib2
import json
import werkzeug.utils
class crm_meeting_synchronize(osv.osv_memory):
_name = 'crm.meeting.synchronize'
def synchronize_events(self, cr, uid, ids, context=None):
gc_obj = self.pool.get('google.calendar')
self.create_new_events(cr, uid, context=context)
#self.bind_recurring_events_to_google(cr, uid, context)
#self.update_events(cr, uid, access_token, context)
return True
#
# def generate_data(self, cr, uid, event, context):
# if event.allday:
# 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), 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')
# end_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.date_deadline, tools.DEFAULT_SERVER_DATETIME_FORMAT), context=context).isoformat('T')
# type = 'dateTime'
# attendee_list = []
# for attendee in event.attendee_ids:
# attendee_list.append({
# 'email':attendee.email,
# 'displayName':attendee.partner_id.name,
# 'responseStatus':google_state_mapping.get(attendee.state, 'needsAction'),
# })
# data = {
# "summary": event.name or '',
# "description": event.description or '',
# "start":{
# type:start_date,
# 'timeZone':context.get('tz')
# },
# "end":{
# type:end_date,
# 'timeZone':context.get('tz')
# },
# "attendees":attendee_list,
# "colorId":4,
# "location":event.location or '',
# "visibility":event['class'] or 'public',
# }
# if event.rrule:
# data["recurrence"]=["RRULE:"+event.rrule]
# return data
#
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']
print "TO CHECK RESULT HERE >>>>>>>>>>>>>>>>>>>>"
context_norecurrent = context.copy()
context_norecurrent['virtual_id'] = False
new_events_ids = crm_meeting.search(cr, uid,[('partner_ids', 'in', user_obj.browse(cr,uid,uid,context=context).partner_id.id),('google_internal_event_id', '=', False)], context=context_norecurrent)
#new_events_ids = [str(i).split('-')[0] for i in new_events_ids]
#new_events_ids = base_calendar_id2real_id(new_events_ids,False); #[str(i).split('-')[0] for i in new_events_ids]
print 'Events ids [new_events_ids] : ', new_events_ids
for event in crm_meeting.browse(cr, uid, list(set(new_events_ids)), context):
response = gc_pool.create_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 bind_recurring_events_to_google(self, cr, uid, context):
# crm_meeting = self.pool['crm.meeting']
# new_events_ids = crm_meeting.search(cr, uid,[('user_id', '=', uid),('google_internal_event_id', '=', False),('recurrent_id', '>', 0)], context)
# new_events_ids = base_calendar_id2real_id(new_events_ids,False); #[str(i).split('-')[0] for i in new_events_ids]
#
# for event in crm_meeting.browse(cr, uid, list(set(new_events_ids)), context):
# source_record = crm_meeting.read(cr, uid ,event.recurrent_id,['allday', 'google_internal_event_id'],context)
# new_google_internal_event_id = False
# if event.recurrent_id_date and source_record.get('allday') and source_record.get('google_internal_event_id'):
# new_google_internal_event_id = source_record.get('google_internal_event_id') +'_'+ event.recurrent_id_date.split(' ')[0].replace('-','') + 'Z'
# elif event.recurrent_id_date and source_record.get('google_internal_event_id'):
# new_google_internal_event_id = source_record.get('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})
def get_event_dict(self,access_token, nextPageToken):
request_url = "https://www.googleapis.com/calendar/v3/calendars/%s/events?fields=%s&access_token=%s" % ('primary',urllib.quote('items,nextPageToken') ,access_token)
if nextPageToken:
request_url += "&pageToken=%s" %(nextPageToken)
try:
req = urllib2.Request(request_url)
content = urllib2.urlopen(req).read()
except urllib2.HTTPError,e:
error_message = e.read()
print error_message
content = json.loads(content)
google_events_dict = {}
for google_event in content['items']:
if google_event.get('updated',False):
google_events_dict[google_event['id']] = google_event
if content.get('nextPageToken', False):
google_events_dict.update(self.get_event_dict(access_token,content['nextPageToken']))
return google_events_dict
def update_events(self, cr, uid, access_token, context):
crm_meeting = self.pool['crm.meeting']
google_event_dict = self.get_event_dict(access_token, False)
updated_events_ids = crm_meeting.search(cr, uid,[('partner_ids', 'in', user_obj.browse(cr,uid,uid,context=context)),('google_internal_event_id', '!=', False),('oe_update_date','!=', False)], context)
for event in crm_meeting.browse(cr, uid, list(set(updated_events_ids)), context):
if event.google_internal_event_id in google_event_dict:
self.check_and_sync(cr, uid, access_token, event, google_event_dict[event.google_internal_event_id], context)
del google_event_dict[event.google_internal_event_id]
else:
request_url = "https://www.googleapis.com/calendar/v3/calendars/%s/events/%s?access_token=%s" % ('primary', event.google_internal_event_id, access_token)
content = {}
try:
req = urllib2.Request(request_url)
content = urllib2.urlopen(req).read()
except urllib2.HTTPError,e:
error_message = e.read()
print error_message
if e.code == 404:
print "Need DELETE"
if content:
content = json.loads(content)
self.check_and_sync(cr, uid, access_token, event, content, context)
for new_google_event in google_event_dict.values():
if 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].replace('T','')[:-1]
for event_id in reccurent_event:
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
#reccurent update from google
self.update_from_google(cr, uid, parent_event, new_google_event, "copy", context)
else:
#new event from google
self.update_from_google(cr, uid, False, new_google_event, "create", context)
# del google_events_dict[new_google_event['id']]
def check_and_sync(self, cr, uid, access_token, 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"):
#update to google
self.update_to_google(cr, uid, access_token, 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"):
#update from google
self.update_from_google(cr, uid, oe_event, google_event, 'write', context)
pass
def update_to_google(self, cr, uid, access_token, oe_event, google_event, context):
crm_meeting = self.pool['crm.meeting']
request_url = "https://www.googleapis.com/calendar/v3/calendars/%s/events/%s?fields=%s" % ('primary', google_event['id'], urllib.quote('id,updated'))
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 = json.dumps(data)
try:
req = urllib2.Request(request_url, data_json, headers)
req.get_method = lambda: 'PATCH'
content = urllib2.urlopen(req).read()
except urllib2.HTTPError,e:
error_message = json.loads(e.read())
content = json.loads(content)
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_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))
if single_event_dict['start'].get('dateTime',False) and single_event_dict['end'].get('dateTime',False):
UTC = pytz.timezone('UTC')
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)
result['duration'] = (delta.seconds / 60) / 60.0 + delta.days *24
date = str(date.astimezone(UTC))[:-6]
date_deadline = str(date_deadline.astimezone(UTC))[:-6]
allday = False
else:
date = single_event_dict['start']['date'] + ' 12:00:00'
date_deadline = single_event_dict['start']['date'] + ' 12:00:00'
allday = True
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',''),
'location':single_event_dict.get('location',''),
'class':single_event_dict.get('visibility','public'),
'oe_update_date':update_date,
'google_internal_event_id': single_event_dict.get('id',''),
})
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)

View File

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_crm_meeting_google_synchronize" model="ir.ui.view">
<field name="name">Synchronize Events to Google</field>
<field name="model">crm.meeting.synchronize</field>
<field name="arch" type="xml">
<form string="Synchronize Events to Google" version="7.0">
<group string="This wizard will synchronize Events to Google Calendar">
</group>
<footer>
<button name="synchronize_events" string="Synchronize" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="action_crm_meeting_google_synchronize" model="ir.actions.act_window">
<field name="name">Synchronize Events to Google</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">crm.meeting.synchronize</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_crm_meeting_google_synchronize"/>
<field name="context">{}</field>
<field name="target">new</field>
</record>
<menuitem name="Synchronize with Google"
id="mail_menu_calendar_synch" parent="mail.mail_my_stuff"
sequence="10" action="action_crm_meeting_google_synchronize"/>
</data>
</openerp>