diff options
| author | Priyanka Kakadiya <pka@odoo.com> | 2019-05-10 11:09:54 +0000 |
|---|---|---|
| committer | Priyanka Kakadiya <pka@odoo.com> | 2019-06-14 04:49:21 +0000 |
| commit | d74ee9a0cf6d72d5433bd213050c9b2846de0ea7 (patch) | |
| tree | 266d79c27eeff46c4500715e1dd9a524aef2a9e6 /addons/hr_timesheet | |
| parent | 562997b2bc0b55f92177952fff3160c762b3e6bb (diff) | |
[IMP] hr_timesheet: added a timesheet for portal user
Purpose of the commit is to add a timesheet section on portal
where you can see all the timesheets and user can see and use the filter
options on them (available when only hr_timesheet is installed)
task-1932488
Diffstat (limited to 'addons/hr_timesheet')
| -rw-r--r-- | addons/hr_timesheet/__init__.py | 1 | ||||
| -rw-r--r-- | addons/hr_timesheet/__manifest__.py | 1 | ||||
| -rw-r--r-- | addons/hr_timesheet/controllers/__init__.py | 5 | ||||
| -rw-r--r-- | addons/hr_timesheet/controllers/portal.py | 106 | ||||
| -rw-r--r-- | addons/hr_timesheet/controllers/project.py | 18 | ||||
| -rw-r--r-- | addons/hr_timesheet/models/hr_timesheet.py | 8 | ||||
| -rw-r--r-- | addons/hr_timesheet/views/hr_timesheet_portal_templates.xml | 64 | ||||
| -rw-r--r-- | addons/hr_timesheet/views/project_portal_templates.xml | 38 |
8 files changed, 224 insertions, 17 deletions
diff --git a/addons/hr_timesheet/__init__.py b/addons/hr_timesheet/__init__.py index 2609681a938..5905766d867 100644 --- a/addons/hr_timesheet/__init__.py +++ b/addons/hr_timesheet/__init__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import controllers from . import models from . import report diff --git a/addons/hr_timesheet/__manifest__.py b/addons/hr_timesheet/__manifest__.py index 22af4117533..d80c3769250 100644 --- a/addons/hr_timesheet/__manifest__.py +++ b/addons/hr_timesheet/__manifest__.py @@ -29,6 +29,7 @@ up a management by affair. 'views/res_config_settings_views.xml', 'views/project_views.xml', 'views/project_portal_templates.xml', + 'views/hr_timesheet_portal_templates.xml', 'report/hr_timesheet_report_view.xml', 'report/report_timesheet_templates.xml', 'views/hr_views.xml', diff --git a/addons/hr_timesheet/controllers/__init__.py b/addons/hr_timesheet/controllers/__init__.py new file mode 100644 index 00000000000..86c009b5649 --- /dev/null +++ b/addons/hr_timesheet/controllers/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import portal +from . import project diff --git a/addons/hr_timesheet/controllers/portal.py b/addons/hr_timesheet/controllers/portal.py new file mode 100644 index 00000000000..9fd6ac942fc --- /dev/null +++ b/addons/hr_timesheet/controllers/portal.py @@ -0,0 +1,106 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from collections import OrderedDict +from dateutil.relativedelta import relativedelta +from operator import itemgetter + +from odoo import fields, http, _ +from odoo.http import request +from odoo.tools import date_utils, groupby as groupbyelem +from odoo.osv.expression import AND + +from odoo.addons.portal.controllers.portal import CustomerPortal, pager as portal_pager + + +class TimesheetCustomerPortal(CustomerPortal): + + def _prepare_portal_layout_values(self): + values = super(TimesheetCustomerPortal, self)._prepare_portal_layout_values() + domain = request.env['account.analytic.line']._timesheet_get_portal_domain() + values['timesheet_count'] = request.env['account.analytic.line'].sudo().search_count(domain) + return values + + @http.route(['/my/timesheets', '/my/timesheets/page/<int:page>'], type='http', auth="user", website=True) + def portal_my_timesheets(self, page=1, sortby=None, filterby=None, search=None, search_in='all', groupby='project', **kw): + Timesheet_sudo = request.env['account.analytic.line'].sudo() + values = self._prepare_portal_layout_values() + domain = request.env['account.analytic.line']._timesheet_get_portal_domain() + + searchbar_sortings = { + 'date': {'label': _('Newest'), 'order': 'date desc'}, + 'name': {'label': _('Name'), 'order': 'name'}, + } + + searchbar_inputs = { + 'all': {'input': 'all', 'label': _('Search in All')}, + } + + searchbar_groupby = { + 'none': {'input': 'none', 'label': _('None')}, + 'project': {'input': 'project', 'label': _('Project')}, + } + + today = fields.Date.today() + quarter_start, quarter_end = date_utils.get_quarter(today) + last_week = today + relativedelta(weeks=-1) + last_month = today + relativedelta(months=-1) + last_year = today + relativedelta(years=-1) + + searchbar_filters = { + 'all': {'label': _('All'), 'domain': []}, + 'today': {'label': _('Today'), 'domain': [("date", "=", today)]}, + 'week': {'label': _('This week'), 'domain': [('date', '>=', date_utils.start_of(today, "week")), ('date', '<=', date_utils.end_of(today, 'week'))]}, + 'month': {'label': _('This month'), 'domain': [('date', '>=', date_utils.start_of(today, 'month')), ('date', '<=', date_utils.end_of(today, 'month'))]}, + 'year': {'label': _('This year'), 'domain': [('date', '>=', date_utils.start_of(today, 'year')), ('date', '<=', date_utils.end_of(today, 'year'))]}, + 'quarter': {'label': _('This Quarter'), 'domain': [('date', '>=', quarter_start), ('date', '<=', quarter_end)]}, + 'last_week': {'label': _('Last week'), 'domain': [('date', '>=', date_utils.start_of(last_week, "week")), ('date', '<=', date_utils.end_of(last_week, 'week'))]}, + 'last_month': {'label': _('Last month'), 'domain': [('date', '>=', date_utils.start_of(last_month, 'month')), ('date', '<=', date_utils.end_of(last_month, 'month'))]}, + 'last_year': {'label': _('Last year'), 'domain': [('date', '>=', date_utils.start_of(last_year, 'year')), ('date', '<=', date_utils.end_of(last_year, 'year'))]}, + } + # default sort by value + if not sortby: + sortby = 'date' + order = searchbar_sortings[sortby]['order'] + # default filter by value + if not filterby: + filterby = 'all' + domain = AND([domain, searchbar_filters[filterby]['domain']]) + + if search and search_in: + domain = AND([domain, [('name', 'ilike', search)]]) + + timesheet_count = Timesheet_sudo.search_count(domain) + # pager + pager = portal_pager( + url="/my/timesheets", + url_args={'sortby': sortby, 'search_in': search_in, 'search': search, 'filterby': filterby}, + total=timesheet_count, + page=page, + step=self._items_per_page + ) + + if groupby == 'project': + order = "project_id, %s" % order + timesheets = Timesheet_sudo.search(domain, order=order, limit=self._items_per_page, offset=pager['offset']) + if groupby == 'project': + grouped_timesheets = [Timesheet_sudo.concat(*g) for k, g in groupbyelem(timesheets, itemgetter('project_id'))] + else: + grouped_timesheets = [timesheets] + + values.update({ + 'timesheets': timesheets, + 'grouped_timesheets': grouped_timesheets, + 'page_name': 'timesheet', + 'default_url': '/my/timesheets', + 'pager': pager, + 'searchbar_sortings': searchbar_sortings, + 'search_in': search_in, + 'sortby': sortby, + 'groupby': groupby, + 'searchbar_inputs': searchbar_inputs, + 'searchbar_groupby': searchbar_groupby, + 'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())), + 'filterby': filterby, + }) + return request.render("hr_timesheet.portal_my_timesheets", values) diff --git a/addons/hr_timesheet/controllers/project.py b/addons/hr_timesheet/controllers/project.py new file mode 100644 index 00000000000..bc321ab98fa --- /dev/null +++ b/addons/hr_timesheet/controllers/project.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.http import request +from odoo.osv import expression + +from odoo.addons.project.controllers.portal import CustomerPortal + + +class ProjectCustomerPortal(CustomerPortal): + + def _task_get_page_view_values(self, task, access_token, **kwargs): + values = super(ProjectCustomerPortal, self)._task_get_page_view_values(task, access_token, **kwargs) + domain = request.env['account.analytic.line']._timesheet_get_portal_domain() + domain = expression.AND([domain, [('task_id', '=', task.id)]]) + timesheets = request.env['account.analytic.line'].sudo().search(domain) + values['timesheets'] = timesheets + return values diff --git a/addons/hr_timesheet/models/hr_timesheet.py b/addons/hr_timesheet/models/hr_timesheet.py index ce2abd5f871..200b4a0a84e 100644 --- a/addons/hr_timesheet/models/hr_timesheet.py +++ b/addons/hr_timesheet/models/hr_timesheet.py @@ -102,6 +102,14 @@ class AccountAnalyticLine(models.Model): # Business Methods # ---------------------------------------------------- + def _timesheet_get_portal_domain(self): + return ['|', '&', + ('task_id.project_id.privacy_visibility', '=', 'portal'), + ('task_id.project_id.message_partner_ids', 'child_of', [self.env.user.partner_id.commercial_partner_id.id]), + '&', + ('task_id.project_id.privacy_visibility', '=', 'portal'), + ('task_id.message_partner_ids', 'child_of', [self.env.user.partner_id.commercial_partner_id.id])] + def _timesheet_preprocess(self, vals): """ Deduce other field values from the one given. Overrride this to compute on the fly some field that can not be computed fields. diff --git a/addons/hr_timesheet/views/hr_timesheet_portal_templates.xml b/addons/hr_timesheet/views/hr_timesheet_portal_templates.xml new file mode 100644 index 00000000000..939c306767f --- /dev/null +++ b/addons/hr_timesheet/views/hr_timesheet_portal_templates.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo> + + <template id="portal_layout" name="Portal layout: timesheet menu entry" inherit_id="portal.portal_breadcrumbs" priority="35"> + <xpath expr="//ol[hasclass('o_portal_submenu')]" position="inside"> + <li t-if="page_name == 'timesheet' or timesheet" t-attf-class="breadcrumb-item #{'active' if not timesheet else ''}"> + <t>Timesheets</t> + </li> + </xpath> + </template> + + <template id="portal_my_home_timesheet" name="Portal My Home : timesheets entries" inherit_id="portal.portal_my_home" priority="45"> + <xpath expr="//div[hasclass('o_portal_docs')]" position="inside"> + <t t-if="timesheet_count" t-call="portal.portal_docs_entry"> + <t t-set="title">Timesheets</t> + <t t-set="url" t-value="'/my/timesheets'"/> + <t t-set="count" t-value="timesheet_count"/> + </t> + </xpath> + </template> + + <template id="portal_my_timesheets" name="My Timesheets"> + <t t-call="portal.portal_layout"> + <t t-set="breadcrumbs_searchbar" t-value="True"/> + + <t t-call="portal.portal_searchbar"> + <t t-set="title">Timesheets</t> + </t> + <t t-if="not grouped_timesheets"> + <div class="alert alert-warning mt8" role="alert"> + There are no timesheets. + </div> + </t> + <t t-if="grouped_timesheets"> + <t t-call="portal.portal_table"> + <t t-foreach="grouped_timesheets" t-as="timesheets"> + <thead> + <tr t-attf-class="{{'thead-light' if not groupby == 'none' else ''}}"> + <th t-if="groupby == 'none'">Description</th> + <th t-else=""> + <em class="font-weight-normal text-muted">Timesheets for project:</em> + <span t-field="timesheets[0].project_id.name"/></th> + <th>Date</th> + <th>Employee</th> + <th class="text-right">Duration</th> + </tr> + </thead> + <tbody> + <t t-foreach="timesheets" t-as="timesheet"> + <tr> + <td><span t-esc="timesheet.name"/></td> + <td><span t-field="timesheet.date" t-options='{"widget": "date"}'/></td> + <td><span t-field="timesheet.employee_id"/></td> + <td class="text-right"><span t-field="timesheet.unit_amount" t-options='{"widget": "duration", "unit": "hour", "round": "minute"}'/></td> + </tr> + </t> + </tbody> + </t> + </t> + </t> + </t> + </template> + +</odoo> diff --git a/addons/hr_timesheet/views/project_portal_templates.xml b/addons/hr_timesheet/views/project_portal_templates.xml index 27f68907def..8a3e6ff2ad0 100644 --- a/addons/hr_timesheet/views/project_portal_templates.xml +++ b/addons/hr_timesheet/views/project_portal_templates.xml @@ -3,27 +3,31 @@ <template id="portal_my_task" inherit_id="project.portal_my_task" name="Portal: My Task with Timesheets"> <xpath expr="//t[@t-set='card_body']" position="inside"> - <div class="container" t-if="task.timesheet_ids"> + <div class="container" t-if="timesheets"> <hr class="mt-4 mb-1"/> <h5 class="mt-2 mb-2">Timesheets</h5> - <table class="table table-sm"> - <thead> - <tr> - <th>Date</th> - <th>Description</th> - <th>Responsible</th> - <th class="text-right">Duration</th> - </tr> - </thead> - <tr t-foreach="task.timesheet_ids" t-as="timesheet"> - <td><t t-esc="timesheet.date"/></td> - <td><t t-esc="timesheet.name"/></td> - <td><t t-esc="timesheet.sudo().user_id.name"/></td> - <td class="text-right"><span t-field="timesheet.unit_amount" t-options='{"widget": "duration", "unit": "hour", "round": "minute"}'/></td> - </tr> - </table> + <t t-call="hr_timesheet.portal_timesheet_table"/> </div> </xpath> </template> + <template id="portal_timesheet_table" name="Portal Timesheet Table"> + <table class="table table-sm"> + <thead> + <tr> + <th>Date</th> + <th>Description</th> + <th>Employee</th> + <th class="text-right">Duration</th> + </tr> + </thead> + <tr t-foreach="timesheets" t-as="timesheet"> + <td><t t-esc="timesheet.date" t-options='{"widget": "date"}'/></td> + <td><t t-esc="timesheet.name"/></td> + <td><t t-esc="timesheet.employee_id.name"/></td> + <td class="text-right"><span t-field="timesheet.unit_amount" t-options='{"widget": "duration", "unit": "hour", "round": "minute"}'/></td> + </tr> + </table> + </template> + </odoo> |
