Files
tryton/work.py
T
2011-03-31 14:44:31 +02:00

270 lines
9.5 KiB
Python

#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import copy
from trytond.model import ModelView, ModelSQL, fields
from trytond.model.modelstorage import OPERATORS
from trytond.pyson import Not, Bool, Eval, Get, Equal
from trytond.transaction import Transaction
class TimesheetWork(ModelSQL, ModelView):
_name = 'timesheet.work'
timesheet_lines = fields.One2Many('timesheet.line', 'work',
'Timesheet Lines',
depends=['timesheet_available', 'active'],
states={
'invisible': Not(Bool(Eval('timesheet_available'))),
'readonly': Not(Bool(Eval('active'))),
})
sequence = fields.Integer('Sequence')
def __init__(self):
super(TimesheetWork, self).__init__()
self._order.insert(0, ('sequence', 'ASC'))
self.parent = copy.copy(self.parent)
self.parent.context = copy.copy(self.parent.context)
self.parent.context['type'] = Eval('type')
self._reset_columns()
TimesheetWork()
class Work(ModelSQL, ModelView):
'Work Effort'
_name = 'project.work'
_description = __doc__
_inherits = {'timesheet.work': 'work'}
work = fields.Many2One('timesheet.work', 'Work', required=True,
ondelete='CASCADE')
type = fields.Selection([
('project', 'Project'),
('task', 'Task')
],
'Type', required=True, select=1,
states={
'invisible': Get(Eval('context', {}), 'type', False),
})
party = fields.Many2One('party.party', 'Party',
states={
'invisible': Not(Equal(Eval('type'), 'project')),
}, depends=['type'])
party_address = fields.Many2One('party.address', 'Contact Address',
domain=[('party', '=', Eval('party'))],
states={
'invisible': Not(Equal(Eval('type'), 'project')),
}, depends=['party', 'type'])
effort = fields.Float("Effort",
states={
'invisible': Not(Equal(Eval('type'), 'task')),
}, depends=['type'], help="Estimated Effort for this work")
total_effort = fields.Function(fields.Float('Total Effort',
help="Estimated total effort for this work and the sub-works"),
'get_total_effort')
comment = fields.Text('Comment')
parent = fields.Function(fields.Many2One('project.work', 'Parent'),
'get_parent', setter='set_parent', searcher='search_parent')
children = fields.One2Many('project.work', 'parent', 'Children')
state = fields.Selection([
('opened', 'Opened'),
('done', 'Done'),
], 'State',
states={
'invisible': Not(Equal(Eval('type'), 'task')),
'required': Equal(Eval('type'), 'task'),
}, select=1, depends=['type'])
def default_type(self):
if Transaction().context.get('type') == 'project':
return 'project'
return 'task'
def default_state(self):
return 'opened'
def __init__(self):
super(Work, self).__init__()
self._sql_constraints += [
('work_uniq', 'UNIQUE(work)', 'There should be only one '\
'timesheet work by task/project!'),
]
self._order.insert(0, ('sequence', 'ASC'))
if 'company' in self._inherit_fields:
company_field = copy.copy(
self._inherit_fields['company'])
company_field[2].states = copy.copy(company_field[2].states)
company_field[2].states.update({
'invisible': Bool(Get(Eval('context', {}), 'type')),
'readonly': Not(Bool(Eval('active'))),
})
self._inherit_fields['company'] = company_field
def get_parent(self, ids, name):
res = dict.fromkeys(ids, None)
project_works = self.browse(ids)
# ptw2pw is "parent timesheet work to project works":
ptw2pw = {}
for project_work in project_works:
if project_work.work.parent.id in ptw2pw:
ptw2pw[project_work.work.parent.id].append(project_work.id)
else:
ptw2pw[project_work.work.parent.id] = [project_work.id]
with Transaction().set_context(active_test=False):
parent_project_ids = self.search([
('work', 'in', ptw2pw.keys()),
])
parent_projects = self.browse(parent_project_ids)
for parent_project in parent_projects:
if parent_project.work.id in ptw2pw:
child_projects = ptw2pw[parent_project.work.id]
for child_project in child_projects:
res[child_project] = parent_project.id
return res
def set_parent(self, ids, name, value):
timesheet_work_obj = self.pool.get('timesheet.work')
if value:
project_works = self.browse(ids + [value])
child_timesheet_work_ids = [x.work.id for x in project_works[:-1]]
parent_timesheet_work_id = project_works[-1].work.id
else:
child_project_works = self.browse(ids)
child_timesheet_work_ids = [x.work.id for x in child_project_works]
parent_timesheet_work_id = False
timesheet_work_obj.write(child_timesheet_work_ids, {
'parent': parent_timesheet_work_id
})
def search_parent(self, name, domain=None):
timesheet_work_obj = self.pool.get('timesheet.work')
project_work_domain = []
timesheet_work_domain = []
if domain[0].startswith('parent.'):
project_work_domain.append(
(domain[0].replace('parent.', ''),)
+ domain[1:])
elif domain[0] == 'parent':
timesheet_work_domain.append(domain)
# ids timesheet_work_domain in operand are project_work ids,
# we need to convert them to timesheet_work ids
operands = set()
for _, _, operand in timesheet_work_domain:
if isinstance(operand, (int, long)) and not isinstance(operand, bool):
operands.add(operand)
elif isinstance(operand, list):
for o in operand:
if isinstance(o, (int, long)) and not isinstance(o, bool):
operands.add(o)
pw2tw = {}
if operands:
operands = list(operands)
# filter out non-existing ids:
operands = self.search([
('id', 'in', operands)
])
# create project_work > timesheet_work mapping
for pw in self.browse(operands):
pw2tw[pw.id] = pw.work.id
for i, d in enumerate(timesheet_work_domain):
if isinstance(d[2], (int, long)):
new_d2 = pw2tw.get(d[2], 0)
elif isinstance(d[2], list):
new_d2 = []
for item in d[2]:
item = pw2tw.get(item, 0)
new_d2.append(item)
timesheet_work_domain[i] = (d[0], d[1], new_d2)
if project_work_domain:
pw_ids = self.search(project_work_domain)
project_works = self.browse(pw_ids)
timesheet_work_domain.append(
('id', 'in', [pw.work.id for pw in project_works]))
tw_ids = timesheet_work_obj.search(timesheet_work_domain)
return [('work', 'in', tw_ids)]
def get_total_effort(self, ids, name):
all_ids = self.search([
('parent', 'child_of', ids),
('active', '=', True),
]) + ids
all_ids = list(set(all_ids))
works = self.browse(all_ids)
res = {}
id2work = {}
leafs = set()
for work in works:
res[work.id] = work.effort
id2work[work.id] = work
if not work.children:
leafs.add(work.id)
while leafs:
parents = set()
for work_id in leafs:
work = id2work[work_id]
if not work.active:
continue
if work.parent and work.parent.id in res:
res[work.parent.id] += res[work_id]
parents.add(work.parent.id)
leafs = parents
return res
def copy(self, ids, default=None):
timesheet_work_obj = self.pool.get('timesheet.work')
int_id = isinstance(ids, (int, long))
if int_id:
ids = [ids]
if default is None:
default = {}
new_ids = []
for project_work in self.browse(ids):
timesheet_work_id = timesheet_work_obj.copy(project_work.work.id,
default=default)
pwdefault = default.copy()
pwdefault['work'] = timesheet_work_id
new_ids.append(super(Work, self).copy(project_work.id,
default=pwdefault))
if int_id:
return new_ids[0]
return new_ids
def delete(self, ids):
timesheet_work_obj = self.pool.get('timesheet.work')
if isinstance(ids, (int, long)):
ids = [ids]
# Get the timesheet works linked to the project works
project_works = self.browse(ids)
timesheet_work_ids = [pw.work.id for pw in project_works]
res = super(Work, self).delete(ids)
timesheet_work_obj.delete(timesheet_work_ids)
return res
Work()