diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py index 162524787cd..3fb557a86b6 100644 --- a/addons/base_calendar/base_calendar.py +++ b/addons/base_calendar/base_calendar.py @@ -25,7 +25,9 @@ from dateutil.rrule import * from osv import osv, fields from tools.translate import _ import base64 +import math import pooler +import pytz import re import tools import vobject @@ -200,6 +202,7 @@ class CalDAV(object): if not datas: return for data in datas: + tzval = None vevent = ical.add(name) for field in self.__attribute__.keys(): map_field = self.ical_get(field, 'field') @@ -237,6 +240,11 @@ class CalDAV(object): alarm_obj = self.pool.get('basic.calendar.alarm') vevent = alarm_obj.export_cal(cr, uid, model, \ data[map_field][0], vevent, context=ctx) + elif field == 'vtimezone' and data[map_field]: + tzval = data[map_field] + tz_obj = self.pool.get('basic.calendar.timezone') + ical = tz_obj.export_cal(cr, uid, None, \ + data[map_field], ical, context=context) elif data[map_field]: if map_type in ("char", "text"): vevent.add(field).value = tools.ustr(data[map_field]) @@ -244,7 +252,10 @@ class CalDAV(object): if field in ('exdate'): vevent.add(field).value = [parser.parse(data[map_field])] else: - vevent.add(field).value = parser.parse(data[map_field]) + dtfield = vevent.add(field) + dtfield.value = parser.parse(data[map_field]) + if tzval: + dtfield.params['TZID'] = [tzval] elif map_type == "timedelta": vevent.add(field).value = timedelta(hours=data[map_field]) elif map_type == "many2one": @@ -296,11 +307,14 @@ class CalDAV(object): ical_data = base64.decodestring(content) self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, context) parsedCal = vobject.readOne(ical_data) - att_data = [] res = [] + vals = {} for child in parsedCal.getChildren(): if child.name.lower() in ('vevent', 'vtodo'): vals = self.parse_ics(cr, uid, child, context=context) + elif child.name.lower() == 'vtimezone': + tz_obj = self.pool.get('basic.calendar.timezone') + tz_obj.import_cal(cr, uid, child, context=context) else: vals = {} continue @@ -588,15 +602,51 @@ class FreeBusy(CalDAV): } -class Timezone(CalDAV): +class Timezone(CalDAV, osv.osv_memory): + _name = 'basic.calendar.timezone' + _calname = 'vtimezone' + __attribute__ = { - 'tzid': None, # Use: R-1, Type: Text, Specifies the text value that uniquely identifies the "VTIMEZONE" calendar component. + 'tzid': {'field': 'tzid'}, # Use: R-1, Type: Text, Specifies the text value that uniquely identifies the "VTIMEZONE" calendar component. 'last-mod': None, # Use: O-1, Type: DATE-TIME, Specifies the date and time that the information associated with the calendar component was last revised in the calendar store. 'tzurl': None, # Use: O-1, Type: URI, Provides a means for a VTIMEZONE component to point to a network location that can be used to retrieve an up-to-date version of itself. 'standardc': {'tzprop': None}, # Use: R-1, 'daylightc': {'tzprop': None}, # Use: R-1, 'x-prop': None, # Use: O-n, Type: Text, } + + def get_name_offset(self, cr, uid, tzid, context={}): + mytz = pytz.timezone(tzid) + mydt = datetime.now(tz=mytz) + offset = mydt.utcoffset() + val = offset.days * 24 + float(offset.seconds) / 3600 + realoffset = '%02d%02d' % (math.floor(abs(val)), \ + round(abs(val) % 1 + 0.01, 2) * 60) + realoffset = (val < 0 and ('-' + realoffset) or ('+' + realoffset)) + return (mydt.tzname(), realoffset) + + def export_cal(self, cr, uid, model, tzid, ical, context={}): + ctx = context.copy() + ctx.update({'model': model}) + cal_tz = ical.add('vtimezone') + cal_tz.add('TZID').value = tzid + tz_std = cal_tz.add('STANDARD') + tzname, offset = self.get_name_offset(cr, uid, tzid) + tz_std.add("TZOFFSETFROM").value = offset + tz_std.add("TZOFFSETTO").value = offset + tz_std.add("DTSTART").value = datetime.now() # TODO + tz_std.add("TZNAME").value = tzname + return ical + + def import_cal(self, cr, uid, ical_data, context=None): + for child in ical_data.getChildren(): + if child.name.lower() == 'tzid': + tzname = child.value + self.ical_set(child.name.lower(), tzname, 'value') + vals = map_data(cr, uid, self) + return vals + +Timezone() class Alarm(CalDAV, osv.osv_memory): diff --git a/addons/caldav/caldav.py b/addons/caldav/caldav.py index 5598236dd48..9b24c145a1b 100644 --- a/addons/caldav/caldav.py +++ b/addons/caldav/caldav.py @@ -19,15 +19,16 @@ # ############################################################################## +from base_calendar import base_calendar from datetime import datetime, timedelta from datetime import datetime, timedelta from dateutil import parser from osv import fields, osv -from base_calendar import base_calendar from service import web_services from tools.translate import _ import base64 import pooler +import pytz import re import time @@ -423,6 +424,9 @@ class calendar_event(osv.osv): _name = "calendar.event" _description = "Calendar Event" __attribute__ = {} + + def _tz_get(self,cr,uid, context={}): + return [(x, x) for x in pytz.all_timezones] def onchange_rrule_type(self, cr, uid, ids, rtype, *args, **argv): if rtype == 'none' or not rtype: @@ -483,7 +487,8 @@ rule or repeating pattern for anexception to a recurrence set"), 'caldav_alarm_id': fields.many2one('calendar.alarm', 'Alarm'), 'recurrent_uid': fields.integer('Recurrent ID'), 'recurrent_id': fields.datetime('Recurrent ID date'), - 'user_id': fields.many2one('res.users', 'Responsible'), + 'vtimezone': fields.selection(_tz_get, 'Timezone', size=64), + 'user_id': fields.many2one('res.users', 'Responsible'), } _defaults = { diff --git a/addons/crm/crm_meeting_view.xml b/addons/crm/crm_meeting_view.xml index c5231c73752..194bade3477 100644 --- a/addons/crm/crm_meeting_view.xml +++ b/addons/crm/crm_meeting_view.xml @@ -91,6 +91,7 @@ + diff --git a/addons/project_calendar/project_calendar_view.xml b/addons/project_calendar/project_calendar_view.xml index d331f8614c7..94679161b94 100644 --- a/addons/project_calendar/project_calendar_view.xml +++ b/addons/project_calendar/project_calendar_view.xml @@ -66,7 +66,7 @@ form - +