Files
tryton/work.py
T

235 lines
8.1 KiB
Python
Raw Normal View History

2009-02-28 17:07:12 +01:00
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
2013-09-06 22:35:00 +02:00
from sql import Literal
from sql.aggregate import Sum
2009-02-28 17:07:12 +01:00
from trytond.model import ModelView, ModelSQL, fields
2012-01-02 18:10:18 +01:00
from trytond.wizard import Wizard, StateView, StateAction, Button
from trytond.pyson import PYSONEncoder, Not, Bool, Eval
2010-08-10 11:59:04 -04:00
from trytond.transaction import Transaction
2011-07-03 13:19:21 +02:00
from trytond.pool import Pool
2013-08-21 18:40:44 +02:00
from trytond.tools import reduce_ids
2011-07-03 13:19:21 +02:00
2012-09-24 22:18:28 +02:00
__all__ = ['Work', 'OpenWorkStart', 'OpenWork', 'OpenWork2', 'OpenWorkGraph']
2008-05-29 17:55:36 +02:00
2009-02-28 17:07:12 +01:00
class Work(ModelSQL, ModelView):
2008-06-09 16:54:33 +02:00
'Work'
2012-09-24 22:18:28 +02:00
__name__ = 'timesheet.work'
2008-05-29 17:55:36 +02:00
name = fields.Char('Name', required=True)
2008-06-02 17:18:11 +02:00
active = fields.Boolean('Active')
2009-06-03 16:32:58 +02:00
parent = fields.Many2One('timesheet.work', 'Parent', left="left",
2012-03-05 10:53:10 +01:00
right="right", select=True, ondelete="RESTRICT")
left = fields.Integer('Left', required=True, select=True)
right = fields.Integer('Right', required=True, select=True)
2009-05-22 19:11:29 +02:00
children = fields.One2Many('timesheet.work', 'parent', 'Children')
2010-03-11 16:55:07 +01:00
hours = fields.Function(fields.Float('Timesheet Hours', digits=(16, 2),
2012-09-21 15:41:53 +02:00
states={
'invisible': ~Eval('timesheet_available'),
},
depends=['timesheet_available'],
help="Total time spent on this work"), 'get_hours')
2009-06-03 16:33:29 +02:00
timesheet_available = fields.Boolean('Available on timesheets',
help="Allow to fill in timesheets with this work")
2013-01-26 15:13:51 +01:00
timesheet_start_date = fields.Date('Timesheet Start',
states={
'invisible': ~Eval('timesheet_available'),
},
depends=['timesheet_available'])
timesheet_end_date = fields.Date('Timesheet End',
states={
'invisible': ~Eval('timesheet_available'),
},
depends=['timesheet_available'])
2012-03-14 09:35:19 +01:00
company = fields.Many2One('company.company', 'Company', required=True,
select=True)
timesheet_lines = fields.One2Many('timesheet.line', 'work',
2011-08-04 16:57:47 +02:00
'Timesheet Lines',
depends=['timesheet_available', 'active'],
states={
'invisible': Not(Bool(Eval('timesheet_available'))),
'readonly': Not(Bool(Eval('active'))),
})
2008-06-02 17:18:11 +02:00
2012-09-24 22:18:28 +02:00
@classmethod
def __setup__(cls):
super(Work, cls).__setup__()
cls._error_messages.update({
'invalid_parent_company': ('Every work must be in the same '
'company as it\'s parent work but "%(child)s" and '
'"%(parent)s" are in different companies.'),
'change_timesheet_available': ('You can not unset "Available '
'on timesheets" for work "%s" because it already has '
'timesheets.'),
2012-09-24 22:18:28 +02:00
})
2012-09-24 22:18:28 +02:00
@staticmethod
def default_active():
2008-06-02 17:18:11 +02:00
return True
2012-09-24 22:18:28 +02:00
@staticmethod
def default_left():
2012-03-30 13:05:54 +02:00
return 0
2012-09-24 22:18:28 +02:00
@staticmethod
def default_right():
2012-03-30 13:05:54 +02:00
return 0
2012-09-24 22:18:28 +02:00
@staticmethod
def default_timesheet_available():
2009-05-22 19:11:29 +02:00
return True
2008-06-02 17:18:11 +02:00
2012-09-24 22:18:28 +02:00
@staticmethod
def default_company():
2012-03-27 10:44:13 +02:00
return Transaction().context.get('company')
2008-06-09 19:17:07 +02:00
@classmethod
def validate(cls, works):
super(Work, cls).validate(works)
cls.check_recursion(works, rec_name='name')
for work in works:
work.check_parent_company()
2012-09-24 22:18:28 +02:00
def check_parent_company(self):
if not self.parent:
return
if self.parent.company != self.company:
self.raise_user_error('invalid_parent_company', {
'child': self.rec_name,
'parent': self.parent.rec_name,
})
2009-05-22 19:11:29 +02:00
2012-09-24 22:18:28 +02:00
@classmethod
def get_hours(cls, works, name):
2013-08-21 18:40:44 +02:00
pool = Pool()
Line = pool.get('timesheet.line')
transaction = Transaction()
cursor = transaction.cursor
in_max = cursor.IN_MAX
context = transaction.context
2013-09-06 22:35:00 +02:00
table_w = cls.__table__()
table_c = cls.__table__()
line = Line.__table__()
2012-09-24 22:18:28 +02:00
ids = [w.id for w in works]
2013-08-21 18:40:44 +02:00
hours = dict.fromkeys(ids, 0)
2013-09-06 22:35:00 +02:00
where = Literal(True)
2013-08-21 18:40:44 +02:00
if context.get('from_date'):
2013-09-06 22:35:00 +02:00
where &= line.date >= context['from_date']
2013-08-21 18:40:44 +02:00
if context.get('to_date'):
2013-09-06 22:35:00 +02:00
where &= line.date <= context['to_date']
2013-09-20 17:32:34 +02:00
if context.get('employees'):
where &= line.employee.in_(context['employees'])
2013-08-21 18:40:44 +02:00
for i in range(0, len(ids), in_max):
sub_ids = ids[i:i + in_max]
2013-09-06 22:35:00 +02:00
red_sql = reduce_ids(table_w.id, sub_ids)
cursor.execute(*table_w.join(table_c,
condition=(table_c.left >= table_w.left)
& (table_c.right <= table_w.right)
).join(line, 'LEFT', condition=line.work == table_c.id
).select(table_w.id, Sum(line.hours),
where=red_sql & where,
group_by=table_w.id))
2013-08-21 18:40:44 +02:00
hours.update(dict(cursor.fetchall()))
return hours
2008-06-03 01:57:48 +02:00
2012-09-24 22:18:28 +02:00
def get_rec_name(self, name):
if self.parent:
return self.parent.get_rec_name(name) + '\\' + self.name
else:
return self.name
2012-04-03 20:07:54 +02:00
2013-04-06 12:29:12 +02:00
@classmethod
def search_rec_name(cls, name, clause):
if isinstance(clause[2], basestring):
values = clause[2].split('\\')
values.reverse()
domain = []
field = 'name'
for name in values:
domain.append((field, clause[1], name.strip()))
field = 'parent.' + field
else:
domain = [('name',) + tuple(clause[1:])]
ids = [w.id for w in cls.search(domain, order=[])]
return [('parent', 'child_of', ids)]
2012-09-24 22:18:28 +02:00
@classmethod
def copy(cls, works, default=None):
if default is None:
default = {}
default = default.copy()
if 'timesheet_lines' not in default:
2012-03-27 10:44:13 +02:00
default['timesheet_lines'] = None
2012-09-24 22:18:28 +02:00
return super(Work, cls).copy(works, default=default)
2012-09-24 22:18:28 +02:00
@classmethod
def write(cls, works, vals):
pool = Pool()
Lines = pool.get('timesheet.line')
2012-09-24 22:18:28 +02:00
childs = None
if not vals.get('timesheet_available', True):
in_max = Transaction().cursor.IN_MAX
for i in range(0, len(works), in_max):
sub_ids = [w.id for w in works[i:i + in_max]]
lines = Lines.search([('work', 'in', sub_ids)], limit=1)
if lines:
cls.raise_user_error('change_timesheet_available',
lines[0].work.rec_name)
2008-06-02 17:18:11 +02:00
if not vals.get('active', True):
2012-09-24 22:18:28 +02:00
childs = cls.search([
('parent', 'child_of', [w.id for w in works]),
])
super(Work, cls).write(works, vals)
if childs:
cls.write(childs, {
'active': False,
})
2008-06-03 01:57:48 +02:00
2012-01-02 18:10:18 +01:00
class OpenWorkStart(ModelView):
'Open Work'
2012-09-24 22:18:28 +02:00
__name__ = 'timesheet.work.open.start'
2008-06-03 01:57:48 +02:00
from_date = fields.Date('From Date')
to_date = fields.Date('To Date')
2012-01-02 18:10:18 +01:00
2008-06-03 01:57:48 +02:00
2008-06-09 16:54:33 +02:00
class OpenWork(Wizard):
'Open Work'
2012-09-24 22:18:28 +02:00
__name__ = 'timesheet.work.open'
2012-01-02 18:10:18 +01:00
start = StateView('timesheet.work.open.start',
'timesheet.work_open_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Open', 'open_', 'tryton-ok', default=True),
])
open_ = StateAction('timesheet.act_work_hours_board')
2012-09-24 22:18:28 +02:00
def do_open_(self, action):
2012-01-02 18:10:18 +01:00
action['pyson_context'] = PYSONEncoder().encode({
2012-09-24 22:18:28 +02:00
'from_date': self.start.from_date,
'to_date': self.start.to_date,
2012-01-02 18:10:18 +01:00
})
return action, {}
2012-09-24 22:18:28 +02:00
def transition_open_(self):
2012-01-02 18:10:18 +01:00
return 'end'
2008-06-03 01:57:48 +02:00
2008-06-09 16:54:33 +02:00
class OpenWork2(OpenWork):
2012-09-24 22:18:28 +02:00
__name__ = 'timesheet.work.open2'
2012-01-02 18:10:18 +01:00
open_ = StateAction('timesheet.act_work_form2')
2008-06-09 16:54:33 +02:00
class OpenWorkGraph(Wizard):
2012-09-24 22:18:28 +02:00
__name__ = 'timesheet.work.open_graph'
2012-01-02 18:10:18 +01:00
start_state = 'open_'
open_ = StateAction('timesheet.act_work_form3')
2012-09-24 22:18:28 +02:00
def do_open_(self, action):
Work = Pool().get('timesheet.work')
2010-08-10 11:59:04 -04:00
if 'active_id' in Transaction().context:
2012-09-24 22:18:28 +02:00
work = Work(Transaction().context['active_id'])
2012-01-02 18:10:18 +01:00
action['name'] = action['name'] + ' - ' + work.rec_name
return action, {}