Files
odoo_source/addons/hr_timesheet/controllers/portal.py
T
fw-bot 0a8f4b6cda Purpose
=======

This PR is in the continuity of odoo#62360.

- Display remaining hours in task sales_line_id (name_get + task form view)
- Remove internal reference from services demo data
- Display sol in project timesheets list if project is billable
- Remove use of non_allow_billable in timesheets as it has been removed from project and task in previous PR (see above)
- Only recompute planned_hours for service product
- Determine the correct SOL for timesheet
- Set the last SOL of customer on timesheet if none is set on task or project
- Allow edition of so_line in timesheet
- Restrict SOL on project to sale lines with a service product
- Use same widget on partner_id many2One than in sale.order (using ranking)
- Remove timesheets table in SO and invoice portal.They were added in previous PR (see above). This introduces the use of links to /my/timesheets/.
- Review portal timesheets (my/timesheets/ and link from orders and invoices)
- Activate group_uom "Units of Measure" on sale_timesheet install
- Hide partner phone number in task form view
- Only determine SOL of task and timesheet if allow_billable=True
- Filter SOL in task so that it matches the SOL of the project SO
- Display red label if remaining hours is negative
- Change SO compute behavior
- Only open SO for salesman on project overview

task-2409761

--
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr

closes odoo/odoo#63695

Forward-port-of: #62900
X-original-commit: b1985773f3a67e28049f9e2bb635bcab059ad9c0
Related: odoo/enterprise#15427
Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
2020-12-22 13:40:28 +00:00

161 lines
7.8 KiB
Python

# -*- 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 datetime import datetime
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, OR
from odoo.addons.portal.controllers.portal import CustomerPortal, pager as portal_pager
class TimesheetCustomerPortal(CustomerPortal):
def _prepare_home_portal_values(self, counters):
values = super()._prepare_home_portal_values(counters)
if 'timesheet_count' in counters:
domain = request.env['account.analytic.line']._timesheet_get_portal_domain()
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 = self._get_searchbar_inputs()
searchbar_groupby = self._get_searchbar_groupby()
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 += self._get_search_domain(search_in, 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, 'groupby': groupby},
total=timesheet_count,
page=page,
step=_items_per_page
)
def get_timesheets():
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=_items_per_page, offset=pager['offset'])
if field:
if groupby == 'date':
time_data = Timesheet_sudo.read_group(domain, ['date', 'unit_amount:sum'], ['date:day'])
mapped_time = dict([(datetime.strptime(m['date:day'], '%d %b %Y').date(), m['unit_amount']) for m in time_data])
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] 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
grouped_timesheets = [(
timesheets,
sum(Timesheet_sudo.search(domain).mapped('unit_amount'))
)] if timesheets else []
return timesheets, grouped_timesheets
timesheets, grouped_timesheets = get_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,
'search': search,
'sortby': sortby,
'groupby': groupby,
'searchbar_inputs': searchbar_inputs,
'searchbar_groupby': searchbar_groupby,
'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())),
'filterby': filterby,
'is_uom_day': request.env['account.analytic.line']._is_timesheet_encode_uom_day(),
})
return request.render("hr_timesheet.portal_my_timesheets", values)