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))]