[IMP] sale_timesheet: clean display of Days for timesheets
Display Days instead of Hours in project overview if encoding unit for timesheets is set to Days [IMP] sale_timesheet: update some labels in Project Overview [IMP] sale_timesheet: fix style in Project Overview [IMP] sale_timesheet: clean code [IMP] sale_timesheet: add some rounding in project overview
This commit is contained in:
@@ -14,4 +14,5 @@ class PortalAccount(PortalAccount):
|
||||
domain = request.env['account.analytic.line']._timesheet_get_portal_domain()
|
||||
domain = expression.AND([domain, [('timesheet_invoice_id', '=', invoice.id)]])
|
||||
values['timesheets'] = request.env['account.analytic.line'].sudo().search(domain)
|
||||
values['is_uom_day'] = request.env['account.analytic.line'].sudo()._is_timesheet_encode_uom_day()
|
||||
return values
|
||||
|
||||
@@ -30,6 +30,8 @@ class Project(models.Model):
|
||||
def _plan_prepare_values(self):
|
||||
currency = self.env.company.currency_id
|
||||
uom_hour = self.env.ref('uom.product_uom_hour')
|
||||
company_uom = self.env.company.timesheet_encode_uom_id
|
||||
is_uom_day = company_uom == self.env.ref('uom.product_uom_day')
|
||||
hour_rounding = uom_hour.rounding
|
||||
billable_types = ['non_billable', 'non_billable_project', 'billable_time', 'billable_fixed']
|
||||
|
||||
@@ -39,13 +41,14 @@ class Project(models.Model):
|
||||
'timesheet_domain': [('project_id', 'in', self.ids)],
|
||||
'profitability_domain': [('project_id', 'in', self.ids)],
|
||||
'stat_buttons': self._plan_get_stat_button(),
|
||||
'is_uom_day': is_uom_day,
|
||||
}
|
||||
|
||||
#
|
||||
# Hours, Rates and Profitability
|
||||
#
|
||||
dashboard_values = {
|
||||
'hours': dict.fromkeys(billable_types + ['total'], 0.0),
|
||||
'time': dict.fromkeys(billable_types + ['total'], 0.0),
|
||||
'rates': dict.fromkeys(billable_types + ['total'], 0.0),
|
||||
'profit': {
|
||||
'invoiced': 0.0,
|
||||
@@ -58,8 +61,12 @@ class Project(models.Model):
|
||||
# hours from non-invoiced timesheets that are linked to canceled so
|
||||
canceled_hours_domain = [('project_id', 'in', self.ids), ('timesheet_invoice_type', '!=', False), ('so_line.state', '=', 'cancel')]
|
||||
total_canceled_hours = sum(self.env['account.analytic.line'].search(canceled_hours_domain).mapped('unit_amount'))
|
||||
dashboard_values['hours']['canceled'] = float_round(total_canceled_hours, precision_rounding=hour_rounding)
|
||||
dashboard_values['hours']['total'] += float_round(total_canceled_hours, precision_rounding=hour_rounding)
|
||||
canceled_hours = float_round(total_canceled_hours, precision_rounding=hour_rounding)
|
||||
if is_uom_day:
|
||||
# convert time from hours to days
|
||||
canceled_hours = round(uom_hour._compute_quantity(canceled_hours, company_uom, raise_if_failure=False), 2)
|
||||
dashboard_values['time']['canceled'] = canceled_hours
|
||||
dashboard_values['time']['total'] += canceled_hours
|
||||
|
||||
# hours (from timesheet) and rates (by billable type)
|
||||
dashboard_domain = [('project_id', 'in', self.ids), ('timesheet_invoice_type', '!=', False), '|', ('so_line', '=', False), ('so_line.state', '!=', 'cancel')] # force billable type
|
||||
@@ -67,12 +74,17 @@ class Project(models.Model):
|
||||
dashboard_total_hours = sum([data['unit_amount'] for data in dashboard_data]) + total_canceled_hours
|
||||
for data in dashboard_data:
|
||||
billable_type = data['timesheet_invoice_type']
|
||||
dashboard_values['hours'][billable_type] = float_round(data.get('unit_amount'), precision_rounding=hour_rounding)
|
||||
dashboard_values['hours']['total'] += float_round(data.get('unit_amount'), precision_rounding=hour_rounding)
|
||||
amount = float_round(data.get('unit_amount'), precision_rounding=hour_rounding)
|
||||
if is_uom_day:
|
||||
# convert time from hours to days
|
||||
amount = round(uom_hour._compute_quantity(amount, company_uom, raise_if_failure=False), 2)
|
||||
dashboard_values['time'][billable_type] = amount
|
||||
dashboard_values['time']['total'] += amount
|
||||
# rates
|
||||
rate = round(data.get('unit_amount') / dashboard_total_hours * 100, 2) if dashboard_total_hours else 0.0
|
||||
dashboard_values['rates'][billable_type] = rate
|
||||
dashboard_values['rates']['total'] += rate
|
||||
dashboard_values['time']['total'] = round(dashboard_values['time']['total'], 2)
|
||||
|
||||
# rates from non-invoiced timesheets that are linked to canceled so
|
||||
dashboard_values['rates']['canceled'] = float_round(100 * total_canceled_hours / (dashboard_total_hours or 1), precision_rounding=hour_rounding)
|
||||
@@ -148,6 +160,11 @@ class Project(models.Model):
|
||||
# compute total
|
||||
for employee_id, vals in repartition_employee.items():
|
||||
repartition_employee[employee_id]['total'] = sum([vals[inv_type] for inv_type in [*billable_types, 'canceled']])
|
||||
if is_uom_day:
|
||||
# convert all times from hours to days
|
||||
for time_type in ['non_billable_project', 'non_billable', 'billable_time', 'billable_fixed', 'canceled', 'total']:
|
||||
if repartition_employee[employee_id][time_type]:
|
||||
repartition_employee[employee_id][time_type] = round(uom_hour._compute_quantity(repartition_employee[employee_id][time_type], company_uom, raise_if_failure=False), 2)
|
||||
hours_per_employee = [repartition_employee[employee_id]['total'] for employee_id in repartition_employee]
|
||||
values['repartition_employee_max'] = (max(hours_per_employee) if hours_per_employee else 1) or 1
|
||||
values['repartition_employee'] = repartition_employee
|
||||
@@ -166,6 +183,8 @@ class Project(models.Model):
|
||||
return False
|
||||
|
||||
uom_hour = self.env.ref('uom.product_uom_hour')
|
||||
company_uom = self.env.company.timesheet_encode_uom_id
|
||||
is_uom_day = company_uom and company_uom == self.env.ref('uom.product_uom_day')
|
||||
|
||||
# build SQL query and fetch raw data
|
||||
query, query_params = self._table_rows_sql_query()
|
||||
@@ -250,6 +269,11 @@ class Project(models.Model):
|
||||
sale_line_row[0]['has_children'] = True
|
||||
timesheet_forecast_table_rows.append(employee_row)
|
||||
|
||||
if is_uom_day:
|
||||
# convert all values from hours to days
|
||||
for row in timesheet_forecast_table_rows:
|
||||
for index in range(1, len(row)):
|
||||
row[index] = round(uom_hour._compute_quantity(row[index], company_uom, raise_if_failure=False), 2)
|
||||
# complete table data
|
||||
return {
|
||||
'header': self._table_header(),
|
||||
|
||||
@@ -89,7 +89,7 @@ $canceled-color: gray;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
>.o_timesheet_plan_badge {
|
||||
.o_timesheet_plan_badge {
|
||||
margin-bottom: 10px;
|
||||
> .badge {
|
||||
border: none;
|
||||
@@ -100,14 +100,16 @@ $canceled-color: gray;
|
||||
}
|
||||
}
|
||||
|
||||
.table {
|
||||
margin-top:15px;
|
||||
}
|
||||
.table > thead > tr > th, .table > thead > tr > td,
|
||||
.table > thead > tr > td,
|
||||
.table > tbody > tr > th, .table > tbody > tr > td {
|
||||
border: none;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.table > thead > tr > th {
|
||||
border: none;
|
||||
padding-left: 0px;;
|
||||
}
|
||||
}
|
||||
|
||||
.o_project_plan_project_timesheet_forecast {
|
||||
|
||||
@@ -89,11 +89,11 @@ class TestSaleProject(TestReporting):
|
||||
project_invoiced = self.so_line_order_project.price_unit * self.so_line_order_project.product_uom_qty * timesheet1.unit_amount
|
||||
project_timesheet_cost = timesheet2.amount + timesheet3.amount + timesheet4.amount + timesheet5.amount + timesheet1.amount
|
||||
|
||||
self.assertEqual(float_compare(vals['dashboard']['hours']['non_billable'], timesheet5.unit_amount, precision_rounding=rounding), 0, "The hours non-billable should be the one from the SO2 line, as we are in ordered quantity")
|
||||
self.assertEqual(float_compare(vals['dashboard']['hours']['non_billable_project'], timesheet2.unit_amount, precision_rounding=rounding), 0, "The hours non-billable-project should be the one from the SO2 line, as we are in ordered quantity")
|
||||
self.assertEqual(float_compare(vals['dashboard']['hours']['billable_time'], timesheet1.unit_amount, precision_rounding=rounding), 0, "The hours billable-time should be the one from the SO2 line, as we are in ordered quantity")
|
||||
self.assertEqual(float_compare(vals['dashboard']['hours']['billable_fixed'], project_so_timesheet_sold_unit, precision_rounding=rounding), 0, "The hours billable-fixed should be the one from the SO2 line, as we are in ordered quantity")
|
||||
self.assertEqual(float_compare(vals['dashboard']['hours']['total'], dashboard_value, precision_rounding=rounding), 0, "The total hours should be the one from the SO2 line, as we are in ordered quantity")
|
||||
self.assertEqual(float_compare(vals['dashboard']['time']['non_billable'], timesheet5.unit_amount, precision_rounding=rounding), 0, "The hours non-billable should be the one from the SO2 line, as we are in ordered quantity")
|
||||
self.assertEqual(float_compare(vals['dashboard']['time']['non_billable_project'], timesheet2.unit_amount, precision_rounding=rounding), 0, "The hours non-billable-project should be the one from the SO2 line, as we are in ordered quantity")
|
||||
self.assertEqual(float_compare(vals['dashboard']['time']['billable_time'], timesheet1.unit_amount, precision_rounding=rounding), 0, "The hours billable-time should be the one from the SO2 line, as we are in ordered quantity")
|
||||
self.assertEqual(float_compare(vals['dashboard']['time']['billable_fixed'], project_so_timesheet_sold_unit, precision_rounding=rounding), 0, "The hours billable-fixed should be the one from the SO2 line, as we are in ordered quantity")
|
||||
self.assertEqual(float_compare(vals['dashboard']['time']['total'], dashboard_value, precision_rounding=rounding), 0, "The total hours should be the one from the SO2 line, as we are in ordered quantity")
|
||||
self.assertEqual(float_compare(vals['dashboard']['rates']['non_billable'], project_rate_non_billable, precision_rounding=rounding), 0, "The rate non-billable should be the one from the SO2 line, as we are in ordered quantity")
|
||||
self.assertEqual(float_compare(vals['dashboard']['rates']['non_billable_project'], project_rate_non_billable_project, precision_rounding=rounding), 0, "The rate non-billable-project should be the one from the SO2 line, as we are in ordered quantity")
|
||||
self.assertEqual(float_compare(vals['dashboard']['rates']['billable_time'], project_rate_billable_time, precision_rounding=rounding), 0, "The rate billable-time should be the one from the SO2 line, as we are in ordered quantity")
|
||||
|
||||
@@ -64,7 +64,8 @@
|
||||
</div>
|
||||
|
||||
<div class="o_title">
|
||||
<h2>Recorded Hours and Profitability</h2>
|
||||
<h2 t-if="is_uom_day">Recorded Days and Profitability</h2>
|
||||
<h2 t-else="">Recorded Hours and Profitability</h2>
|
||||
</div>
|
||||
|
||||
<t t-set="display_cost" t-value="dashboard['profit']['expense_cost'] != 0.0"/>
|
||||
@@ -74,11 +75,17 @@
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<th>
|
||||
<a type="action" data-model="account.analytic.line" t-att-data-domain="json.dumps(timesheet_domain)" data-context='{"pivot_row_groupby": ["date:month"],"pivot_column_groupby": ["timesheet_invoice_type"], "pivot_measures": ["unit_amount"]}' data-views='[[0, "pivot"], [0, "list"]]' tabindex="-1">Hours</a>
|
||||
<a type="action" data-model="account.analytic.line" t-att-data-domain="json.dumps(timesheet_domain)"
|
||||
data-context='{"pivot_row_groupby": ["date:month"],"pivot_column_groupby": ["timesheet_invoice_type"], "pivot_measures": ["unit_amount"]}'
|
||||
data-views='[[0, "pivot"], [0, "list"]]' tabindex="-1">
|
||||
<span t-if="is_uom_day">Days recorded</span>
|
||||
<span t-else="">Hours recorded</span>
|
||||
</a>
|
||||
</th>
|
||||
<tr>
|
||||
<td class="o_timesheet_plan_dashboard_cell">
|
||||
<t t-esc="dashboard['hours']['billable_time']" t-options="{'widget': 'float_time'}"/>
|
||||
<t t-if="is_uom_day" t-esc="dashboard['time']['billable_time']" t-options="{'widget': 'timesheet_uom'}"/>
|
||||
<t t-else="" t-esc="dashboard['time']['billable_time']" t-options="{'widget': 'float_time'}"/>
|
||||
</td>
|
||||
<td class="o_timesheet_plan_dashboard_cell">
|
||||
(<t t-esc="dashboard['rates']['billable_time']"/> %)
|
||||
@@ -89,7 +96,8 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="o_timesheet_plan_dashboard_cell">
|
||||
<t t-esc="dashboard['hours']['billable_fixed']" t-options="{'widget': 'float_time'}"/>
|
||||
<t t-if="is_uom_day" t-esc="dashboard['time']['billable_fixed']" t-options="{'widget': 'timesheet_uom'}"/>
|
||||
<t t-else="" t-esc="dashboard['time']['billable_fixed']" t-options="{'widget': 'float_time'}"/>
|
||||
</td>
|
||||
<td class="o_timesheet_plan_dashboard_cell">
|
||||
(<t t-esc="dashboard['rates']['billable_fixed']"/> %)
|
||||
@@ -98,9 +106,10 @@
|
||||
Billed at a Fixed price
|
||||
</td>
|
||||
</tr>
|
||||
<tr t-if="dashboard['hours']['non_billable_project'] != 0">
|
||||
<tr t-if="dashboard['time']['non_billable_project'] != 0">
|
||||
<td class="o_timesheet_plan_dashboard_cell">
|
||||
<t t-esc="dashboard['hours']['non_billable_project']" t-options="{'widget': 'float_time'}"/>
|
||||
<t t-if="is_uom_day" t-esc="dashboard['time']['non_billable_project']" t-options="{'widget': 'timesheet_uom'}"/>
|
||||
<t t-else="" t-esc="dashboard['time']['non_billable_project']" t-options="{'widget': 'float_time'}"/>
|
||||
</td>
|
||||
<td class="o_timesheet_plan_dashboard_cell">
|
||||
(<t t-esc="dashboard['rates']['non_billable_project']"/> %)
|
||||
@@ -111,7 +120,8 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="o_timesheet_plan_dashboard_cell">
|
||||
<t t-esc="dashboard['hours']['non_billable']" t-options="{'widget': 'float_time'}"/>
|
||||
<t t-if="is_uom_day" t-esc="dashboard['time']['non_billable']" t-options="{'widget': 'timesheet_uom'}"/>
|
||||
<t t-else="" t-esc="dashboard['time']['non_billable']" t-options="{'widget': 'float_time'}"/>
|
||||
</td>
|
||||
<td class="o_timesheet_plan_dashboard_cell">
|
||||
(<t t-esc="dashboard['rates']['non_billable']"/> %)
|
||||
@@ -130,9 +140,10 @@
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr t-if="dashboard['hours']['canceled'] > 0">
|
||||
<tr t-if="dashboard['time']['canceled'] > 0">
|
||||
<td class="o_timesheet_plan_dashboard_cell">
|
||||
<t t-esc="dashboard['hours']['canceled']" t-options="{'widget': 'float_time'}"/>
|
||||
<t t-if="is_uom_day" t-esc="dashboard['time']['canceled']" t-options="{'widget': 'timesheet_uom'}"/>
|
||||
<t t-else="" t-esc="dashboard['time']['canceled']" t-options="{'widget': 'float_time'}"/>
|
||||
</td>
|
||||
<td class="o_timesheet_plan_dashboard_cell">
|
||||
(<t t-esc="dashboard['rates']['canceled']"/> %)
|
||||
@@ -142,7 +153,12 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="o_timesheet_plan_dashboard_total"><b><t t-esc="dashboard['hours']['total']" t-options="{'widget': 'float_time'}"/></b></td>
|
||||
<td class="o_timesheet_plan_dashboard_total">
|
||||
<b>
|
||||
<t t-if="is_uom_day" t-esc="dashboard['time']['total']" t-options="{'widget': 'timesheet_uom'}"/>
|
||||
<t t-else="" t-esc="dashboard['time']['total']" t-options="{'widget': 'float_time'}"/>
|
||||
</b>
|
||||
</td>
|
||||
<td><b>Total</b></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
@@ -227,28 +243,38 @@
|
||||
<p>There are no timesheets for now.</p>
|
||||
</t>
|
||||
<t t-if="repartition_employee">
|
||||
<div class="float-right o_timesheet_plan_badge">
|
||||
<span class="badge badge-pill o_progress_billable_time">
|
||||
<a type="action" data-model="account.analytic.line" t-att-data-domain="json.dumps(timesheet_domain + [('timesheet_invoice_type','=','billable_time')])" tabindex="-1">Billed on Timesheets</a>
|
||||
</span>
|
||||
<span class="badge badge-pill o_progress_billable_fixed">
|
||||
<a type="action" data-model="account.analytic.line" t-att-data-domain="json.dumps(timesheet_domain + [('timesheet_invoice_type','=','billable_fixed')])" tabindex="-1">Billed at a Fixed price</a>
|
||||
</span>
|
||||
<span t-if="dashboard['hours']['non_billable_project'] != 0" class="badge badge-pill o_progress_non_billable_project">
|
||||
<a type="action" data-model="account.analytic.line" t-att-data-domain="json.dumps(timesheet_domain + [('timesheet_invoice_type','=','non_billable_project')])" tabindex="-1">No task found</a>
|
||||
</span>
|
||||
<span class="badge badge-pill o_progress_non_billable">
|
||||
<a type="action" data-model="account.analytic.line" t-att-data-domain="json.dumps(timesheet_domain + [('timesheet_invoice_type','=','non_billable')])" tabindex="-1">Non billable tasks</a>
|
||||
</span>
|
||||
<!-- only show the canceled pill if there were timesheets on canceled so -->
|
||||
<t t-if="sum([employee.get('canceled', 0.0) for employee in repartition_employee.values()]) > 0">
|
||||
<span class="badge badge-pill o_progress_canceled">
|
||||
<a type="action" data-model="account.analytic.line" t-att-data-domain="json.dumps(timesheet_domain + [('so_line.state', '=', 'cancel')])" tabindex="-1">Cancelled</a>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Employee</th>
|
||||
<th t-if="is_uom_day" class="text-nowrap text-right pr-5">Days Spent</th>
|
||||
<th t-else="" class="text-nowrap text-right pr-5">Hours Spent</th>
|
||||
<td>
|
||||
<div class="float-right o_timesheet_plan_badge">
|
||||
<span class="badge badge-pill o_progress_billable_time">
|
||||
<a type="action" data-model="account.analytic.line" t-att-data-domain="json.dumps(timesheet_domain + [('timesheet_invoice_type','=','billable_time')])" tabindex="-1">Billed on Timesheets</a>
|
||||
</span>
|
||||
<span class="badge badge-pill o_progress_billable_fixed">
|
||||
<a type="action" data-model="account.analytic.line" t-att-data-domain="json.dumps(timesheet_domain + [('timesheet_invoice_type','=','billable_fixed')])" tabindex="-1">Billed at a Fixed price</a>
|
||||
</span>
|
||||
<span t-if="dashboard['time']['non_billable_project'] != 0" class="badge badge-pill o_progress_non_billable_project">
|
||||
<a type="action" data-model="account.analytic.line" t-att-data-domain="json.dumps(timesheet_domain + [('timesheet_invoice_type','=','non_billable_project')])" tabindex="-1">No task found</a>
|
||||
</span>
|
||||
<span class="badge badge-pill o_progress_non_billable">
|
||||
<a type="action" data-model="account.analytic.line" t-att-data-domain="json.dumps(timesheet_domain + [('timesheet_invoice_type','=','non_billable')])" tabindex="-1">Non billable tasks</a>
|
||||
</span>
|
||||
<!-- only show the canceled pill if there were timesheets on canceled so -->
|
||||
<t t-if="sum([employee.get('canceled', 0.0) for employee in repartition_employee.values()]) > 0">
|
||||
<span class="badge badge-pill o_progress_canceled">
|
||||
<a type="action" data-model="account.analytic.line" t-att-data-domain="json.dumps(timesheet_domain + [('so_line.state', '=', 'cancel')])" tabindex="-1">Cancelled</a>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<t t-foreach="repartition_employee" t-as="employee_id">
|
||||
<t t-set="employee" t-value="repartition_employee[employee_id]"/>
|
||||
@@ -262,7 +288,8 @@
|
||||
</a>
|
||||
</td>
|
||||
<td class="text-right pr-5" style="width: 10%; vertical-align: middle;">
|
||||
<t t-esc="employee['total']" t-options="{'widget': 'float_time'}"/>
|
||||
<t t-if="is_uom_day" t-esc="employee['total']" t-options="{'widget': 'timesheet_uom'}"/>
|
||||
<t t-else="" t-esc="employee['total']" t-options="{'widget': 'float_time'}"/>
|
||||
</td>
|
||||
<td style="vertical-align:middle">
|
||||
<div class="border rounded">
|
||||
@@ -367,15 +394,24 @@
|
||||
<t t-if="row_value_index != 0">
|
||||
<t t-if="row_value_index < len(row)-2">
|
||||
<t t-if="row_is_milestone">
|
||||
<i t-att-class="'text-muted' if not row_value else ''"><t t-esc="row_value" t-options="{'widget': 'float_time'}"/></i>
|
||||
<i t-att-class="'text-muted' if not row_value else ''">
|
||||
<t t-if="is_uom_day" t-esc="row_value" t-options="{'widget': 'timesheet_uom'}"/>
|
||||
<t t-else="" t-esc="row_value" t-options="{'widget': 'float_time'}"/>
|
||||
</i>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span t-att-class="'text-muted' if not row_value else ''"><t t-esc="row_value" t-options="{'widget': 'float_time'}"/></span>
|
||||
<span t-att-class="'text-muted' if not row_value else ''">
|
||||
<t t-if="is_uom_day" t-esc="row_value" t-options="{'widget': 'timesheet_uom'}"/>
|
||||
<t t-else="" t-esc="row_value" t-options="{'widget': 'float_time'}"/>
|
||||
</span>
|
||||
</t>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-if="not row_is_milestone and not row[0].get('type') == 'hr_employee'">
|
||||
<span t-att-class="'text-muted' if not row_value else ''"><t t-esc="row_value" t-options="{'widget': 'float_time'}"/></span>
|
||||
<span t-att-class="'text-muted' if not row_value else ''">
|
||||
<t t-if="is_uom_day" t-esc="row_value" t-options="{'widget': 'timesheet_uom'}"/>
|
||||
<t t-else="" t-esc="row_value" t-options="{'widget': 'float_time'}"/>
|
||||
</span>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
@@ -406,7 +442,9 @@
|
||||
<template id="progressbar" name="project overview progressbar segments">
|
||||
<t t-set="amount" t-value="employee[key]"/>
|
||||
<t t-if="amount > 0">
|
||||
<t t-set="title"><t t-esc="label"/>: <t t-esc="amount" t-options="{'widget': 'float_time'}"/></t>
|
||||
<t t-set="title">
|
||||
<t t-esc="label"/>: <t t-if="is_uom_day" t-esc="amount" t-options="{'widget': 'timesheet_uom'}"/><t t-else="" t-esc="amount" t-options="{'widget': 'float_time'}"/>
|
||||
</t>
|
||||
<a t-attf-class="progress-bar o_progress_{{key}}"
|
||||
t-attf-style="width: {{amount / total * 100}}%"
|
||||
type="action" data-model="account.analytic.line"
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
<th t-if="nr_projects > 1">Project</th>
|
||||
<th t-if="nr_tasks > 0">Task</th>
|
||||
<th>Description</th>
|
||||
<th class="text-right">Duration</th>
|
||||
<th t-if="timesheets[0]._is_timesheet_encode_uom_day()" class="text-right">Duration (days)</th>
|
||||
<th t-else="" class="text-right">Duration (hours)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr t-foreach="timesheets" t-as="timesheet">
|
||||
@@ -45,7 +46,10 @@
|
||||
<td t-if="nr_projects > 1"><span t-field="timesheet.project_id"/></td>
|
||||
<td t-if="nr_tasks > 0"><span t-field="timesheet.task_id"/></td>
|
||||
<td><t t-esc="timesheet.name"/></td>
|
||||
<td class="text-right"><span t-field="timesheet.unit_amount" t-options='{"widget": "float_time"}'/></td>
|
||||
<td class="text-right">
|
||||
<span t-if="timesheet._is_timesheet_encode_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"}'/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user