summaryrefslogtreecommitdiff
path: root/addons/hr_timesheet
diff options
context:
space:
mode:
authorXavier BOL (xbo) <xbo@odoo.com>2020-12-10 18:34:47 +0100
committerXavier BOL (xbo) <xbo@odoo.com>2020-12-21 15:35:20 +0100
commita41df84a83380dded4cb8c9d83444f916b9e004d (patch)
tree72eb76af9b079497898b95eca1983d783f0bbe10 /addons/hr_timesheet
parentdaa1036eb6b54588224bc5d6fe9be6974cde1ea8 (diff)
[IMP] {hr,sale}_timesheet: review portal timesheets
This commit improves the portal view containing the timesheets list (this view is available in the '/my/timesheets' route. In sale_timesheet module, we * add new group by and a search on SOL, * add an SOL field on the left of the unit_amount one, * change the group by by default, to group the timesheets by SOL * display the following information in the group: 'x Hours ordered, x Remaining', when the timesheets are grouped by SOL. However, the 'x Remaining' part should only be visible if the number of timesheets is greater than 0. * move the total number of hours in the group itself and align it to the right. * change the number of items displayed per page, 100 items instead of 20. * reduce the size of the font in tbody tag (0.8rem instead of 0.875rem) * display the content of the field on hover, it's usefull when the field it's cropped. * Add 'View Timesheets' button in portal SO: this new button button called 'View timesheets' is displayed next the name of the product of a SO in Sale Order Portal. it is only visible if the number of timehseets is greater than 0 for this SOL. The button redirects the user to /my/timesheets page with a filter on the corresponding SOL + a group by SOL. task-2409761
Diffstat (limited to 'addons/hr_timesheet')
-rw-r--r--addons/hr_timesheet/controllers/portal.py79
-rw-r--r--addons/hr_timesheet/views/hr_timesheet_portal_templates.xml100
2 files changed, 121 insertions, 58 deletions
diff --git a/addons/hr_timesheet/controllers/portal.py b/addons/hr_timesheet/controllers/portal.py
index 8127b83be6f..b244ee3e656 100644
--- a/addons/hr_timesheet/controllers/portal.py
+++ b/addons/hr_timesheet/controllers/portal.py
@@ -23,32 +23,59 @@ class TimesheetCustomerPortal(CustomerPortal):
values['timesheet_count'] = request.env['account.analytic.line'].sudo().search_count(domain)
return values
+ def _get_searchbar_inputs(self):
+ return {
+ 'all': {'input': 'all', 'label': _('Search in All')},
+ 'project': {'input': 'project', 'label': _('Search in Project')},
+ 'name': {'input': 'name', 'label': _('Search in Description')},
+ 'employee': {'input': 'employee', 'label': _('Search in Employee')},
+ 'task': {'input': 'task', 'label': _('Search in Task')}
+ }
+
+ def _get_searchbar_groupby(self):
+ return {
+ 'none': {'input': 'none', 'label': _('None')},
+ 'project': {'input': 'project', 'label': _('Project')},
+ 'task': {'input': 'task', 'label': _('Task')},
+ 'date': {'input': 'date', 'label': _('Date')},
+ 'employee': {'input': 'employee', 'label': _('Employee')}
+ }
+
+ def _get_search_domain(self, search_in, search):
+ search_domain = []
+ if search_in in ('project', 'all'):
+ search_domain = OR([search_domain, [('project_id', 'ilike', search)]])
+ if search_in in ('name', 'all'):
+ search_domain = OR([search_domain, [('name', 'ilike', search)]])
+ if search_in in ('employee', 'all'):
+ search_domain = OR([search_domain, [('employee_id', 'ilike', search)]])
+ if search_in in ('task', 'all'):
+ search_domain = OR([search_domain, [('task_id', 'ilike', search)]])
+ return search_domain
+
+ def _get_groupby_mapping(self):
+ return {
+ 'project': 'project_id',
+ 'task': 'task_id',
+ 'employee': 'employee_id',
+ 'date': 'date'
+ }
+
@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='none', **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()
+ _items_per_page = 100
searchbar_sortings = {
'date': {'label': _('Newest'), 'order': 'date desc'},
'name': {'label': _('Description'), 'order': 'name'},
}
- searchbar_inputs = {
- 'all': {'input': 'all', 'label': _('Search in All')},
- 'project': {'input': 'project', 'label': _('Search in Project')},
- 'name': {'input': 'name', 'label': _('Search in Description')},
- 'employee': {'input': 'employee', 'label': _('Search in Employee')},
- 'task': {'input': 'task', 'label': _('Search in Task')},
- }
+ searchbar_inputs = self._get_searchbar_inputs()
- searchbar_groupby = {
- 'none': {'input': 'none', 'label': _('None')},
- 'project': {'input': 'project', 'label': _('Project')},
- 'task': {'input': 'task', 'label': _('Task')},
- 'date': {'input': 'date', 'label': _('Date')},
- 'employee': {'input': 'employee', 'label': _('Employee')},
- }
+ searchbar_groupby = self._get_searchbar_groupby()
today = fields.Date.today()
quarter_start, quarter_end = date_utils.get_quarter(today)
@@ -77,16 +104,7 @@ class TimesheetCustomerPortal(CustomerPortal):
domain = AND([domain, searchbar_filters[filterby]['domain']])
if search and search_in:
- search_domain = []
- if search_in in ('project', 'all'):
- search_domain = OR([search_domain, [('project_id', 'ilike', search)]])
- if search_in in ('name', 'all'):
- search_domain = OR([search_domain, [('name', 'ilike', search)]])
- if search_in in ('employee', 'all'):
- search_domain = OR([search_domain, [('employee_id', 'ilike', search)]])
- if search_in in ('task', 'all'):
- search_domain = OR([search_domain, [('task_id', 'ilike', search)]])
- domain += search_domain
+ domain += self._get_search_domain(search_in, search)
timesheet_count = Timesheet_sudo.search_count(domain)
# pager
@@ -95,19 +113,14 @@ class TimesheetCustomerPortal(CustomerPortal):
url_args={'sortby': sortby, 'search_in': search_in, 'search': search, 'filterby': filterby, 'groupby': groupby},
total=timesheet_count,
page=page,
- step=self._items_per_page
+ step=_items_per_page
)
def get_timesheets():
- groupby_mapping = {
- 'project': 'project_id',
- 'task': 'task_id',
- 'employee': 'employee_id',
- 'date': 'date',
- }
+ groupby_mapping = self._get_groupby_mapping()
field = groupby_mapping.get(groupby, None)
orderby = '%s, %s' % (field, order) if field else order
- timesheets = Timesheet_sudo.search(domain, order=orderby, limit=self._items_per_page, offset=pager['offset'])
+ timesheets = Timesheet_sudo.search(domain, order=orderby, limit=_items_per_page, offset=pager['offset'])
if field:
if groupby == 'date':
time_data = Timesheet_sudo.read_group(domain, ['date', 'unit_amount:sum'], ['date:day'])
@@ -115,7 +128,7 @@ class TimesheetCustomerPortal(CustomerPortal):
grouped_timesheets = [(Timesheet_sudo.concat(*g), mapped_time[k]) for k, g in groupbyelem(timesheets, itemgetter('date'))]
else:
time_data = time_data = Timesheet_sudo.read_group(domain, [field, 'unit_amount:sum'], [field])
- mapped_time = dict([(m[field][0], m['unit_amount']) for m in time_data])
+ mapped_time = dict([(m[field][0] if m[field] else False, m['unit_amount']) for m in time_data])
grouped_timesheets = [(Timesheet_sudo.concat(*g), mapped_time[k.id]) for k, g in groupbyelem(timesheets, itemgetter(field))]
return timesheets, grouped_timesheets
diff --git a/addons/hr_timesheet/views/hr_timesheet_portal_templates.xml b/addons/hr_timesheet/views/hr_timesheet_portal_templates.xml
index 90f2d679928..4385bbddd6a 100644
--- a/addons/hr_timesheet/views/hr_timesheet_portal_templates.xml
+++ b/addons/hr_timesheet/views/hr_timesheet_portal_templates.xml
@@ -36,24 +36,74 @@
<t t-foreach="grouped_timesheets" t-as="timesheets_with_hours">
<t t-set="timesheets" t-value="timesheets_with_hours[0]"/>
<t t-set="hours_spent" t-value="timesheets_with_hours[1]"/>
- <thead>
+ <thead style="font-size: 0.8rem">
<tr t-if="not groupby =='none'" t-attf-class="{{'thead-light'}}">
- <th t-if="groupby == 'project'" colspan="5">
- <em class="font-weight-normal text-muted">Timesheets for project:</em>
- <span t-field="timesheets[0].project_id.name"/>
- </th>
- <th t-elif="groupby == 'task'" colspan="5">
- <em class="font-weight-normal text-muted">Timesheets for task:</em>
- <span t-field="timesheets[0].task_id.name"/>
- </th>
- <th t-elif="groupby == 'date'" colspan="5">
- <em class="font-weight-normal text-muted">Timesheets on </em>
- <span t-field="timesheets[0].date"/>
- </th>
- <th t-elif="groupby == 'employee'" colspan="5">
- <em class="font-weight-normal text-muted">Timesheets for employee:</em>
- <span t-field="timesheets[0].employee_id.name"/>
- </th>
+ <t t-if="groupby == 'project'">
+ <th t-if="groupby == 'project'" colspan="5">
+ <em class="font-weight-normal text-muted">Timesheets for project:</em>
+ <span t-field="timesheets[0].project_id.name"/>
+ </th>
+ <th colspan="1" class="text-right text-muted">
+ <t t-if="is_uom_day">
+ Total: <span class="text-muted" t-esc="timesheets[0]._convert_hours_to_days(hours_spent)" t-options='{"widget": "timesheet_uom"}'/>
+ </t>
+ <t t-else="">
+ Total: <span class="text-muted" t-esc="hours_spent" t-options='{"widget": "float_time"}'/>
+ </t>
+ </th>
+ </t>
+ <t t-elif="groupby == 'task'">
+ <th colspan="5">
+ <em class="font-weight-normal text-muted">Timesheets for task:</em>
+ <span t-field="timesheets[0].task_id.name"/>
+ </th>
+ <th colspan="1" class="text-right text-muted">
+ <t t-if="is_uom_day">
+ Total: <span t-esc="timesheets[0]._convert_hours_to_days(hours_spent)" t-options='{"widget": "timesheet_uom"}'/>
+ </t>
+ <t t-else="">
+ Total: <span t-esc="hours_spent" t-options='{"widget": "float_time"}'/>
+ </t>
+ </th>
+ </t>
+ <t t-elif="groupby == 'date'">
+ <th colspan="5">
+ <em class="font-weight-normal text-muted">Timesheets on </em>
+ <span t-field="timesheets[0].date"/>
+ </th>
+ <th colspan="1" class="text-right text-muted">
+ <t t-if="is_uom_day">
+ Total: <span t-esc="timesheets[0]._convert_hours_to_days(hours_spent)" t-options='{"widget": "timesheet_uom"}'/>
+ </t>
+ <t t-else="">
+ Total: <span t-esc="hours_spent" t-options='{"widget": "float_time"}'/>
+ </t>
+ </th>
+ </t>
+ <t t-elif="groupby == 'employee'">
+ <th colspan="5">
+ <em class="font-weight-normal text-muted">Timesheets for employee:</em>
+ <span t-field="timesheets[0].employee_id.name"/>
+ </th>
+ <th colspan="1" class="text-right text-muted">
+ <t t-if="is_uom_day">
+ Total: <span t-esc="timesheets[0]._convert_hours_to_days(hours_spent)" t-options='{"widget": "timesheet_uom"}'/>
+ </t>
+ <t t-else="">
+ Total: <span t-esc="hours_spent" t-options='{"widget": "float_time"}'/>
+ </t>
+ </th>
+ </t>
+ </tr>
+ <tr t-else="">
+ <div style="text-align: right;" class="mr-2 mb-1 text-muted">
+ <t t-if="is_uom_day">
+ Total: <span t-esc="timesheets[0]._convert_hours_to_days(hours_spent)" t-options='{"widget": "timesheet_uom"}'/>
+ </t>
+ <t t-else="">
+ Total: <span t-esc="hours_spent" t-options='{"widget": "float_time"}'/>
+ </t>
+ </div>
</tr>
<tr>
<th t-if="not groupby == 'date'">Date</th>
@@ -61,21 +111,21 @@
<th t-if="not groupby == 'project'">Project</th>
<th t-if="not groupby == 'task'">Task</th>
<th>Description</th>
- <th t-if="is_uom_day" class="text-right">Days Spent <small class="text-muted">(Total: <span t-esc="timesheets[0]._convert_hours_to_days(hours_spent)" t-options='{"widget": "timesheet_uom"}'/>)</small></th>
- <th t-else="" class="text-right">Hours Spent <small class="text-muted">(Total: <span t-esc="hours_spent" t-options='{"widget": "float_time"}'/>)</small></th>
+ <th t-if="is_uom_day" class="text-right">Days Spent</th>
+ <th t-else="" class="text-right">Hours Spent</th>
</tr>
</thead>
- <tbody>
+ <tbody style="font-size: 0.8rem">
<t t-foreach="timesheets" t-as="timesheet">
<tr>
<td t-if="not groupby == 'date'"><span t-field="timesheet.date" t-options='{"widget": "date"}'/></td>
- <td t-if="not groupby == 'employee'"><span t-field="timesheet.employee_id"/></td>
- <td t-if="not groupby == 'project'"><span t-field="timesheet.project_id"/></td>
- <td t-if="not groupby == 'task'"><span t-field="timesheet.task_id"/></td>
- <td><span t-esc="timesheet.name"/></td>
+ <td t-if="not groupby == 'employee'"><span t-field="timesheet.employee_id" t-att-title="timesheet.employee_id.display_name" /></td>
+ <td t-if="not groupby == 'project'"><span t-field="timesheet.project_id" t-att-title="timesheet.project_id.display_name"/></td>
+ <td t-if="not groupby == 'task'"><span t-field="timesheet.task_id" t-att-title="timesheet.task_id.display_name"/></td>
+ <td><span t-esc="timesheet.name" t-att-title="timesheet.name"/></td>
<td class="text-right">
<span t-if="is_uom_day" t-esc="timesheet._get_timesheet_time_day()" t-options='{"widget": "timesheet_uom"}'/>
- <span t-else= "" t-field="timesheet.unit_amount" t-options='{"widget": "float_time"}'/>
+ <span t-else="" t-field="timesheet.unit_amount" t-options='{"widget": "float_time"}'/>
</td>
</tr>
</t>