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/base_calendar/base_calendar_data.xml b/addons/base_calendar/base_calendar_data.xml index 0e7250071c8..b15cd72874e 100644 --- a/addons/base_calendar/base_calendar_data.xml +++ b/addons/base_calendar/base_calendar_data.xml @@ -1,10 +1,7 @@ - + - - OpenERP - diff --git a/addons/caldav/caldav.py b/addons/caldav/caldav.py index 5741f645b1e..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,9 @@ 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'), - } + 'vtimezone': fields.selection(_tz_get, 'Timezone', size=64), + 'user_id': fields.many2one('res.users', 'Responsible'), + } _defaults = { 'class': lambda *a: 'public', diff --git a/addons/caldav/caldav_data.xml b/addons/caldav/caldav_data.xml index 295b05ba540..c8b20ac134b 100644 --- a/addons/caldav/caldav_data.xml +++ b/addons/caldav/caldav_data.xml @@ -129,381 +129,5 @@ - - - vevent - - - - - - vtodo - - - - - - valarm - - - - - - attendee - - - - - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - - - - - field - - - diff --git a/addons/crm/crm.py b/addons/crm/crm.py index ed4735a55e8..d9d4c6e6c9d 100644 --- a/addons/crm/crm.py +++ b/addons/crm/crm.py @@ -580,7 +580,7 @@ class crm_case(osv.osv): def __history(self, cr, uid, cases, keyword, history=False, email=False, details=None, context={}): - model_obj = self.pool.get('ir.model') + model_obj = self.pool.get('ir.model') for case in cases: model_ids = model_obj.search(cr, uid, [('model','=',case._name)]) data = { @@ -820,14 +820,7 @@ class crm_case_history(osv.osv): _name = "crm.case.history" _description = "Case history" _order = "id desc" - _inherits = {'crm.case.log':"log_id"} - - def create(self, cr, user, vals, context=None): - if vals.has_key('res_id') and vals['res_id']: - case_obj = self.pool.get(vals['model_id']) - cases = case_obj.browse(cr, user, [vals['res_id']]) - case_obj._action(cr, user, cases, '') - return super(crm_case_history, self).create(cr, user, vals, context) + _inherits = {'crm.case.log':"log_id"} def _note_get(self, cursor, user, ids, name, arg, context=None): res = {} diff --git a/addons/crm/crm_mailgate.py b/addons/crm/crm_mailgate.py index 2da93ee3347..e66e2784f2a 100644 --- a/addons/crm/crm_mailgate.py +++ b/addons/crm/crm_mailgate.py @@ -49,9 +49,9 @@ class crm_cases(osv.osv): res = mailgate_obj.partner_get(cr, uid, msg['From']) if res: data.update(res) - res = self.create(cr, uid, data) + res = self.create(cr, uid, data) cases = self.browse(cr, uid, [res]) - self.__history(cr, uid, cases, _('Receive'), history=True, email=msg['From']) + self._history(cr, uid, cases, _('Receive'), history=True, email=msg['From']) return res def msg_update(self, cr, uid, ids, msg, data={}, default_act='pending'): @@ -80,7 +80,7 @@ class crm_cases(osv.osv): res = self.write(cr, uid, ids, data) cases = self.browse(cr, uid, [res]) - self.__history(cr, uid, cases, _('Receive'), history=True, email=msg['From']) + self._history(cr, uid, cases, _('Receive'), history=True, email=msg['From']) getattr(self,act)(cr, uid, ids) return res diff --git a/addons/crm/crm_meeting_data.xml b/addons/crm/crm_meeting_data.xml index 789708c6a35..09566903d1c 100644 --- a/addons/crm/crm_meeting_data.xml +++ b/addons/crm/crm_meeting_data.xml @@ -25,33 +25,101 @@ Case Meeting crm.meeting - + + - + + + + meeting + + + vevent + [('user_id','=', uid)] + + + + valarm + + + + attendee + + + + + + + + + + + field + - + + + + + field + - + field - + + + + + + field + - + + + + + field + + + + + + + field + + + field - + - + + + + + + field + + + + + + + field + + + @@ -59,5 +127,220 @@ field + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + 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_data.xml b/addons/project_calendar/project_calendar_data.xml index e4c333ca6e2..63b5e99333a 100644 --- a/addons/project_calendar/project_calendar_data.xml +++ b/addons/project_calendar/project_calendar_data.xml @@ -1,13 +1,17 @@ - - - vtodo - - + + meeting_todo + + vtodo + + + [('user_id','=', uid)] + + @@ -15,34 +19,430 @@ {'needs-action': 'draft', 'completed': 'done', 'in-process': 'open', 'cancelled': 'cancelled'} field - - + + + + + + field + + + field - - + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + field - - + + + + + + field + + + field - - + + + + + + field + + + + + + + field + + + hours + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + vevent + + + [('user_id','=', uid)] + + + + valarm + + + + + + attendee + + + + + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + + field + + + + + + + field + + + + + + + {'tentative': 'draft', 'confirmed': 'open', 'cancelled': 'cancel'} + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + + field + + + + + + - \ No newline at end of file + 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 - + diff --git a/addons/survey/report/survey_analysis_report.py b/addons/survey/report/survey_analysis_report.py index 79871a63084..069488034d8 100755 --- a/addons/survey/report/survey_analysis_report.py +++ b/addons/survey/report/survey_analysis_report.py @@ -257,6 +257,8 @@ class survey_analysis(report_rml): sqc.question_id = sr.question_id and sra.answer_id = %d and sqc.title ='%s'\ group by sra.answer_id,sqc.rating_weight" % (ans.id,matrix_ans[mat_col])) col_weight = cr.fetchone() + if not col_weight : + col_weight= (0,0) res_count = col_weight[0] if tot_res: rating_weight_sum += col_weight[1] * tot_res diff --git a/addons/survey/report/survey_browse_response.py b/addons/survey/report/survey_browse_response.py index 26ac0e54103..6e26f21e5b3 100644 --- a/addons/survey/report/survey_browse_response.py +++ b/addons/survey/report/survey_browse_response.py @@ -268,7 +268,7 @@ class survey_browse_response(report_rml): """ elif que.type in ['matrix_of_choices_only_one_ans','matrix_of_choices_only_multi_ans','rating_scale','matrix_of_drop_down_menus']: if len(answer) and answer[0].state == "done": - if que.comment_column: + if que.type in ['matrix_of_choices_only_one_ans','rating_scale'] and que.comment_column: pass cols_widhts = [] cols_widhts.append(200) @@ -278,7 +278,7 @@ class survey_browse_response(report_rml): tmp=0.0 sum = 0.0 i = 0 - if que.comment_column: + if que.type in ['matrix_of_choices_only_one_ans','rating_scale'] and que.comment_column: for col in cols_widhts: if i==0: cols_widhts[i] = cols_widhts[i]/2.0 @@ -292,7 +292,7 @@ class survey_browse_response(report_rml): if col.title not in matrix_ans: matrix_ans.append(col.title) len_matrix = len(matrix_ans) - if que.comment_column: + if que.type in ['matrix_of_choices_only_one_ans','rating_scale'] and que.comment_column: matrix_ans.append(que.column_name) rml+="""""" for mat_col in matrix_ans: @@ -342,14 +342,14 @@ class survey_browse_response(report_rml): """ rml+= """""" + value + """""" - if que.comment_column: + if que.type in ['matrix_of_choices_only_one_ans','rating_scale'] and que.comment_column: if comment_value=='False': comment_value = '' rml+= """"""+ to_xml(tools.ustr(comment_value)) + """""" rml+=""" """ - if que.comment_field_type: + if que.is_comment_require: rml+=""" - """ + to_xml(tools.ustr(answer[0].comment)) + """""" + """ + to_xml(tools.ustr(answer[0].comment or '')) + """""" else: rml +=""" No Response diff --git a/addons/survey/survey.py b/addons/survey/survey.py index c6a4a1daf2b..632f4c768ef 100644 --- a/addons/survey/survey.py +++ b/addons/survey/survey.py @@ -331,9 +331,9 @@ class survey_question(osv.osv): raise osv.except_osv(_('Error !'),_("Maximum Required Answer is greater than Minimum Required Answer")) if question['type'] == 'matrix_of_drop_down_menus' and vals.has_key('column_heading_ids'): for col in vals['column_heading_ids']: - if col[2].has_key('menu_choice') and not col[2]['menu_choice']: + if col[2] and col[2].has_key('menu_choice') and not col[2]['menu_choice']: raise osv.except_osv(_('Error !'),_("You must enter one or more menu choices in column heading")) - elif col[2].has_key('menu_choice') and col[2]['menu_choice'].strip() == '': + elif col[2] and col[2].has_key('menu_choice') and col[2]['menu_choice'].strip() == '': raise osv.except_osv(_('Error !'),_("You must enter one or more menu choices in column heading (white spaces not allowed)")) return super(survey_question, self).write(cr, uid, ids, vals, context=context) @@ -740,24 +740,28 @@ class survey_question_wiz(osv.osv_memory): fields[tools.ustr(que) + "_commentcolumn_"+tools.ustr(row['id']) + "_field"] = {'type':'char', 'size' : 255, 'string':tools.ustr(que_rec['column_name']), 'views':{}} etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_commentcolumn_"+tools.ustr(row['id'])+ "_field"}) elif que_rec['type'] == 'matrix_of_choices_only_multi_ans': - xml_group = etree.SubElement(xml_group, 'group', {'col': '2', 'colspan': '2'}) + xml_group = etree.SubElement(xml_group, 'group', {'col': str(len(que_rec['column_heading_ids']) + 1), 'colspan': '4'}) + etree.SubElement(xml_group, 'separator', {'string': '.','colspan': '1'}) + for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']): + etree.SubElement(xml_group, 'separator', {'string': tools.ustr(col['title']),'colspan': '1'}) for row in ans_ids: etree.SubElement(xml_group, 'label', {'string': to_xml(tools.ustr(row['answer'])) +' :-', 'align': '0.0'}) - etree.SubElement(xml_group, 'newline') for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']): - etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(row['id']) + "_" + tools.ustr(col['title'])}) + etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(row['id']) + "_" + tools.ustr(col['title']), 'nolabel':"1"}) fields[tools.ustr(que) + "_" + tools.ustr(row['id']) + "_" + tools.ustr(col['title'])] = {'type':'boolean', 'string': col['title']} elif que_rec['type'] == 'matrix_of_drop_down_menus': - xml_group = etree.SubElement(xml_group, 'group', {'col': '2', 'colspan': '2'}) + xml_group = etree.SubElement(xml_group, 'group', {'col': str(len(que_rec['column_heading_ids']) + 1), 'colspan': '4'}) + etree.SubElement(xml_group, 'separator', {'string': '.','colspan': '1'}) + for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']): + etree.SubElement(xml_group, 'separator', {'string': tools.ustr(col['title']),'colspan': '1'}) for row in ans_ids: etree.SubElement(xml_group, 'label', {'string': to_xml(tools.ustr(row['answer']))+' :-', 'align': '0.0'}) - etree.SubElement(xml_group, 'newline') for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']): selection = [] if col['menu_choice']: for item in col['menu_choice'].split('\n'): if item and not item.strip() == '': selection.append((item ,item)) - etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(row['id']) + "_" + tools.ustr(col['title'])}) + etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(row['id']) + "_" + tools.ustr(col['title']),'nolabel':'1'}) fields[tools.ustr(que) + "_" + tools.ustr(row['id']) + "_" + tools.ustr(col['title'])] = {'type':'selection', 'string': col['title'], 'selection':selection} elif que_rec['type'] == 'multiple_textboxes': xml_group = etree.SubElement(xml_group, 'group', {'col': '1', 'colspan': '4'}) @@ -1238,7 +1242,7 @@ class survey_question_wiz(osv.osv_memory): numeric_sum += int(val) elif val and len(key.split('_')) == 3: resp_obj.write(cr, uid, update, {'state': 'done'}) - if type(val) == type(''): + if type(val) == type('') or type(val) == type(u''): ans_create_id = res_ans_obj.create(cr, uid, {'response_id':update, 'answer_id':ans_id_len[1], 'answer' : ans_id_len[2], 'value_choice' : val}) sur_name_read['store_ans'][update].update({key:val}) else: diff --git a/addons/survey/survey_view.xml b/addons/survey/survey_view.xml index 70b41b589fe..5085ed4986d 100644 --- a/addons/survey/survey_view.xml +++ b/addons/survey/survey_view.xml @@ -30,7 +30,7 @@