diff --git a/INSTALL b/INSTALL
index e8cb52c14c..0b5f2eb6ee 100644
--- a/INSTALL
+++ b/INSTALL
@@ -5,6 +5,7 @@ Prerequisites
-------------
* Python 2.6 or later (http://www.python.org/)
+ * python-sql (http://code.google.com/p/python-sql/)
* trytond (http://www.tryton.org/)
* trytond_company (http://www.tryton.org/)
* trytond_company_work_time (http://www.tryton.org/)
diff --git a/line.py b/line.py
index 541b01689a..9ef785dc99 100644
--- a/line.py
+++ b/line.py
@@ -1,8 +1,12 @@
#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 sql import Literal
+from sql.aggregate import Max, Sum
+from sql.conditionals import Coalesce
+from sql.functions import Extract
+
from trytond.model import ModelView, ModelSQL, fields
from trytond.wizard import Wizard, StateView, StateAction, Button
-from trytond.backend import FIELDS
from trytond.pyson import Eval, PYSONEncoder, Date, Get
from trytond.transaction import Transaction
from trytond.pool import Pool
@@ -126,25 +130,24 @@ class HoursEmployee(ModelSQL, ModelView):
@staticmethod
def table_query():
- clause = ' '
- args = [True]
+ pool = Pool()
+ Line = pool.get('timesheet.line')
+ line = Line.__table__()
+ where = Literal(True)
if Transaction().context.get('start_date'):
- clause += 'AND date >= %s '
- args.append(Transaction().context['start_date'])
+ where &= line.date >= Transaction().context['start_date']
if Transaction().context.get('end_date'):
- clause += 'AND date <= %s '
- args.append(Transaction().context['end_date'])
- return ('SELECT DISTINCT(employee) AS id, '
- 'MAX(create_uid) AS create_uid, '
- 'MAX(create_date) AS create_date, '
- 'MAX(write_uid) AS write_uid, '
- 'MAX(write_date) AS write_date, '
- 'employee, '
- 'SUM(COALESCE(hours, 0)) AS hours '
- 'FROM timesheet_line '
- 'WHERE %s '
- + clause +
- 'GROUP BY employee', args)
+ where &= line.date <= Transaction().context['end_date']
+ return line.select(
+ line.employee.as_('id'),
+ Max(line.create_uid).as_('create_uid'),
+ Max(line.create_date).as_('create_date'),
+ Max(line.write_uid).as_('write_uid'),
+ Max(line.write_date).as_('write_date'),
+ line.employee,
+ Sum(Coalesce(line.hours, 0)).as_('hours'),
+ where=where,
+ group_by=line.employee)
class OpenHoursEmployeeStart(ModelView):
@@ -192,23 +195,25 @@ class HoursEmployeeWeekly(ModelSQL, ModelView):
@classmethod
def table_query(cls):
- type_name = FIELDS[cls.year._type].sql_type(cls.year)[0]
- return ('SELECT id, create_uid, create_date, write_uid, write_date, '
- 'CAST(year AS ' + type_name + ') AS year, week, '
- 'employee, hours '
- 'FROM ('
- 'SELECT EXTRACT(WEEK FROM date) + '
- 'EXTRACT(YEAR FROM date) * 100 + '
- 'employee * 1000000 AS id, '
- 'MAX(create_uid) AS create_uid, '
- 'MAX(create_date) AS create_date, '
- 'MAX(write_uid) AS write_uid, '
- 'MAX(write_date) AS write_date, '
- 'EXTRACT(YEAR FROM date) AS year, '
- 'EXTRACT(WEEK FROM date) AS week, employee, '
- 'SUM(COALESCE(hours, 0)) AS hours '
- 'FROM timesheet_line '
- 'GROUP BY year, week, employee) AS ' + cls._table, [])
+ pool = Pool()
+ Line = pool.get('timesheet.line')
+ line = Line.__table__()
+ type_name = cls.year.sql_type().base
+ year_column = Extract('YEAR', line.date).cast(type_name).as_('year')
+ week_column = Extract('WEEK', line.date).as_('week')
+ return line.select(
+ Max(Extract('WEEK', line.date)
+ + Extract('YEAR', line.date) * 100
+ + line.employee * 1000000).as_('id'),
+ Max(line.create_uid).as_('create_uid'),
+ Max(line.create_date).as_('create_date'),
+ Max(line.write_uid).as_('write_uid'),
+ Max(line.write_date).as_('write_date'),
+ year_column,
+ week_column,
+ line.employee,
+ Sum(Coalesce(line.hours, 0)).as_('hours'),
+ group_by=(year_column, week_column, line.employee))
class HoursEmployeeMonthly(ModelSQL, ModelView):
@@ -228,20 +233,22 @@ class HoursEmployeeMonthly(ModelSQL, ModelView):
@classmethod
def table_query(cls):
- type_name = FIELDS[cls.year._type].sql_type(cls.year)[0]
- return ('SELECT id, create_uid, create_date, write_uid, write_date, '
- 'CAST(year AS ' + type_name + ') AS year, month, '
- 'employee, hours '
- 'FROM ('
- 'SELECT EXTRACT(MONTH FROM date) + '
- 'EXTRACT(YEAR FROM date) * 100 + '
- 'employee * 1000000 AS id, '
- 'MAX(create_uid) AS create_uid, '
- 'MAX(create_date) AS create_date, '
- 'MAX(write_uid) AS write_uid, '
- 'MAX(write_date) AS write_date, '
- 'EXTRACT(YEAR FROM date) AS year, '
- 'EXTRACT(MONTH FROM date) AS month, employee, '
- 'SUM(COALESCE(hours, 0)) AS hours '
- 'FROM timesheet_line '
- 'GROUP BY year, month, employee) AS ' + cls._table, [])
+ pool = Pool()
+ Line = pool.get('timesheet.line')
+ line = Line.__table__()
+ type_name = cls.year.sql_type().base
+ year_column = Extract('YEAR', line.date).cast(type_name).as_('year')
+ month_column = Extract('MONTH', line.date).as_('month')
+ return line.select(
+ Max(Extract('MONTH', line.date)
+ + Extract('YEAR', line.date) * 100
+ + line.employee * 1000000).as_('id'),
+ Max(line.create_uid).as_('create_uid'),
+ Max(line.create_date).as_('create_date'),
+ Max(line.write_uid).as_('write_uid'),
+ Max(line.write_date).as_('write_date'),
+ year_column,
+ month_column,
+ line.employee,
+ Sum(Coalesce(line.hours, 0)).as_('hours'),
+ group_by=(year_column, month_column, line.employee))
diff --git a/setup.py b/setup.py
index 2f7404667f..21a820d99b 100644
--- a/setup.py
+++ b/setup.py
@@ -21,7 +21,7 @@ major_version, minor_version, _ = info.get('version', '0.0.1').split('.', 2)
major_version = int(major_version)
minor_version = int(minor_version)
-requires = []
+requires = ['python-sql']
for dep in info.get('depends', []):
if not re.match(r'(ir|res|webdav)(\W|$)', dep):
requires.append('trytond_%s >= %s.%s, < %s.%s' %
diff --git a/work.py b/work.py
index e972f4727a..2f78ecaf52 100644
--- a/work.py
+++ b/work.py
@@ -1,5 +1,8 @@
#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 sql import Literal
+from sql.aggregate import Sum
+
from trytond.model import ModelView, ModelSQL, fields
from trytond.wizard import Wizard, StateView, StateAction, Button
from trytond.pyson import PYSONEncoder, Not, Bool, Eval
@@ -105,27 +108,26 @@ class Work(ModelSQL, ModelView):
in_max = cursor.IN_MAX
context = transaction.context
+ table_w = cls.__table__()
+ table_c = cls.__table__()
+ line = Line.__table__()
ids = [w.id for w in works]
hours = dict.fromkeys(ids, 0)
- date_cond = ''
- date_args = []
+ where = Literal(True)
if context.get('from_date'):
- date_cond = ' AND date >= %s'
- date_args.append(context['from_date'])
+ where &= line.date >= context['from_date']
if context.get('to_date'):
- date_cond += ' AND date <= %s'
- date_args.append(context['to_date'])
+ where &= line.date <= context['to_date']
for i in range(0, len(ids), in_max):
sub_ids = ids[i:i + in_max]
- red_sql, red_ids = reduce_ids('w.id', sub_ids)
- cursor.execute('SELECT w.id, SUM(l.hours) '
- 'FROM "' + cls._table + '" AS w '
- 'JOIN "' + cls._table + '" AS c '
- 'ON c.left >= w.left AND c.right <= w.right '
- 'LEFT JOIN "' + Line._table + '" AS l '
- 'ON l.work = c.id '
- 'WHERE ' + red_sql + ' ' + date_cond + ' '
- 'GROUP BY w.id', red_ids + date_args)
+ 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))
hours.update(dict(cursor.fetchall()))
return hours
diff --git a/work.xml b/work.xml
index 51a6a9993d..e3570470cd 100644
--- a/work.xml
+++ b/work.xml
@@ -25,7 +25,7 @@ this repository contains the full copyright notices and license terms. -->
Works
timesheet.work
- [('parent', '=', False)]
+ [('parent', '=', None)]
@@ -71,7 +71,7 @@ this repository contains the full copyright notices and license terms. -->
Works
timesheet.work
- [('parent', '=', False)]
+ [('parent', '=', None)]
@@ -88,7 +88,7 @@ this repository contains the full copyright notices and license terms. -->
Hours per Work
timesheet.work
- [('parent', '=', Get(Eval('timesheet.act_work_tree2', {}), 'id', False))]
+ [('parent', '=', Get(Eval('timesheet.act_work_tree2', {}), 'id', None))]