diff --git a/CHANGELOG b/CHANGELOG index 1827497a9b..26640420df 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Add user application API * Remove tree structure on Work * Add optional origin on Work diff --git a/__init__.py b/__init__.py index d1f95f6c16..0ba16a0fec 100644 --- a/__init__.py +++ b/__init__.py @@ -1,9 +1,13 @@ # 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 trytond.pool import Pool + from .work import * from .line import * +from .user import * +from . import routes + +__all__ = ['register', 'routes'] def register(): @@ -16,6 +20,7 @@ def register(): HoursEmployeeContext, HoursEmployeeWeekly, HoursEmployeeMonthly, + UserApplication, module='timesheet', type_='model') Pool.register( EnterLines, diff --git a/doc/index.rst b/doc/index.rst index 8fb819e513..9619e23fb1 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -25,3 +25,8 @@ A timesheet line express the fact that one employee spend a part of his/her time on a specific work at a given date. An optional Description field allow to give some extra informations about what have been done. + +.. toctree:: + :maxdepth: 1 + + user_application diff --git a/doc/user_application.rst b/doc/user_application.rst new file mode 100644 index 0000000000..d70f3ea62b --- /dev/null +++ b/doc/user_application.rst @@ -0,0 +1,28 @@ +Timesheet User Application +########################## + +The timesheet module defines some routes for user applications: + + - `GET` `//timesheet/employees`: + return the list of the user employees as dictionary with the keys: `id` + and `name`. + + - `GET` `//timesheet/employee//works`: + return the list of works available for the employee. The works are + dictionary with keys: `id`, `name`, `start` and `end`. The dates are in + the format `%Y-%m-%d`. + + - `GET` `//timesheet/employee//lines/`: + return the list of timesheet lines for the employee at the date + (`%Y-%m-%d'). The lines are dictionary with keys: `id`, `work`, + `work.name`, `duration` and `description`. The duration is in seconds. + + - `POST` `//timesheet/line`: + Create a line using the data as dictionary of value. The date must be in + the format `%Y-%m-%d` and the `duration` in seconds. + + - `PUT` `//timesheet/line/`: + Update the line using the data like for the `POST`. + + - `DELETE` `//timesheet/line/`: + Delete the line diff --git a/routes.py b/routes.py new file mode 100644 index 0000000000..98179ffab5 --- /dev/null +++ b/routes.py @@ -0,0 +1,119 @@ +# This file is part of Tryton. The COPYRIGHT file at the top level of +# this repository contains the full copyright notices and license terms. +import datetime + +from werkzeug.exceptions import abort, Response + +from trytond.transaction import Transaction +from trytond.wsgi import app +from trytond.protocols.wrappers import with_pool, with_transaction, \ + user_application + +timesheet_application = user_application('timesheet') + + +@app.route('//timesheet/employees', methods=['GET']) +@with_pool +@with_transaction() +@timesheet_application +def timesheet_employees(request, pool): + User = pool.get('res.user') + user = User(Transaction().user) + return [{'id': e.id, 'name': e.rec_name} for e in user.employees] + + +@app.route('//timesheet/employee//works', + methods=['GET']) +@with_pool +@with_transaction() +@timesheet_application +def timesheet_works(request, pool, employee): + Work = pool.get('timesheet.work') + Employee = pool.get('company.employee') + employee = Employee(employee) + with Transaction().set_context( + company=employee.company.id, employee=employee.id): + works = Work.search([]) + return [{ + 'id': w.id, + 'name': w.rec_name, + 'start': (w.timesheet_start_date.strftime('%Y-%m-%d') + if w.timesheet_start_date else None), + 'end': (w.timesheet_end_date.strftime('%Y-%m-%d') + if w.timesheet_end_date else None), + } for w in works] + + +@app.route('//timesheet/employee//lines/', + methods=['GET']) +@with_pool +@with_transaction() +@timesheet_application +def timesheet_lines(request, pool, employee, date): + User = pool.get('res.user') + Employee = pool.get('company.employee') + Line = pool.get('timesheet.line') + + employee = Employee(employee) + date = datetime.datetime.strptime(date, '%Y-%m-%d').date() + user = User(Transaction().user) + if employee not in user.employees: + abort(403) + + with Transaction().set_context( + company=employee.company.id, employee=employee.id): + lines = Line.search([ + ('employee', '=', employee.id), + ('date', '=', date), + ]) + return [{ + 'id': l.id, + 'work': l.work.id, + 'work.name': l.work.rec_name, + 'duration': l.duration.total_seconds(), + 'description': l.description, + } for l in lines] + + +@app.route('//timesheet/line/', + methods=['PUT', 'DELETE']) +@app.route('//timesheet/line', methods=['POST']) +@with_pool +@with_transaction() +@timesheet_application +def timesheet(request, pool, line=None): + Line = pool.get('timesheet.line') + User = pool.get('res.user') + Employee = pool.get('company.employee') + if request.method in {'POST', 'PUT'}: + data = request.parsed_data + if 'employee' in data: + employee = Employee(data['employee']) + data['company'] = employee.company.id + else: + employee = User(Transaction().user).employee + if 'date' in data: + data['date'] = datetime.datetime.strptime( + data['date'], '%Y-%m-%d').date() + if 'duration' in data: + data['duration'] = datetime.timedelta( + seconds=data['duration']) + with Transaction().set_context( + company=employee.company.id, employee=employee.id): + if not line: + line, = Line.create([request.parsed_data]) + else: + line = Line(line) + Line.write([line], request.parsed_data) + return { + 'id': line.id, + 'work': line.work.id, + 'work.name': line.work.rec_name, + 'duration': line.duration.total_seconds(), + 'description': line.description, + } + else: + with Transaction().set_context( + company=line.company.id, employee=line.employee.id): + Line.delete([line]) + return Response(None, 204) diff --git a/user.py b/user.py new file mode 100644 index 0000000000..d9c5fbc289 --- /dev/null +++ b/user.py @@ -0,0 +1,15 @@ +# 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 trytond.pool import PoolMeta + +__all__ = ['UserApplication'] + + +class UserApplication: + __metaclass__ = PoolMeta + __name__ = 'res.user.application' + + @classmethod + def __setup__(cls): + super(UserApplication, cls).__setup__() + cls.application.selection.append(('timesheet', 'Timesheet'))