[IMP]: project_calendar: Made task management compatible with new changes in caldav + View and functionality Improvement according to meeting

bzr revid: rpa@openerp.co.in-20100113100718-rpb2z3ihiyxooo07
This commit is contained in:
rpa (Open ERP) 2010-01-13 15:37:18 +05:30
parent 6de7c24b14
commit f400e195cf
2 changed files with 277 additions and 136 deletions

View File

@ -31,69 +31,82 @@ class project_task(osv.osv):
_inherit = "project.task"
_columns = {
'class': fields.selection([('PUBLIC', 'PUBLIC'), ('PRIVATE', 'PRIVATE'), \
('CONFIDENTIAL', 'CONFIDENTIAL')], 'Privacy'),
'location' : fields.char('Location', size=264, help="Gives Location of Task"),
'rrule' : fields.char('Recurrent Rule', size=352),
'exdate' : fields.text('Exception Date/Times', help="This property defines the list\
of date/time exceptions for arecurring calendar component."),
'exrule' : fields.char('Exception Rule', size=352, help="defines a rule or repeating pattern\
for anexception to a recurrence set"),
'attendee_ids': fields.many2many('crm.caldav.attendee', 'task_attendee_rel', 'case_id', \
'attendee_id', 'Attendees'),
'alarm_id': fields.many2one('crm.caldav.alarm', 'Reminder'),
'caldav_url': fields.char('Caldav URL', size=34),
'class': fields.selection([('public', 'Public'), ('private', 'Private'), \
('confidential', 'Confidential')], 'Mark as'),
'location': fields.char('Location', size=264, help="Location of Task"),
'exdate': fields.text('Exception Date/Times', help="This property \
defines the list of date/time exceptions for arecurring calendar component."),
'exrule': fields.char('Exception Rule', size=352, help="defines a rule\
or repeating pattern for anexception to a recurrence set"),
'attendee_ids': fields.many2many('calendar.attendee', 'task_attendee_rel', 'task_id', 'attendee_id', 'Attendees'),
'caldav_url': fields.char('Calendar URL', size=34),
'rrule': fields.char('Recurrent Rule', size=124),
'rrule_type': fields.selection([('none', 'None'), ('daily', 'Daily'), \
('weekly', 'Weekly'), ('monthly', 'Monthly'), \
('yearly', 'Yearly'), ('custom', 'Custom')], 'Recurrency'),
'alarm_id': fields.many2one('res.alarm', 'Alarm'),
'caldav_alarm_id': fields.many2one('calendar.alarm', 'Alarm'),
}
__attribute__ = {
'class': {'field': 'class', 'type': 'text'},
'completed': {'field': 'date_close', 'type': 'datetime'},
# 'created': {'field': 'field', 'type': 'text'},
# 'created': {'field': 'field', 'type': 'text'},
'description': {'field': 'description', 'type': 'text'},
# 'dtstamp': {'field': 'field', 'type': 'text'},
# 'dtstamp': {'field': 'field', 'type': 'text'},
'dtstart': {'field': 'date_start', 'type': 'datetime'},
'duration': {'field': 'planned_hours', 'type': 'timedelta'},
'due': {'field': 'date_deadline', 'type': 'datetime'},
# 'geo': {'field': 'field', 'type': 'text'},
# 'last-mod ': {'field': 'field', 'type': 'text'},
'location': {'field': 'location', 'type': 'text'}, # To add
# 'geo': {'field': 'field', 'type': 'text'},
# 'last-mod ': {'field': 'field', 'type': 'text'},
'location': {'field': 'location', 'type': 'text'},
'organizer': {'field': 'partner_id', 'type': 'many2one', 'object': 'res.partner'},
'percent': {'field': 'progress_rate', 'type': 'int'},
'priority': {'field': 'priority', 'type': 'text'},
# 'recurid': {'field': 'field', 'type': 'text'},
# 'recurid': {'field': 'field', 'type': 'text'},
'seq': {'field': 'sequence', 'type': 'text'},
'status': {'field': 'state', 'type': 'selection', 'mapping': {'NEEDS-ACTION': 'draft', \
'COMPLETED': 'done', 'IN-PROCESS': 'open', \
'CANCELLED': 'cancelled'}},
'status': {'field': 'state', 'type': 'selection', \
'mapping': {'needs-action': 'draft', \
'completed': 'done', 'in-process': 'open', \
'cancelled': 'cancelled'}},
'summary': {'field': 'name', 'type': 'text'},
'uid': {'field': 'id', 'type': 'int'},
'url': {'field': 'caldav_url', 'type': 'text'}, # To add
# 'attach': {'field': 'field', 'type': 'text'},
'attendee': {'field': 'attendee_ids', 'type': 'many2many', 'object': 'crm.caldav.attendee'},
# 'categories': {'field': 'type', 'type': 'text'}, # Needs review
'url': {'field': 'caldav_url', 'type': 'text'},
# 'attach': {'field': 'field', 'type': 'text'},
'attendee': {'field': 'attendee_ids', 'type': 'many2many', 'object': 'calendar.attendee'},
'comment': {'field': 'notes', 'type': 'text'},
# 'contact': {'field': 'field', 'type': 'text'},
'exdate' : {'field':'exdate', 'type':'datetime'},
'exrule' : {'field':'exrule', 'type':'text'},
# 'rstatus': {'field': 'field', 'type': 'text'},
# 'related': {'field': 'field', 'type': 'text'},
# 'resources': {'field': 'field', 'type': 'text'},
# 'rdate': {'field': 'field', 'type': 'text'},
# 'contact': {'field': 'field', 'type': 'text'},
'exdate': {'field':'exdate', 'type':'datetime'},
'exrule': {'field':'exrule', 'type':'text'},
# 'rstatus': {'field': 'field', 'type': 'text'},
# 'related': {'field': 'field', 'type': 'text'},
# 'resources': {'field': 'field', 'type': 'text'},
# 'rdate': {'field': 'field', 'type': 'text'},
'rrule': {'field': 'rrule', 'type': 'text'},
'valarm' : {'field':'alarm_id', 'type':'many2one', 'object' : 'crm.caldav.alarm'},
'valarm': {'field':'caldav_alarm_id', 'type':'many2one', 'object': 'calendar.alarm'},
}
def onchange_rrule_type(self, cr, uid, ids, type, *args, **argv):
if type == 'none':
return {'value': {'rrule': ''}}
if type == 'custom':
return {}
rrule = self.pool.get('calendar.custom.rrule')
rrulestr = rrule.compute_rule_string(cr, uid, {'freq': type.upper(), \
'interval': 1})
return {'value': {'rrule': rrulestr}}
def import_cal(self, cr, uid, data, context={}):
file_content = base64.decodestring(data)
todo_obj = self.pool.get('caldav.todo')
todo_obj = self.pool.get('basic.calendar.todo')
todo_obj.__attribute__.update(self.__attribute__)
attendee_obj = self.pool.get('caldav.attendee')
crm_attendee = self.pool.get('crm.caldav.attendee')
attendee_obj = self.pool.get('basic.calendar.attendee')
crm_attendee = self.pool.get('calendar.attendee')
attendee_obj.__attribute__.update(crm_attendee.__attribute__)
alarm_obj = self.pool.get('caldav.alarm')
crm_alarm = self.pool.get('crm.caldav.alarm')
alarm_obj = self.pool.get('basic.calendar.alarm')
crm_alarm = self.pool.get('calendar.alarm')
alarm_obj.__attribute__.update(crm_alarm.__attribute__)
vals = todo_obj.import_ical(cr, uid, file_content)
@ -107,89 +120,159 @@ class project_task(osv.osv):
plan = (diff.seconds/float(86400) + diff.days) * obj_tm.factor
val['planned_hours'] = plan
else:
# Converts timedelta into Project time unit
val['planned_hours'] = (val['planned_hours'].seconds/float(86400) + \
val['planned_hours'].days) * obj_tm.factor
is_exists = common.uid2openobjectid(cr, val['id'], self._name )
# Converts timedelta into hours
hours = (val['planned_hours'].seconds / float(3600)) + \
(val['planned_hours'].days * 24)
val['planned_hours'] = hours
is_exists = common.uid2openobjectid(cr, val['id'], self._name)
val.pop('id')
if is_exists:
self.write(cr, uid, [is_exists], val)
else:
case_id = self.create(cr, uid, val)
task_id = self.create(cr, uid, val)
return {'count': len(vals)}
def export_cal(self, cr, uid, ids, context={}):
task_data = self.read(cr, uid, ids, [], context ={'read': True})
todo_obj = self.pool.get('caldav.todo')
task_datas = self.read(cr, uid, ids, [], context ={'read': True})
tasks = []
for task in task_datas:
if task.get('planned_hours', None) and task.get('date_deadline', None):
task.pop('planned_hours')
tasks.append(task)
todo_obj = self.pool.get('basic.calendar.todo')
todo_obj.__attribute__.update(self.__attribute__)
attendee_obj = self.pool.get('caldav.attendee')
attendee = self.pool.get('crm.caldav.attendee')
attendee_obj = self.pool.get('basic.calendar.attendee')
attendee = self.pool.get('calendar.attendee')
attendee_obj.__attribute__.update(attendee.__attribute__)
alarm_obj = self.pool.get('caldav.alarm')
alarm = self.pool.get('crm.caldav.alarm')
alarm_obj = self.pool.get('basic.calendar.alarm')
alarm = self.pool.get('calendar.alarm')
alarm_obj.__attribute__.update(alarm.__attribute__)
ical = todo_obj.export_ical(cr, uid, task_data, {'model': 'project.task'})
ical = todo_obj.export_ical(cr, uid, tasks, {'model': 'project.task'})
caendar_val = ical.serialize()
caendar_val = caendar_val.replace('"', '').strip()
return caendar_val
def read(self, cr, uid, ids, fields=None, context={}, load='_classic_read'):
""" logic for recurrent event
example : 123-20091111170822"""
if context and context.has_key('read'):
return super(project_task, self).read(cr, uid, ids, fields=fields, context=context, \
load=load)
if not type(ids) == list :
# Called from code
return super(project_task, self).read(cr, uid, common.caldevIDs2readIDs(ids), \
fields=fields, context=context, load=load)
def get_recurrent_ids(self, cr, uid, select, base_start_date, base_until_date, limit=100):
if not limit:
limit = 100
if isinstance(select, (str, int, long)):
ids = [select]
else:
ids = map(lambda x:common.caldevIDs2readIDs(x), ids)
ids = select
result = []
if ids and (base_start_date or base_until_date):
cr.execute("select t.id, t.rrule, t.date_start, t.exdate \
from project_task t\
where t.id in ("+ ','.join(map(lambda x: str(x), ids))+")")
count = 0
for data in cr.dictfetchall():
start_date = base_start_date and datetime.strptime(base_start_date, "%Y-%m-%d") or False
until_date = base_until_date and datetime.strptime(base_until_date, "%Y-%m-%d") or False
if count > limit:
break
event_date = datetime.strptime(data['date_start'], "%Y-%m-%d %H:%M:%S")
if start_date and start_date <= event_date:
start_date = event_date
if not data['rrule']:
if start_date and event_date < start_date:
continue
if until_date and event_date > until_date:
continue
idval = common.real_id2caldav_id(data['id'], data['date_start'])
result.append(idval)
count += 1
else:
exdate = data['exdate'] and data['exdate'].split(',') or []
event_obj = self.pool.get('basic.calendar.event')
rrule_str = data['rrule']
new_rrule_str = []
rrule_until_date = False
is_until = False
for rule in rrule_str.split(';'):
name, value = rule.split('=')
if name == "UNTIL":
is_until = True
value = parser.parse(value)
rrule_until_date = parser.parse(value.strftime("%Y-%m-%d"))
if until_date and until_date >= rrule_until_date:
until_date = rrule_until_date
if until_date:
value = until_date.strftime("%Y%m%d%H%M%S")
new_rule = '%s=%s' % (name, value)
new_rrule_str.append(new_rule)
if not is_until and until_date:
value = until_date.strftime("%Y%m%d%H%M%S")
name = "UNTIL"
new_rule = '%s=%s' % (name, value)
new_rrule_str.append(new_rule)
new_rrule_str = ';'.join(new_rrule_str)
start_date = datetime.strptime(data['date_start'], "%Y-%m-%d %H:%M:%S")
rdates = event_obj.get_recurrent_dates(str(new_rrule_str), exdate, start_date)
for rdate in rdates:
r_date = datetime.strptime(rdate, "%Y-%m-%d %H:%M:%S")
if start_date and r_date < start_date:
continue
if until_date and r_date > until_date:
continue
idval = common.real_id2caldav_id(data['id'], rdate)
result.append(idval)
count += 1
if result:
ids = result
if isinstance(select, (str, int, long)):
return ids and ids[0] or False
return ids
def search(self, cr, uid, args, offset=0, limit=100, order=None,
context=None, count=False):
args_without_date = []
start_date = False
until_date = False
for arg in args:
if arg[0] not in ('date_start', unicode('date_start')):
args_without_date.append(arg)
else:
if arg[1] in ('>', '>='):
start_date = arg[2]
elif arg[1] in ('<', '<='):
until_date = arg[2]
res = super(project_task, self).search(cr, uid, args_without_date, offset,
limit, order, context, count)
return self.get_recurrent_ids(cr, uid, res, start_date, until_date, limit)
def read(self, cr, uid, ids, fields=None, context={}, load='_classic_read'):
if isinstance(ids, (str, int, long)):
select = [ids]
else:
select = ids
select = map(lambda x: (x, common.caldav_id2real_id(x)), select)
result = []
if fields and 'date_start' not in fields:
fields.append('date_start')
if not ids:
return []
result = []
for read_id in ids:
res = super(project_task, self).read(cr, uid, read_id, fields=fields, context=context, load=load)
cr.execute("""select id, rrule, date_start, exdate \
from project_task where id = %s""" % read_id)
data = cr.dictfetchall()[0]
if not data['rrule']:
strdate = ''.join((re.compile('\d')).findall(data['date_start']))
idval = str(common.caldevIDs2readIDs(data['id'])) + '-' + strdate
data['id'] = idval
res.update(data)
result.append(res)
else:
exdate = data['exdate'] and data['exdate'].split(',') or []
event_obj = self.pool.get('caldav.event')
rdates = event_obj.get_recurrent_dates(str(data['rrule']), exdate, data['date_start'])[:10]
for rdate in rdates:
val = res.copy()
idval = (re.compile('\d')).findall(rdate)
val['date_start'] = rdate
id = str(res['id']).split('-')[0]
val['id'] = id + '-' + ''.join(idval)
val1 = val.copy()
result.append(val1)
for caldav_id, real_id in select:
res = super(project_task, self).read(cr, uid, real_id, fields=fields, context=context, load=load)
ls = common.caldav_id2real_id(caldav_id, with_date=True)
if not isinstance(ls, (str, int, long)) and len(ls) >= 2:
res['date_start'] = ls[1]
res['id'] = caldav_id
result.append(res)
if isinstance(ids, (str, int, long)):
return result and result[0] or False
return result
def search(self, cr, uid, args, offset=0, limit=None, order=None,
context=None, count=False):
res = super(project_task, self).search(cr, uid, args, offset,
limit, order, context, count)
return res
def write(self, cr, uid, ids, vals, context=None):
def write(self, cr, uid, ids, vals, context=None, check=True, update_check=True):
if isinstance(ids, (str, int, long)):
select = [ids]
else:
select = ids
new_ids = []
for id in ids:
id = common.caldevIDs2readIDs(id)
for id in select:
id = common.caldav_id2real_id(id)
if not id in new_ids:
new_ids.append(id)
res = super(project_task, self).write(cr, uid, new_ids, vals, context=context)
@ -199,39 +282,34 @@ class project_task(osv.osv):
if isinstance(ids, (str, int, long)):
select = [ids]
else:
select = ids
select = map(lambda x:common.caldevIDs2readIDs(x), select)
res = super(project_task, self).browse(cr, uid, select, context, list_class, fields_process)
select = ids
select = map(lambda x:common.caldav_id2real_id(x), select)
res = super(project_task, self).browse(cr, uid, select, context, list_class, fields_process)
if isinstance(ids, (str, int, long)):
return res and res[0] or False
return res
def copy(self, cr, uid, id, default=None, context={}):
return super(project_task, self).copy(cr, uid, common.caldevIDs2readIDs(id), default, context)
return super(project_task, self).copy(cr, uid, common.caldav_id2real_id(id), default, context)
def unlink(self, cr, uid, ids, context=None):
for id in ids:
if len(str(id).split('-')) > 1:
date_new = time.strftime("%Y-%m-%d %H:%M:%S", \
time.strptime(str(str(id).split('-')[1]), "%Y%m%d%H%M%S"))
for record in self.read(cr, uid, [common.caldevIDs2readIDs(id)], \
['date', 'rrule', 'exdate']):
for record in self.read(cr, uid, [common.caldav_id2real_id(id)], \
['date_start', 'rrule', 'exdate']):
if record['rrule']:
exdate = (record['exdate'] and (record['exdate'] + ',' ) or '') + \
exdate = (record['exdate'] and (record['exdate'] + ',') or '') + \
''.join((re.compile('\d')).findall(date_new)) + 'Z'
if record['date_start'] == date_new:
self.write(cr, uid, [common.caldevIDs2readIDs(id)], {'exdate' : exdate})
self.write(cr, uid, [common.caldav_id2real_id(id)], {'exdate': exdate})
else:
ids = map(lambda x:common.caldevIDs2readIDs(x), ids)
ids = map(lambda x:common.caldav_id2real_id(x), ids)
return super(project_task, self).unlink(cr, uid, ids)
else:
return super(project_task, self).unlink(cr, uid, ids)
def create(self, cr, uid, vals, context={}):
if 'case_id' in vals:
vals['case_id'] = common.caldevIDs2readIDs(vals['case_id'])
return super(project_task, self).create(cr, uid, vals, context)
project_task()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -21,27 +21,90 @@
<field name="type">form</field>
<field name="arch" type="xml">
<notebook position="inside">
<page string="Calendar Properties">
<field name="class"/>
<field name="caldav_url" widget="url"/>
<field name="location"/>
<field name="alarm_id"/>
<newline/>
<field name="rrule" colspan="2"/>
<button string="Change RRule" name="97"
icon="gtk-save-as" type="action" colspan="2"
context="{'model' : 'project.task'}"/>
<field name="exrule" colspan="4"/>
<separator string="Exception Dates" colspan="4"/>
<field name="exdate" nolabel="1" colspan="4"/>
</page>
<page string="Attendee Details">
<separator string="Attendee" colspan="4"/>
<field name="attendee_ids" colspan="4" nolabel="1"/>
<page string="Assignees Detail">
<button string="Assign Task"
name="%(caldav.action_view_calendar_invite_attendee_wizard)d"
icon="terp-partner" type="action"
context="{'model' : 'project.task'}" colspan="2"/>
<field name="attendee_ids" colspan="4"
nolabel="1" widget="one2many" mode="tree,form">
<tree string="Assignees details"
editable="top">
<field name="email" />
<field name="role" select="1" />
<field name="state" />
</tree>
<form string="Assignees details">
<notebook colspan="4">
<page string="Details">
<field name="email" />
<field name="rsvp" select="1" />
<field name="cutype" select="1" />
<field name="role" select="1" />
<separator colspan="4"
string="" />
<field name="state" />
</page>
<page string="Other">
<field name="user_id"
select="1" />
<field name="partner_address_id"
select="1" />
<newline />
</page>
</notebook>
</form>
</field>
</page>
</notebook>
</field>
</record>
<record id="view_project_caldav_task_form1" model="ir.ui.view">
<field name="name">project.task.caldav.form1</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_form2"/>
<field name="type">form</field>
<field name="arch" type="xml">
<field name="sequence" position="after">
<field name="class" />
</field>
</field>
</record>
<record id="view_project_caldav_task_form2" model="ir.ui.view">
<field name="name">project.task.caldav.form2</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_form2" />
<field name="type">form</field>
<field name="arch" type="xml">
<field name="date_close" position="after">
<group colspan="2" col="3">
<field name="rrule_type" string="Recurrency"
on_change="onchange_rrule_type(rrule_type)" colspan="1" />
<button string="Custom" name="101"
icon="gtk-save-as" type="action"
context="{'model' : 'project.task'}"
attrs="{'readonly': [('rrule_type','!=','custom')]}" />
</group>
</field>
</field>
</record>
<record id="view_project_caldav_task_form3" model="ir.ui.view">
<field name="name">project.task.caldav.form3</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_form2" />
<field name="type">form</field>
<field name="arch" type="xml">
<field name="partner_id" position="after">
<field name="location" colspan="2" />
<field name="alarm_id" string="Reminder" widget="selection" />
<field name="caldav_url" widget="url" />
<field name="rrule" invisible="1"/>
</field>
</field>
</record>
</data>
</openerp>