19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:31:00 +01:00
parent a1137a1456
commit e1d89e11e3
2789 changed files with 1093187 additions and 605897 deletions

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="hr_department_view_kanban" model="ir.ui.view">
<field name="name">hr.department.kanban.inherit</field>
<field name="model">hr.department</field>
<field name="inherit_id" ref="hr.hr_department_view_kanban"/>
<field name="arch" type="xml">
<data>
<xpath expr="//div[hasclass('o_kanban_manage_reports')]" position="inside">
<div role="menuitem">
<a name="%(act_hr_timesheet_report)d" type="action"
class="dropdown-item"
context="{ 'search_default_department_id': [id], 'default_department_id': id}">
Timesheets
</a>
</div>
</xpath>
</data>
</field>
</record>
</odoo>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="hr_employee_public_view_form" model="ir.ui.view">
<field name="name">hr.employee.public.form.inherit.timesheet</field>
<field name="model">hr.employee.public</field>
<field name="inherit_id" ref="hr.hr_employee_public_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside">
<field name="has_timesheet" groups="hr_timesheet.group_hr_timesheet_user" invisible="1"/>
<button invisible="not is_user or not has_timesheet" class="oe_stat_button" type="object" name="action_timesheet_from_employee" icon="fa-calendar" groups="hr_timesheet.group_hr_timesheet_user">
<div class="o_stat_info">
<span class="o_stat_text">Timesheets</span>
</div>
</button>
</xpath>
</field>
</record>
</odoo>

View file

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="timesheet_action_view_from_employee_form" model="ir.actions.act_window.view">
<field name="sequence" eval="10"/>
<field name="view_mode">form</field>
<field name="view_id" ref="hr_timesheet_line_form"/>
<field name="act_window_id" ref="timesheet_action_from_employee"/>
</record>
<record id="hr_employee_view_form_inherit_timesheet" model="ir.ui.view">
<field name="name">hr.employee.form.timesheet</field>
<field name="model">hr.employee</field>
<field name="inherit_id" ref="hr_hourly_cost.view_employee_form"/>
<field name="priority" eval="40"/>
<field name="arch" type="xml">
<xpath expr="/form" position="attributes">
<attribute name="delete">0</attribute>
</xpath>
<button name="action_open_versions" position="before">
<field name="has_timesheet" groups="hr_timesheet.group_hr_timesheet_user" invisible="1"/>
<button invisible="not has_timesheet" class="oe_stat_button" type="object" name="action_timesheet_from_employee" icon="fa-calendar" groups="hr_timesheet.group_hr_timesheet_user">
<div class="o_stat_info">
<span class="o_stat_text">Timesheets</span>
</div>
</button>
</button>
</field>
</record>
<record id="view_employee_tree_inherit_timesheet" model="ir.ui.view">
<field name="name">hr.employee.list.timesheet</field>
<field name="model">hr.employee</field>
<field name="inherit_id" ref="hr.view_employee_tree"/>
<field name="arch" type="xml">
<xpath expr="/list" position="attributes">
<attribute name="delete">0</attribute>
</xpath>
</field>
</record>
<record id="hr_employee_view_kanban_inherit_timesheet" model="ir.ui.view">
<field name="name">hr.employee.kanban.timesheet</field>
<field name="model">hr.employee</field>
<field name="inherit_id" ref="hr.hr_kanban_view_employees"/>
<field name="arch" type="xml">
<xpath expr="/kanban" position="attributes">
<attribute name="delete">0</attribute>
</xpath>
</field>
</record>
<record id="unlink_employee_action" model="ir.actions.server">
<field name="name">Delete</field>
<field name="model_id" ref="hr.model_hr_employee"/>
<field name="binding_model_id" ref="hr.model_hr_employee"/>
<field name="binding_view_types">form,list,kanban</field>
<field name="state">code</field>
<field name="code">action = records.action_unlink_wizard()</field>
</record>
</odoo>

View file

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<menuitem id="timesheet_menu_root"
name="Timesheets"
sequence="75"
groups="group_hr_timesheet_user"
web_icon="hr_timesheet,static/description/icon_timesheet.png"
>
<menuitem id="timesheet_menu_activity_user"
name="My Timesheets"
groups="group_hr_timesheet_user"
action="act_hr_timesheet_line"
/>
<menuitem id="menu_hr_time_tracking"
name="Timesheets"
groups="group_hr_timesheet_approver"
sequence="5"
>
<menuitem id="timesheet_menu_activity_mine"
name="My Timesheets"
groups="group_hr_timesheet_approver"
action="act_hr_timesheet_line"
/>
<menuitem id="timesheet_menu_activity_all"
name="All Timesheets"
action="timesheet_action_all"
groups="hr_timesheet.group_hr_timesheet_approver"
/>
</menuitem>
<menuitem id="menu_timesheets_reports"
name="Reporting"
groups="group_hr_timesheet_approver"
sequence="99"
>
<menuitem id="menu_timesheets_reports_timesheet"
name="Timesheets"
sequence="10"
>
<menuitem id="menu_hr_activity_analysis"
action="act_hr_timesheet_report"
groups="hr_timesheet.group_hr_timesheet_approver"
name="By Employee"
sequence="10"
/>
<menuitem id="timesheet_menu_report_timesheet_by_project"
action="timesheet_action_report_by_project"
name="By Project"
sequence="15"
/>
<menuitem id="timesheet_menu_report_timesheet_by_task"
action="timesheet_action_report_by_task"
name="By Task"
sequence="20"
/>
</menuitem>
</menuitem>
<menuitem id="hr_timesheet_menu_configuration"
name="Configuration"
action="hr_timesheet_config_settings_action"
groups="base.group_system"
sequence="100"
/>
</menuitem>
</odoo>

View file

@ -1,6 +1,5 @@
<?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 ''}">
@ -9,14 +8,19 @@
</xpath>
</template>
<template id="portal_my_home_timesheet" name="Show Timesheets" customize_show="True" inherit_id="portal.portal_my_home" priority="45">
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<template id="portal_my_home_timesheet" name="Timesheets" customize_show="True" inherit_id="portal.portal_my_home" priority="45">
<xpath expr="//div[hasclass('o_portal_docs')]" position="before">
<t t-set="portal_service_category_enable" t-value="True"/>
</xpath>
<div id="portal_service_category" position="inside">
<t t-call="portal.portal_docs_entry">
<t t-set="icon" t-value="'/hr_timesheet/static/img/timesheet.svg'"/>
<t t-set="title">Timesheets</t>
<t t-set="url" t-value="'/my/timesheets'"/>
<t t-set="text">Review all timesheets related to your projects</t>
<t t-set="placeholder_count" t-value="'timesheet_count'"/>
</t>
</xpath>
</div>
</template>
<template id="portal_my_timesheets" name="My Timesheets">
@ -27,7 +31,7 @@
<t t-set="title">Timesheets</t>
</t>
<t t-if="not grouped_timesheets">
<div class="alert alert-warning mt8" role="alert">
<div class="alert alert-warning" role="alert">
There are no timesheets.
</div>
</t>
@ -36,12 +40,11 @@
<thead>
<tr>
<th t-if="not groupby == 'date'">Date</th>
<th t-if="not groupby == 'employee'">Employee</th>
<th t-if="not groupby == 'project'">Project</th>
<th t-if="not groupby == 'task'">Task</th>
<th t-if="not groupby == 'employee_id'">Employee</th>
<th t-if="not groupby == 'project_id'">Project</th>
<th t-if="not groupby == 'task_id'">Task</th>
<th>Description</th>
<th t-if="is_uom_day" class="text-end" t-att-colspan="2 if groupby != 'none' else 0">Days Spent</th>
<th t-else="" class="text-end" t-att-colspan="2 if groupby != 'none' else 0">Hours Spent</th>
<th class="text-end" t-att-colspan="2 if groupby != 'none' else 0" name="t_label">Time Spent</th>
</tr>
</thead>
<t t-foreach="grouped_timesheets" t-as="timesheets_with_hours">
@ -49,77 +52,50 @@
<t t-set="hours_spent" t-value="timesheets_with_hours[1]"/>
<tbody style="font-size: 0.8rem">
<tr t-if="not groupby =='none'" class="table-light">
<t t-if="groupby == 'project'">
<th t-if="groupby == 'project'" colspan="5">
<t t-if="groupby == 'project_id'">
<th colspan="5">
<span t-field="timesheets[0].project_id.name"/>
</th>
<th colspan="1" class="text-end text-muted">
<t t-if="is_uom_day">
Total: <span class="text-muted" t-esc="timesheets._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'">
<t t-elif="groupby == 'task_id'">
<th colspan="5">
<span t-field="timesheets[0].task_id.name"/>
</th>
<th colspan="1" class="text-end text-muted">
<t t-if="is_uom_day">
Total: <span t-esc="timesheets._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>
<span t-if="timesheets[0].task_id" t-field="timesheets[0].task_id.name"/>
<span t-else="">No Task</span>
</th>
</t>
<t t-elif="groupby == 'date'">
<th colspan="5">
<span t-field="timesheets[0].date"/>
</th>
<th colspan="1" class="text-end text-muted">
<t t-if="is_uom_day">
Total: <span t-esc="timesheets._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'">
<t t-elif="groupby == 'employee_id'">
<th colspan="5">
<span t-field="timesheets[0].employee_id.name"/>
</th>
<th colspan="1" class="text-end text-muted">
<t t-if="is_uom_day">
Total: <span t-esc="timesheets._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>
</t>
<t t-elif="groupby == 'parent_task_id'">
<th colspan="6">
<span t-if="timesheets[0].parent_task_id" t-field="timesheets[0].parent_task_id.name"/>
<span t-else="">No Parent Task</span>
</th>
</t>
</tr>
<tr t-else="">
<div style="text-align: right;" class="me-2 mb-1 text-muted">
<th colspan="1" class="text-end text-muted">
<t t-if="is_uom_day">
Total: <span t-esc="timesheets._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>
</th>
</tr>
</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" 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 t-if="not groupby == 'employee_id'"><span t-field="timesheet.employee_id" t-att-title="timesheet.employee_id.display_name" /></td>
<td t-if="not groupby == 'project_id'"><span t-field="timesheet.project_id" t-att-title="timesheet.project_id.display_name"/></td>
<td t-if="not groupby == 'task_id'"><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-end" t-att-colspan="2 if groupby != 'none' else 0">
<span t-if="is_uom_day" t-esc="timesheet._get_timesheet_time_day()" t-options='{"widget": "timesheet_uom"}'/>
@ -134,4 +110,74 @@
</t>
</template>
<template id="portal_timesheet_table" name="Portal Timesheet Table">
<table class="o_portal_my_doc_table table table-sm table-striped">
<thead>
<tr>
<th>Date</th>
<th>Employee</th>
<th>Description</th>
<th class="text-end" name="t_label">Time Spent</th>
</tr>
</thead>
<tr t-foreach="timesheets" t-as="timesheet" valign="middle">
<td><t t-esc="timesheet.date" t-options='{"widget": "date"}'/></td>
<td t-attf-title="#{timesheet.employee_id.name}"><t t-esc="timesheet.employee_id.name"/></td>
<td><t t-esc="timesheet.name"/></td>
<td class="text-end">
<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"}'/>
</td>
</tr>
</table>
<div class="container_subtotal">
<div class="row justify-content-end">
<div t-attf-class="{{'col-auto' if report_type != 'html' else 'col-sm-2'}}">
<table class="table table-sm">
<tr>
<td><strong>Total Time Spent: </strong></td>
<td class="text-end">
<span t-if="is_uom_day" t-esc="timesheets._convert_hours_to_days(task.effective_hours)" t-options="{'widget': 'timesheet_uom'}"/>
<span t-else="" t-esc="task.effective_hours" t-options='{"widget": "float_time"}'/>
</td>
</tr>
<tr>
<div t-if="task.subtask_effective_hours">
<td><strong>Time recorded on sub-tasks: </strong></td>
<td class="text-end">
<span t-if="is_uom_day" t-esc="timesheets._convert_hours_to_days(task.subtask_effective_hours)" t-options='{"widget": "timesheet_uom"}'/>
<span t-else="" t-esc="task.subtask_effective_hours" t-options='{"widget": "float_time"}'/>
</td>
</div>
</tr>
<tr>
<div t-if="task.total_hours_spent and task.subtask_effective_hours" name="total_time">
<t t-if="is_uom_day">
<td><strong>Total Days: </strong></td>
<td class="text-end">
<span t-esc="timesheets._convert_hours_to_days(task.total_hours_spent)" t-options='{"widget": "timesheet_uom"}'/>
</td>
</t>
<t t-else="">
<td><strong>Total Hours: </strong></td>
<td class="text-end">
<span t-esc="task.total_hours_spent" t-options='{"widget": "float_time"}'/>
</td>
</t>
</div>
</tr>
<tr t-attf-class="{{task.remaining_hours &lt; 0 and 'text-danger' or ''}}">
<div t-if="task.allocated_hours > 0" name="allocated_time">
<td><strong>Time Remaining: </strong></td>
<td class="text-end">
<span t-if="is_uom_day" t-esc="timesheets._convert_hours_to_days(task.remaining_hours)" t-options='{"widget": "timesheet_uom"}'/>
<span t-else="" t-esc="task.remaining_hours" t-options='{"widget": "float_time"}'/>
</td>
</div>
</tr>
</table>
</div>
</div>
</div>
</template>
</odoo>

View file

@ -1,49 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- Timesheet root menus -->
<menuitem id="timesheet_menu_root"
name="Timesheets"
sequence="75"
groups="group_hr_timesheet_user"
web_icon="hr_timesheet,static/description/icon_timesheet.png"/>
<menuitem id="menu_hr_time_tracking"
name="Timesheets"
parent="timesheet_menu_root"
groups = "group_hr_timesheet_approver"
sequence="5"/>
<!--
Timesheet line Views
-->
<record id="hr_timesheet_line_tree" model="ir.ui.view">
<field name="name">account.analytic.line.tree.hr_timesheet</field>
<field name="name">account.analytic.line.list.hr_timesheet</field>
<field name="model">account.analytic.line</field>
<field name="arch" type="xml">
<tree editable="bottom" string="Timesheet Activities" sample="1">
<field name="date"/>
<field name="employee_id" invisible="1"/>
<field name="project_id" required="1" options="{'no_create_edit': True, 'no_open': 1}"/>
<field name="task_id" optional="show" options="{'no_create_edit': True, 'no_open': True}" widget="task_with_hours" context="{'default_project_id': project_id}"/>
<field name="name" optional="show" required="0"/>
<field name="unit_amount" optional="show" widget="timesheet_uom" sum="Total" decoration-danger="unit_amount &gt; 24 or unit_amount &lt; 0"/>
<field name="company_id" invisible="1"/>
<field name="user_id" invisible="1"/>
</tree>
<list editable="top" string="Timesheet Activities" sample="1" decoration-muted="readonly_timesheet == True">
<field name="readonly_timesheet" column_invisible="True"/>
<field name="date" readonly="readonly_timesheet"/>
<field name="employee_id" column_invisible="True" readonly="readonly_timesheet"/>
<field name="project_id" options="{'no_create_edit': True}" required="1" readonly="readonly_timesheet"
context="{'search_default_my_projects': True}"/>
<field name="task_id" optional="show" options="{'no_create_edit': True, 'no_open': True}" widget="task_with_hours"
context="{'default_project_id': project_id, 'search_default_my_tasks': True, 'search_default_open_tasks': True}"
readonly="readonly_timesheet"/>
<field name="name" optional="show" required="0" readonly="readonly_timesheet"/>
<field name="unit_amount" string="Time Spent" optional="show" widget="timesheet_uom" sum="Total" readonly="readonly_timesheet"
decoration-danger="unit_amount &gt; 24 or unit_amount &lt; 0" decoration-muted="unit_amount == 0"/>
<field name="company_id" column_invisible="True"/>
<field name="user_id" column_invisible="True"/>
</list>
</field>
</record>
<record id="hr_timesheet_line_portal_tree" model="ir.ui.view">
<field name="name">portal.hr_timesheet.account.analytic.line.list</field>
<field name="model">account.analytic.line</field>
<field name="inherit_id" ref="hr_timesheet_line_tree"/>
<field name="mode">primary</field>
<field name="priority">10</field>
<field name="arch" type="xml">
<xpath expr="//list" position="attributes">
<attribute name="edit">0</attribute>
<attribute name="create">0</attribute>
<attribute name="delete">0</attribute>
<attribute name="js_class"></attribute>
</xpath>
<xpath expr="//field[@name='task_id']" position="attributes">
<attribute name="options">{'no_create_edit': True, 'no_open': True}</attribute>
</xpath>
</field>
</record>
<record id="timesheet_view_tree_user" model="ir.ui.view">
<field name="name">account.analytic.line.view.tree.with.user</field>
<field name="name">account.analytic.line.view.list.with.user</field>
<field name="model">account.analytic.line</field>
<field name="inherit_id" ref="hr_timesheet_line_tree"/>
<field name="mode">primary</field>
<field name="priority">10</field>
<field name="arch" type="xml">
<xpath expr="//field[@name='employee_id']" position="attributes">
<attribute name="invisible">0</attribute>
<attribute name="column_invisible">0</attribute>
<attribute name="required">1</attribute>
<attribute name="widget">many2one_avatar_employee</attribute>
<attribute name="context">{'active_test': True}</attribute>
@ -58,7 +65,7 @@
<pivot string="Timesheets" sample="1">
<field name="employee_id" type="row"/>
<field name="date" interval="month" type="col"/>
<field name="unit_amount" type="measure" widget="timesheet_uom"/>
<field name="unit_amount" string="Time Spent" type="measure" widget="timesheet_uom"/>
<field name="amount" string="Timesheet Costs"/>
</pivot>
</field>
@ -70,7 +77,7 @@
<field name="arch" type="xml">
<pivot string="Timesheet" sample="1">
<field name="date" interval="week" type="row"/>
<field name="unit_amount" type="measure" widget="timesheet_uom"/>
<field name="unit_amount" string="Time Spent" type="measure" widget="timesheet_uom"/>
<field name="amount" string="Timesheet Costs"/>
</pivot>
</field>
@ -83,7 +90,7 @@
<graph string="Timesheets" sample="1" js_class="hr_timesheet_graphview">
<field name="task_id"/>
<field name="project_id"/>
<field name="unit_amount" type="measure" widget="timesheet_uom"/>
<field name="unit_amount" string="Time Spent" type="measure" widget="timesheet_uom"/>
<field name="amount" string="Timesheet Costs"/>
</graph>
</field>
@ -98,7 +105,7 @@
<field name="date" interval="week"/>
<field name="project_id"/>
<field name="amount" type="measure" string="Timesheet Costs"/>
<field name="unit_amount" type="measure" widget="timesheet_uom"/>
<field name="unit_amount" string="Time Spent" type="measure" widget="timesheet_uom"/>
</graph>
</field>
</record>
@ -112,11 +119,29 @@
<field name="employee_id"/>
<field name="project_id"/>
<field name="amount" type="measure" string="Timesheet Costs"/>
<field name="unit_amount" type="measure" widget="timesheet_uom"/>
<field name="unit_amount" string="Time Spent" type="measure" widget="timesheet_uom"/>
</graph>
</field>
</record>
<!-- For a single project Timesheet view, group by month then task -->
<record id="view_hr_timesheet_line_by_project" model="ir.ui.view">
<field name="name">account.analytic.line.graph.by.project</field>
<field name="model">account.analytic.line</field>
<field name="inherit_id" ref="hr_timesheet.view_hr_timesheet_line_graph_all"/>
<field name="mode">primary</field>
<field name="arch" type="xml">
<field name="project_id" position="replace"/>
<field name="employee_id" position="before">
<field name="date" interval="month"/>
<field name="task_id"/>
</field>
<field name="employee_id" position="attributes">
<attribute name="invisible">1</attribute>
</field>
</field>
</record>
<record id="view_hr_timesheet_line_graph_by_employee" model="ir.ui.view">
<field name="name">account.analytic.line.graph.by.employee</field>
<field name="model">account.analytic.line</field>
@ -137,34 +162,43 @@
<sheet string="Analytic Entry">
<group>
<group>
<field name="project_id" required="1"/>
<field name="task_id" widget="task_with_hours" context="{'default_project_id': project_id}"/>
<field name="name"/>
<field name="readonly_timesheet" invisible="1"/>
<field name="project_id" options="{'no_create_edit': True}"
context="{'search_default_my_projects': True}"
required="1"
readonly="readonly_timesheet"/>
<field name="task_id" widget="task_with_hours" options="{'no_create_edit': True}"
context="{'default_project_id': project_id, 'search_default_my_tasks': True, 'search_default_open_tasks': True}"
readonly="readonly_timesheet"/>
<field name="company_id" groups="base.group_multi_company" invisible="1"/>
</group>
<group>
<field name="date"/>
<field name="date" readonly="readonly_timesheet"/>
<field name="amount" invisible="1"/>
<field name="unit_amount" widget="timesheet_uom" decoration-danger="unit_amount &gt; 24"/>
<field name="unit_amount" string="Time Spent" widget="timesheet_uom" decoration-danger="unit_amount &gt; 24"
readonly="readonly_timesheet" decoration-muted="unit_amount == 0"/>
<field name="currency_id" invisible="1"/>
<field name="company_id" invisible="1"/>
</group>
</group>
<field name="name" placeholder="Describe your activity" widget="text" nolabel="1" required="0" readonly="readonly_timesheet"/>
</sheet>
</form>
</field>
</record>
<record id="timesheet_view_form_user" model="ir.ui.view">
<field name="name">account.analytic.line.tree.with.user</field>
<field name="name">account.analytic.line.list.with.user</field>
<field name="model">account.analytic.line</field>
<field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_form"/>
<field name="mode">primary</field>
<field name="priority">10</field>
<field name="arch" type="xml">
<xpath expr="//field[@name='date']" position="before">
<field name="employee_id" required="1" context="{'active_test': True}"/>
<field name="user_id" invisible="1"/>
<field name="employee_id" groups="hr_timesheet.group_hr_timesheet_approver" widget="many2one_avatar_employee"
required="1"
readonly="readonly_timesheet" context="{'active_test': True}"/>
<field name="user_id" invisible="1" groups="hr_timesheet.group_hr_timesheet_approver"/>
</xpath>
</field>
</record>
@ -172,29 +206,64 @@
<record id="hr_timesheet_line_search" model="ir.ui.view">
<field name="name">account.analytic.line.search</field>
<field name="model">account.analytic.line</field>
<field name="inherit_id" ref="analytic.view_account_analytic_line_filter"/>
<field name="arch" type="xml">
<search string="Timesheet">
<field name="date"/>
<field name="employee_id"/>
<field name="project_id"/>
<field name="ancestor_task_id" groups="project.group_subtask_project"/>
<field name="task_id"/>
<field name="name"/>
<field name="department_id"/>
<field name="manager_id"/>
<xpath expr="//filter[@name='month']" position="before">
<filter name="mine" string="My Timesheets" domain="[('user_id', '=', uid)]"/>
<separator/>
<filter name="month" string="Date" date="date"/>
<group expand="0" string="Group By">
<filter string="Project" name="groupby_project" domain="[]" context="{'group_by': 'project_id'}"/>
<filter string="Ancestor Task" name="groupby_parent_task" domain="[]" context="{'group_by': 'ancestor_task_id'}" groups="project.group_subtask_project"/>
<filter string="Task" name="groupby_task" domain="[]" context="{'group_by': 'task_id'}"/>
<filter string="Date" name="groupby_date" domain="[]" context="{'group_by': 'date'}" help="Timesheet by Date"/>
<filter string="Department" name="groupby_department" domain="[]" context="{'group_by': 'department_id'}"/>
<filter string="Manager" name="groupby_manager" domain="[]" context="{'group_by': 'manager_id'}"/>
<filter string="Employee" name="groupby_employee" domain="[]" context="{'group_by': 'employee_id'}"/>
</group>
</search>
</xpath>
<filter name="month" position="inside">
<filter name="date_this_week" string="This Week" domain="[
('date', '&gt;=', '=week_start'),
('date', '&lt;', '=week_start +1w'),
]"/>
<filter name="date_today" string="Today" domain="[('date', '&gt;=', 'today'), ('date', '&lt;', 'today +1d')]"/>
<filter name="date_last_week" string="Last Week" domain="[
('date', '&gt;=', '=week_start -1w'),
('date', '&lt;', '=week_start'),
]"/>
</filter>
<xpath expr="//group[@name='groupby']" position="before">
<field name="employee_id"/>
<field name="project_id"/>
<field name="task_id"/>
<field name="parent_task_id"/>
<field name="department_id"/>
<field name="manager_id"/>
</xpath>
<xpath expr="//group[@name='groupby']" position="inside">
<filter string="Project" name="groupby_project" domain="[]" context="{'group_by': 'project_id'}"/>
<filter string="Parent Task" name="groupby_parent_task" domain="[]" context="{'group_by': 'parent_task_id'}"/>
<filter string="Task" name="groupby_task" domain="[]" context="{'group_by': 'task_id'}"/>
<filter string="Department" name="groupby_department" domain="[]" context="{'group_by': 'department_id'}"/>
<filter string="Manager" name="groupby_manager" domain="[]" context="{'group_by': 'manager_id'}"/>
<filter string="Employee" name="groupby_employee" domain="[]" context="{'group_by': 'employee_id'}"/>
</xpath>
</field>
</record>
<record id="timesheet_view_form_portal_user" model="ir.ui.view">
<field name="name">account.analytic.line.form</field>
<field name="model">account.analytic.line</field>
<field name="inherit_id" ref="hr_timesheet.timesheet_view_form_user"/>
<field name="mode">primary</field>
<field name="priority">10</field>
<field name="arch" type="xml">
<xpath expr="//field[@name='employee_id']" position="attributes">
<attribute name="required">1</attribute>
<attribute name="widget">many2one_avatar_employee</attribute>
<attribute name="context">{'active_test': True}</attribute>
<attribute name="options">{'no_open': True}</attribute>
<attribute name="readonly">1</attribute>
</xpath>
<xpath expr="//field[@name='project_id']" position="attributes">
<attribute name="options">{'no_create_edit': True, 'no_open': True}</attribute>
<attribute name="readonly">1</attribute>
</xpath>
<xpath expr="//field[@name='task_id']" position="attributes">
<attribute name="options">{'no_create_edit': True, 'no_open': True}</attribute>
<attribute name="readonly">1</attribute>
</xpath>
</field>
</record>
@ -219,76 +288,133 @@
<field name="model">account.analytic.line</field>
<field name="arch" type="xml">
<kanban class="o_kanban_mobile" sample="1">
<field name="date"/>
<field name="employee_id"/>
<field name="user_id"/>
<field name="name"/>
<field name="project_id"/>
<field name="task_id" context="{'default_project_id': project_id}" domain="[('project_id', '=', project_id)]"/>
<field name="unit_amount" widget="timesheet_uom"/>
<field name="company_id" invisible="1"/>
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_global_click o_kanban_record_has_image_fill px-0 pb-0">
<div class="oe_kanban_details d-flex flex-column">
<div class="o_kanban_record_top px-2 h-50">
<img t-att-src="kanban_image('hr.employee', 'avatar_128', record.employee_id.raw_value)" t-att-title="record.employee_id.value" t-att-alt="record.employee_id.value" class="o_image_40_cover float-start"/>
<div class="o_kanban_record_headings ps-4 pe-2">
<div class="text-truncate">
<strong class="o_kanban_record_title">
<span t-esc="record.project_id.value" t-att-title="record.project_id.value"/>
</strong>
</div>
<div class="text-truncate">
<i><span t-esc="record.task_id.value" t-att-title="record.task_id.value"/></i>
</div>
<div class="text-truncate">
<span t-esc="record.name.value" t-att-title="record.name.value"/>
</div>
</div>
</div>
<div class="o_kanban_record_bottom d-block mx-2">
<hr class="mt4 mb4"/>
<span>
<i class="fa fa-calendar me-1" role="img" aria-label="Date" title="Date"></i>
<t t-esc="record.date.value"/>
</span>
<span class="float-end" name="duration">
<strong>Duration: </strong><field name="unit_amount" widget="timesheet_uom" decoration-danger="unit_amount &gt; 24"/>
</span>
</div>
<t t-name="card">
<div class="d-flex gap-1">
<span t-att-title="record.employee_id.value">
<field name="employee_id" widget="image" options="{'preview_image': 'avatar_128'}" class="o_image_64_cover me-2 float-start"/>
</span>
<div class="d-flex flex-column min-w-0 lh-sm">
<span class="text-truncate" invisible="context.get('default_project_id')" t-att-title="record.project_id.value">
<field name="project_id" class="p-0 fw-bold fs-5"/>
</span>
<span name="task_id_wrapper" class="text-truncate" t-att-title="record.task_id.value">
<field name="task_id" invisible="context.get('default_project_id')"/>
<field name="task_id" invisible="not context.get('default_project_id')" class="p-0 fw-bold fs-5"/>
</span>
<span>
<i class="fa fa-calendar me-1" role="img" aria-label="Date" title="Date"></i>
<field name="date"/><span invisible="context.get('is_my_timesheets')"> - <field name="employee_id"/></span>
</span>
<span class="text-truncate" t-att-title="record.name.value"><field name="name" class="fst-italic"/></span>
</div>
</div>
<footer class="mt-0 pt-0">
<div class="d-flex ms-auto">
<strong><field name="unit_amount" widget="timesheet_duration_uom" decoration-danger="unit_amount &gt; 24" decoration-muted="unit_amount == 0" class="ms-1"/></strong>
</div>
</footer>
</t>
</templates>
</kanban>
</field>
</record>
<record id="view_calendar_account_analytic_line" model="ir.ui.view">
<field name="name">account.analytic.line.calendar</field>
<field name="model">account.analytic.line</field>
<field name="arch" type="xml">
<calendar
scales="month"
mode="month"
date_start="date"
color="employee_id"
show_unusual_days="True"
multi_create_view="hr_timesheet.view_calendar_account_analytic_line_multi_create"
js_class="timesheet_calendar"
create_name_field="calendar_display_name"
form_view_id="%(hr_timesheet.hr_timesheet_line_form)d"
>
<field name="employee_id" avatar_field="avatar_128" widget="many2one_avatar_employee"/>
<field name="project_id"/>
<field name="task_id" invisible="not task_id"/>
<field name="name"/>
<field name="employee_id" avatar_field="avatar_128" filters="1" write_model="account.analytic.line.calendar.employee" write_field="employee_id" filter_field="checked"/>
</calendar>
</field>
</record>
<record id="view_calendar_account_analytic_line_multi_create" model="ir.ui.view">
<field name="name">account.analytic.line.calendar.multi_create</field>
<field name="model">account.analytic.line</field>
<field name="arch" type="xml">
<form>
<group>
<field name="project_id" options="{'no_create_edit': True}"
context="{'search_default_my_projects': True}" required="1"/>
<field name="task_id" widget="task_with_hours"
context="{'default_project_id': project_id, 'search_default_my_tasks': True, 'search_default_open_tasks': True}"/>
<field name="unit_amount" string="Time Spent" widget="timesheet_uom" decoration-danger="unit_amount &gt; 24"
decoration-muted="unit_amount == 0"/>
<field name="name" required="0" placeholder="e.g. Sending E-mails"/>
</group>
</form>
</field>
</record>
<record id="view_calendar_account_analytic_line_my_timesheets" model="ir.ui.view">
<field name="name">account.analytic.line.calendar</field>
<field name="model">account.analytic.line</field>
<field name="inherit_id" ref="hr_timesheet.view_calendar_account_analytic_line"/>
<field name="mode">primary</field>
<field name="arch" type="xml">
<calendar position="attributes">
<attribute name="color">project_id</attribute>
<attribute name="js_class">timesheet_calendar_my_timesheets</attribute>
</calendar>
<field name="employee_id" position="replace"/>
<field name="employee_id" filters="1" position="replace"/>
</field>
</record>
<record id="view_kanban_account_analytic_line_portal_user" model="ir.ui.view">
<field name="name">portal.account.analytic.line.kanban</field>
<field name="model">account.analytic.line</field>
<field name="inherit_id" ref="hr_timesheet.view_kanban_account_analytic_line"/>
<field name="mode">primary</field>
<field name="priority">10</field>
<field name="arch" type="xml">
<xpath expr="//div/span" position="replace" class="ps-0"/>
</field>
</record>
<!--
Menus and Actions
Actions
-->
<record id="act_hr_timesheet_line" model="ir.actions.act_window">
<field name="name">My Timesheets</field>
<field name="path">timesheets</field>
<field name="res_model">account.analytic.line</field>
<field name="view_mode">tree,form,kanban,pivot,graph</field>
<field name="view_mode">list,form,kanban,pivot,graph</field>
<field name="domain">[('project_id', '!=', False), ('user_id', '=', uid)]</field>
<field name="context">{
"search_default_week":1,
"is_timesheet": 1,
"is_my_timesheets": 1,
}</field>
<field name="search_view_id" ref="hr_timesheet_line_my_timesheet_search"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No timesheets found. Let's create one!
No activities found. Let's start a new one!
</p>
<p>
Keep track of your working hours by project every day and bill your customers for that time.
Track your working hours by projects every day and invoice this time to your customers.
</p>
</field>
</record>
<record id="act_hr_timesheet_line_view_tree" model="ir.actions.act_window.view">
<field name="view_mode">tree</field>
<field name="view_mode">list</field>
<field name="sequence" eval="4"/>
<field name="view_id" ref="hr_timesheet_line_tree"/>
<field name="act_window_id" ref="act_hr_timesheet_line"/>
@ -301,6 +427,13 @@
<field name="act_window_id" ref="act_hr_timesheet_line"/>
</record>
<record id="act_hr_timesheet_line_view_calendar" model="ir.actions.act_window.view">
<field name="view_mode">calendar</field>
<field name="sequence" eval="5"/>
<field name="view_id" ref="view_calendar_account_analytic_line_my_timesheets"/>
<field name="act_window_id" ref="act_hr_timesheet_line"/>
</record>
<record id="act_hr_timesheet_line_view_kanban" model="ir.actions.act_window.view">
<field name="view_mode">kanban</field>
<field name="sequence">6</field>
@ -310,30 +443,18 @@
<record id="act_hr_timesheet_line_view_pivot" model="ir.actions.act_window.view">
<field name="view_mode">pivot</field>
<field name="sequence">7</field>
<field name="view_id" ref="hr_timesheet.view_my_timesheet_line_pivot"/>
<field name="sequence" eval="7"/>
<field name="view_id" ref="view_my_timesheet_line_pivot"/>
<field name="act_window_id" ref="act_hr_timesheet_line"/>
</record>
<record id="act_hr_timesheet_line_view_graph" model="ir.actions.act_window.view">
<field name="view_mode">graph</field>
<field name="sequence">8</field>
<field name="view_id" ref="hr_timesheet.view_hr_timesheet_line_graph_my"/>
<field name="sequence" eval="8"/>
<field name="view_id" ref="view_hr_timesheet_line_graph_my"/>
<field name="act_window_id" ref="act_hr_timesheet_line"/>
</record>
<menuitem id="timesheet_menu_activity_mine"
name="My Timesheets"
groups="group_hr_timesheet_approver"
parent="menu_hr_time_tracking"
action="act_hr_timesheet_line"/>
<menuitem id="timesheet_menu_activity_user"
name="My Timesheets"
groups="group_hr_timesheet_user"
parent="timesheet_menu_root"
action="act_hr_timesheet_line"/>
<record id="timesheet_action_task" model="ir.actions.act_window">
<field name="name">Task's Timesheets</field>
<field name="res_model">account.analytic.line</field>
@ -341,7 +462,7 @@
'is_timesheet': 1,
}</field>
<field name="domain">[('task_id', 'in', active_ids)]</field>
<field name="view_mode">tree</field>
<field name="view_mode">list</field>
<field name="view_id" ref="timesheet_view_tree_user"/>
</record>
@ -352,14 +473,15 @@
'is_timesheet': 1,
}</field>
<field name="domain">[('project_id', 'in', active_ids)]</field>
<field name="view_mode">tree</field>
<field name="view_mode">list</field>
<field name="view_id" ref="timesheet_view_tree_user"/>
</record>
<record id="timesheet_action_all" model="ir.actions.act_window">
<field name="name">All Timesheets</field>
<field name="res_model">account.analytic.line</field>
<field name="view_mode">tree,form,kanban,pivot,graph</field>
<field name="path">all-timesheets</field>
<field name="view_mode">list,form,kanban,pivot,graph</field>
<field name="search_view_id" ref="hr_timesheet_line_search"/>
<field name="domain">[('project_id', '!=', False)]</field>
<field name="context">{
@ -368,17 +490,17 @@
}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No timesheets found. Let's create one!
No activities found. Let's start a new one!
</p>
<p>
Keep track of your working hours by project every day and bill your customers for that time.
Track your working hours by projects every day and invoice this time to your customers.
</p>
</field>
</record>
<record id="timesheet_action_view_all_tree" model="ir.actions.act_window.view">
<field name="sequence" eval="4"/>
<field name="view_mode">tree</field>
<field name="view_mode">list</field>
<field name="view_id" ref="timesheet_view_tree_user"/>
<field name="act_window_id" ref="timesheet_action_all"/>
</record>
@ -390,6 +512,13 @@
<field name="act_window_id" ref="timesheet_action_all"/>
</record>
<record id="timesheet_action_view_all_calendar" model="ir.actions.act_window.view">
<field name="sequence" eval="5"/>
<field name="view_mode">calendar</field>
<field name="view_id" ref="view_calendar_account_analytic_line"/>
<field name="act_window_id" ref="timesheet_action_all"/>
</record>
<record id="timesheet_action_view_all_kanban" model="ir.actions.act_window.view">
<field name="view_mode">kanban</field>
<field name="sequence">6</field>
@ -411,11 +540,104 @@
<field name="act_window_id" ref="timesheet_action_all"/>
</record>
<menuitem id="timesheet_menu_activity_all"
name="All Timesheets"
parent="menu_hr_time_tracking"
action="timesheet_action_all"
groups="hr_timesheet.group_hr_timesheet_approver"/>
<record id="timesheet_action_from_employee" model="ir.actions.act_window">
<field name="name">Timesheets</field>
<field name="res_model">account.analytic.line</field>
<field name="search_view_id" ref="hr_timesheet_line_search"/>
<field name="domain">[('project_id', '!=', False), ('employee_id', '=', active_id)]</field>
<field name="context">{
'default_employee_id': active_id,
"is_timesheet": 1,
}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Record a new activity
</p><p>
You can register and track your workings hours by project every
day. Every time spent on a project will become a cost and can be re-invoiced to
customers if required.
</p>
</field>
</record>
<record id="act_hr_timesheet_line_by_project" model="ir.actions.act_window">
<field name="name">Timesheets</field>
<field name="res_model">account.analytic.line</field>
<field name="path">project-timesheets</field>
<field name="view_mode">list,kanban,pivot,graph,form</field>
<field name="view_id" ref="timesheet_view_tree_user"/>
<field name="domain">[('project_id', '=', active_id)]</field>
<field name="context">{
"default_project_id": active_id,
"is_timesheet": 1,
}</field>
<field name="search_view_id" ref="hr_timesheet_line_search"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Record a new activity
</p><p>
Track your working hours by projects every day and invoice this time to your customers.
</p>
</field>
</record>
<record id="project_embedded_action_timesheets" model="ir.embedded.actions">
<field name="parent_res_model">project.project</field>
<field name="sequence">20</field>
<field name="parent_action_id" ref="project.act_project_project_2_project_task_all"/>
<field name="action_id" eval="False"/>
<field name="name">Timesheets</field>
<field name="python_method">action_project_timesheets</field>
<field name="domain">[('allow_timesheets', '=', True)]</field>
<field name="context">{'from_embedded_action': true}</field>
<field name="groups_ids" eval="[(4, ref('hr_timesheet.group_hr_timesheet_user'))]" />
</record>
<record id="project_embedded_action_timesheets_dashboard" model="ir.embedded.actions">
<field name="parent_res_model">project.project</field>
<field name="sequence">30</field>
<field name="parent_action_id" ref="project.project_update_all_action"/>
<field name="action_id" eval="False"/>
<field name="name">Timesheets</field>
<field name="python_method">action_project_timesheets</field>
<field name="domain">[('allow_timesheets', '=', True)]</field>
<field name="context">{'from_embedded_action': true}</field>
<field name="groups_ids" eval="[(4, ref('hr_timesheet.group_hr_timesheet_user'))]" />
</record>
<record id="act_hr_timesheet_line_by_project_view_tree" model="ir.actions.act_window.view">
<field name="view_mode">list</field>
<field name="sequence" eval="1"/>
<field name="view_id" ref="timesheet_view_tree_user"/>
<field name="act_window_id" ref="act_hr_timesheet_line_by_project"/>
</record>
<record id="act_hr_timesheet_line_by_project_view_kanban" model="ir.actions.act_window.view">
<field name="view_mode">kanban</field>
<field name="sequence" eval="2"/>
<field name="view_id" ref="view_kanban_account_analytic_line"/>
<field name="act_window_id" ref="act_hr_timesheet_line_by_project"/>
</record>
<record id="act_hr_timesheet_line_by_project_view_pivot" model="ir.actions.act_window.view">
<field name="view_mode">pivot</field>
<field name="sequence" eval="3"/>
<field name="view_id" ref="view_hr_timesheet_line_pivot"/>
<field name="act_window_id" ref="act_hr_timesheet_line_by_project"/>
</record>
<record id="act_hr_timesheet_line_by_project_view_graph" model="ir.actions.act_window.view">
<field name="view_mode">graph</field>
<field name="sequence" eval="4"/>
<field name="view_id" ref="view_hr_timesheet_line_by_project"/>
<field name="act_window_id" ref="act_hr_timesheet_line_by_project"/>
</record>
<record id="act_hr_timesheet_line_by_project_view_form" model="ir.actions.act_window.view">
<field name="view_mode">form</field>
<field name="sequence" eval="10"/>
<field name="view_id" ref="hr_timesheet_line_form"/>
<field name="act_window_id" ref="act_hr_timesheet_line_by_project"/>
</record>
</data>
</odoo>

View file

@ -1,63 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="timesheet_action_from_employee" model="ir.actions.act_window">
<field name="name">Timesheets</field>
<field name="res_model">account.analytic.line</field>
<field name="search_view_id" ref="hr_timesheet_line_search"/>
<field name="domain">[('project_id', '!=', False)]</field>
<field name="context">{
'search_default_month':1,
'search_default_employee_id': [active_id],
'default_employee_id': active_id,
"is_timesheet": 1,
}</field>
</record>
<record id="timesheet_action_view_from_employee_list" model="ir.actions.act_window.view">
<field name="sequence" eval="5"/>
<field name="view_mode">tree</field>
<field name="view_id" ref="hr_timesheet_line_tree"/>
<field name="act_window_id" ref="timesheet_action_from_employee"/>
</record>
<record id="timesheet_action_view_from_employee_form" model="ir.actions.act_window.view">
<field name="sequence" eval="10"/>
<field name="view_mode">form</field>
<field name="view_id" ref="hr_timesheet_line_form"/>
<field name="act_window_id" ref="timesheet_action_from_employee"/>
</record>
<record id="hr_employee_view_form_inherit_timesheet" model="ir.ui.view">
<field name="name">hr.employee.form.timesheet</field>
<field name="model">hr.employee</field>
<field name="inherit_id" ref="hr_hourly_cost.view_employee_form"/>
<field name="priority" eval="40"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside">
<button class="oe_stat_button" type="action" name="%(timesheet_action_from_employee)d" icon="fa-calendar" groups="hr_timesheet.group_hr_timesheet_user">
<div class="o_stat_info">
<span class="o_stat_text">Timesheets</span>
</div>
</button>
</xpath>
</field>
</record>
<record id="hr_department_view_kanban" model="ir.ui.view">
<field name="name">hr.department.kanban.inherit</field>
<field name="model">hr.department</field>
<field name="inherit_id" ref="hr.hr_department_view_kanban"/>
<field name="arch" type="xml">
<data>
<xpath expr="//div[hasclass('o_kanban_manage_reports')]" position="inside">
<a name="%(act_hr_timesheet_report)d" type="action"
groups="hr_timesheet.group_timesheet_manager" class="dropdown-item"
context="{ 'search_default_department_id': [active_id], 'default_department_id': active_id}">
Timesheets
</a>
</xpath>
</data>
</field>
</record>
</odoo>

View file

@ -1,114 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="portal_my_task" inherit_id="project.portal_my_task" name="Portal: My Task with Timesheets">
<xpath expr="//li[@id='task-nav']" position="before">
<li t-if="timesheets and allow_timesheets" class="list-group-item d-grid flex-grow-1" id='nav-report'>
<div class="o_download_pdf d-flex gap-1">
<a class="btn btn-secondary flex-fill o_download_btn" t-att-href="task.get_portal_url(report_type='pdf', download=True)" title="Download"><i class="fa fa-download"/> Download</a>
<a class="btn btn-secondary flex-fill o_print_btn o_project_timesheet_print" t-att-href="task.get_portal_url(report_type='pdf')" href="#" title="Print" target="_blank"><i class="fa fa-print"/> Print</a>
</div>
</li>
</xpath>
<xpath expr="//li[@id='nav-header']" position="after">
<li t-if="timesheets and allow_timesheets" class="nav-item">
<a class="nav-link ps-3" href="#task_timesheets">
Timesheets
</a>
</li>
</xpath>
<xpath expr="//div[@id='card_body']" position="inside">
<div class="container" t-if="timesheets and allow_timesheets">
<hr class="mt-4 mb-1"/>
<h5 id="task_timesheets" class="mt-2 mb-2" data-anchor="true">Timesheets</h5>
<t t-call="hr_timesheet.portal_timesheet_table"/>
</div>
</xpath>
<xpath expr="//div[@name='portal_my_task_planned_hours']" position="after">
<div t-if="task.planned_hours > 0"><strong>Progress:</strong> <span t-field="task.progress"/>%</div>
</xpath>
<xpath expr="//div[@name='portal_my_task_planned_hours']/t" position="replace">
<t t-call="hr_timesheet.portal_my_task_planned_hours_template"></t>
</xpath>
</template>
<template id="portal_my_task_planned_hours_template">
<t t-if="is_uom_day and timesheets._convert_hours_to_days(task.planned_hours) > 0">
<strong>Allocated Days:</strong> <span t-esc="timesheets._convert_hours_to_days(task.planned_hours)" t-options='{"widget": "timesheet_uom"}'/>
</t>
<t t-if="not is_uom_day and task.planned_hours > 0" t-call="project.portal_my_task_planned_hours_template"></t>
</template>
<template id="portal_tasks_list_inherit" inherit_id="project.portal_tasks_list" name="Portal: My Tasks with Timesheets">
<xpath expr="//t[@t-foreach='tasks']/tr" position="before">
<t t-set="timesheet_ids" t-value="task.sudo().timesheet_ids"/>
<t t-set="is_uom_day" t-value="timesheet_ids._is_timesheet_encode_uom_day()"/>
</xpath>
<xpath expr="//thead/tr/t[@t-set='number_of_header']" position="attributes">
<attribute name="t-value">9</attribute>
</xpath>
<xpath expr="//thead/tr/th[@name='project_portal_milestones']" position="after">
<th t-if="is_uom_day" class="text-end">Days Spent</th>
<th t-else="" class="text-end">Hours Spent</th>
</xpath>
<xpath expr="//tbody/t/tr/td[@name='project_portal_milestones']" position="after">
<td class="text-end">
<t t-if="is_uom_day">
<t t-out="timesheet_ids._convert_hours_to_days(task.effective_hours)"/>
<span t-if="task.planned_hours > 0"> / <t t-out="timesheet_ids._convert_hours_to_days(task.planned_hours)"/></span>
</t>
<t t-else="">
<span t-field="task.effective_hours" t-options='{"widget": "float_time"}'/>
<t t-if="task.planned_hours > 0">
/
<span t-field="task.planned_hours" t-options='{"widget": "float_time"}'/>
</t>
</t>
</td>
</xpath>
</template>
<template id="portal_timesheet_table" name="Portal Timesheet Table">
<table class="o_portal_my_doc_table table table-sm">
<thead>
<tr>
<th>Date</th>
<th>Employee</th>
<th>Description</th>
<th t-if="is_uom_day" class="text-end">Days Spent</th>
<th t-else="" class="text-end">Hours Spent</th>
</tr>
</thead>
<tr t-foreach="timesheets" t-as="timesheet">
<td><t t-esc="timesheet.date" t-options='{"widget": "date"}'/></td>
<td t-attf-title="#{timesheet.employee_id.name}"><t t-esc="timesheet.employee_id.name"/></td>
<td><t t-esc="timesheet.name"/></td>
<td class="text-end">
<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"}'/>
</td>
</tr>
<tfoot>
<tr>
<th colspan="3"></th>
<th class="text-end">
<t t-set="timesheets_amount" t-value="round(sum(timesheets.mapped('unit_amount')), 2) or 0.0"></t>
<div t-if="is_uom_day"><strong>Days Spent:</strong> <span t-esc="timesheets._convert_hours_to_days(timesheets_amount)" t-options='{"widget": "timesheet_uom"}'/></div>
<div t-else=""><strong>Hours Spent:</strong> <span t-esc="timesheets_amount" t-options='{"widget": "float_time"}'/></div>
<t t-set="timesheets_by_subtask_amount" t-value="round(sum(sum(timesheet_by_subtask.mapped('unit_amount') or 0.0) for timesheet_by_subtask in timesheets_by_subtask.values()), 2) or 0.0"></t>
<div t-if="timesheets_by_subtask">
<div t-if="is_uom_day">Days recorded on sub-tasks: <span t-esc="timesheets._convert_hours_to_days(timesheets_by_subtask_amount)" t-options='{"widget": "timesheet_uom"}'/></div>
<div t-else="">Hours recorded on sub-tasks: <span t-esc="timesheets_by_subtask_amount" t-options='{"widget": "float_time"}'/></div>
</div>
<t t-set="planned_time" t-value="task.planned_hours"></t>
<div t-if="planned_time > 0" name="planned_time" t-attf-class="{{task.remaining_hours &lt; 0 and 'text-danger' or ''}}">
<div t-if="is_uom_day">Remaining Days: <span t-esc="timesheets._convert_hours_to_days(planned_time - timesheets_amount - timesheets_by_subtask_amount)" t-options='{"widget": "timesheet_uom"}'/></div>
<div t-else="">Remaining Hours: <span t-esc="planned_time - timesheets_amount - timesheets_by_subtask_amount" t-options='{"widget": "float_time"}'/></div>
</div>
</th>
</tr>
</tfoot>
</table>
</template>
</odoo>

View file

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="project_project_view_form_simplified_inherit_timesheet" model="ir.ui.view">
<field name="name">project.project.view.form.simplified.inherit.timesheet</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.project_project_view_form_simplified"/>
<field name="priority">24</field>
<field name="arch" type="xml">
<xpath expr="//div[hasclass('o_settings_container')]" position="inside">
<setting string="Timesheets" help="Log time on tasks">
<field name="allow_timesheets"/>
</setting>
</xpath>
</field>
</record>
<record id="project_invoice_form" model="ir.ui.view">
<field name="name">Inherit project form : Invoicing Data</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.edit_project"/>
<field name="priority">24</field>
<field name="arch" type="xml">
<xpath expr="//header" position="after">
<field name="analytic_account_active" invisible="1"/>
<t name="timesheet_error" invisible="not allow_timesheets or is_template">
<div class="alert alert-warning mb-1 text-center" role="alert" colspan="2" invisible="not account_id or analytic_account_active">
You cannot log timesheets on this project since it is linked to an inactive analytic account.<br/>
Please switch to another account, or reactivate the current one to timesheet on the project.
</div>
</t>
</xpath>
<xpath expr="//field[@name='date']" position="after">
<field name="allocated_hours" widget="timesheet_uom_no_toggle" invisible="not allow_timesheets" groups="hr_timesheet.group_hr_timesheet_user"/>
</xpath>
<xpath expr="//group[@name='group_time_managment']" position="attributes">
<attribute name="invisible">0</attribute>
</xpath>
<xpath expr="//group[@name='group_time_managment']" position="inside">
<setting class="col-lg-12" id="timesheet_settings" string="Timesheets" help="Log time on tasks">
<field name="allow_timesheets"/>
</setting>
</xpath>
</field>
</record>
<record id="project_project_view_tree_inherit_sale_project" model="ir.ui.view">
<field name="name">project.project.list.inherit.sale.timesheet</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.view_project"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='date']" position="after">
<field name="allow_timesheets" column_invisible="1"/>
<field name="allocated_hours" widget="timesheet_uom_no_toggle" optional="hide" invisible="allocated_hours == 0 or not allow_timesheets" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="effective_hours" widget="timesheet_uom_no_toggle" optional="hide" invisible="effective_hours == 0 or not allow_timesheets" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="remaining_hours" widget="timesheet_uom_no_toggle"
decoration-danger="remaining_hours &lt; 0"
decoration-warning="allocated_hours > 0 and (remaining_hours / allocated_hours) &lt; 0.2"
optional="hide"
invisible="allocated_hours == 0 or not allow_timesheets"
groups="hr_timesheet.group_hr_timesheet_user"
/>
</xpath>
</field>
</record>
<record id="view_project_kanban_inherited" model="ir.ui.view">
<field name="name">project.project.timesheet.kanban.inherited</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.view_project_kanban"/>
<field name="priority">24</field>
<field name="arch" type="xml">
<xpath expr="//templates" position="before">
<field name="allow_timesheets"/>
<field name="remaining_hours"/>
<field name="encode_uom_in_days"/>
<field name="allocated_hours"/>
</xpath>
<xpath expr="//div[@name='card_menu_view']" position="inside">
<div role="menuitem" t-if="record.allow_timesheets.raw_value and !record.is_template.raw_value" groups="hr_timesheet.group_hr_timesheet_user">
<a name="action_project_timesheets" type="object">Timesheets</a>
</div>
</xpath>
<xpath expr="//div[hasclass('o_project_kanban_boxes')]" position="after">
<t t-set="badgeColor" t-value="'border-success'"/>
<t t-set="badgeColor" t-value="'border-danger'" t-if="record.remaining_hours.raw_value &lt; 0"/>
<t t-set="title" t-if="record.encode_uom_in_days.raw_value">Days Remaining</t>
<t t-set="title" t-else="">Time Remaining</t>
<div t-if="!record.is_template.raw_value and record.allow_timesheets.raw_value and record.allocated_hours.raw_value &gt; 0"
t-attf-class="me-1 ms-1 bg-transparent badge border {{ badgeColor }}" t-att-title="title" groups="hr_timesheet.group_hr_timesheet_user">
<field name="remaining_hours" widget="timesheet_uom" class="p-0"/>
</div>
</xpath>
</field>
</record>
<record id="view_project_project_filter_inherit_timesheet" model="ir.ui.view">
<field name="name">project.project.view.inherit.timesheet</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.view_project_project_filter"/>
<field name="arch" type="xml">
<filter name="late_milestones" position="before">
<filter string="Timesheets &gt;100%" name="projects_in_overtime" domain="[('is_project_overtime', '=', True)]" groups="project.group_project_manager"/>
</filter>
</field>
</record>
<record id="project.open_view_project_all" model="ir.actions.act_window">
<field name="domain">[('is_internal_project', '=', False), ("is_template", "=", False)]</field>
</record>
<record id="project.open_view_project_all_group_stage" model="ir.actions.act_window">
<field name="domain">[('is_internal_project', '=', False), ("is_template", "=", False)]</field>
</record>
<!-- Project Template -->
<record id="project_templates_view_list_inherit_timesheet" model="ir.ui.view">
<field name="name">project.project.template.list.inherit.timesheet</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.project_templates_view_list"/>
<field name="arch" type="xml">
<field name="effective_hours" position="replace"/>
<field name="remaining_hours" position="replace"/>
</field>
</record>
</data>
</odoo>

View file

@ -1,177 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="project_sharing_inherit_project_task_view_form" model="ir.ui.view">
<field name="name">project.sharing.project.task.view.form.inherit</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.project_sharing_project_task_view_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='child_ids']/tree/field[@name='portal_user_names']" position="after">
<field name="planned_hours" widget="timesheet_uom_no_toggle" sum="Initially Planned Hours" optional="hide"/>
<field name="effective_hours" widget="timesheet_uom" sum="Effective Hours" optional="hide"/>
<field name="subtask_effective_hours" string="Sub-tasks Hours Spent" widget="timesheet_uom" sum="Sub-tasks Hours Spent" optional="hide"/>
<field name="total_hours_spent" string="Total Hours" widget="timesheet_uom" sum="Total Hours" optional="hide"/>
<field name="remaining_hours" widget="timesheet_uom" sum="Remaining Hours" optional="hide" decoration-danger="progress &gt;= 100" decoration-warning="progress &gt;= 80 and progress &lt; 100"/>
<field name="progress" widget="progressbar" optional="hide"/>
</xpath>
<xpath expr="//notebook/page[@name='description_page']" position="after">
<field name="analytic_account_active" invisible="1"/>
<field name="allow_timesheets" invisible="1"/>
<field name="encode_uom_in_days" invisible="1"/>
<field name="subtask_count" invisible="1"/>
<page string="Timesheets" id="timesheets_tab" attrs="{'invisible': [('allow_timesheets', '=', False)]}">
<group>
<group>
<div colspan="2">
<label for="planned_hours" string="Allocated Hours" class="me-2" attrs="{'invisible': [('encode_uom_in_days', '=', True)]}"/>
<label for="planned_hours" string="Allocated Days" class="me-2" attrs="{'invisible': [('encode_uom_in_days', '=', False)]}"/>
<field name="planned_hours" class="o_field_float_time oe_inline ms-2" widget="timesheet_uom_no_toggle"/>
<span attrs="{'invisible': ['|', ('allow_subtasks', '=', False), ('subtask_count', '=', 0)]}">
(incl. <field name="subtask_planned_hours" nolabel="1" groups="project.group_subtask_project" widget="timesheet_uom_no_toggle" class="oe_inline"/> on
<span class="fw-bold text-dark"> Sub-tasks</span>)
</span>
</div>
</group>
<group>
<field name="progress" widget="progressbar"/>
</group>
</group>
<field name="timesheet_ids" mode="tree,kanban"
attrs="{'invisible': [('analytic_account_active', '=', False)]}">
<tree string="Timesheet Activities" default_order="date" no_open="1" create="false" delete="0">
<field name="date"/>
<field name="employee_id"/>
<field name="name"/>
<field name="unit_amount" widget="timesheet_uom" decoration-danger="unit_amount &gt; 24"/>
</tree>
<kanban class="o_kanban_mobile">
<field name="date"/>
<field name="employee_id"/>
<field name="name"/>
<field name="unit_amount" decoration-danger="unit_amount &gt; 24"/>
<field name="project_id"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_card oe_kanban_global_click">
<div class="row">
<div class="col-6">
<strong><span><t t-esc="record.employee_id.value"/></span></strong>
</div>
<div class="col-6 float-end text-end">
<strong><t t-esc="record.date.value"/></strong>
</div>
</div>
<div class="row">
<div class="col-6 text-muted">
<span><t t-esc="record.name.value"/></span>
</div>
<div class="col-6">
<span class="float-end text-end">
<field name="unit_amount" widget="float_time"/>
</span>
</div>
</div>
</div>
</t>
</templates>
</kanban>
</field>
<group attrs="{'invisible': [('analytic_account_active', '=', False)]}">
<group class="oe_subtotal_footer oe_right" name="project_hours">
<span class="o_td_label float-start">
<label class="fw-bold" for="effective_hours" string="Hours Spent" attrs="{'invisible': [('encode_uom_in_days', '=', True)]}"/>
<label class="fw-bold" for="effective_hours" string="Days Spent" attrs="{'invisible': [('encode_uom_in_days', '=', False)]}"/>
</span>
<field name="effective_hours" widget="timesheet_uom" nolabel="1"/>
<!-- remove o_form_subtask_button class from master-->
<button name="action_view_subtask_timesheet" type="object" class="o_form_subtask_button ps-0 border-0 oe_inline oe_link mb-2 o_td_label float-start" attrs="{'invisible' : ['|', ('allow_subtasks', '=', False), ('subtask_effective_hours', '=', 0.0)]}">
<span class="text-nowrap" attrs="{'invisible' : [('encode_uom_in_days', '=', True)]}">Hours Spent on Sub-tasks:</span>
<span class="text-nowrap" attrs="{'invisible' : [('encode_uom_in_days', '=', False)]}">Days Spent on Sub-tasks:</span>
</button>
<field name="subtask_effective_hours" class="mt-2" widget="timesheet_uom"
attrs="{'invisible' : ['|', ('allow_subtasks', '=', False), ('subtask_effective_hours', '=', 0.0)]}" nolabel="1"/>
<span id="total_hours_spent_label" attrs="{'invisible': ['|', ('allow_subtasks', '=', False), ('subtask_effective_hours', '=', 0.0)]}" class="o_td_label float-start">
<label class="fw-bold" for="total_hours_spent" string="Total Hours"
attrs="{'invisible': [('encode_uom_in_days', '=', True)]}"/>
<label class="fw-bold" for="total_hours_spent" string="Total Days"
attrs="{'invisible': [('encode_uom_in_days', '=', False)]}"/>
</span>
<field name="total_hours_spent" widget="timesheet_uom" class="oe_subtotal_footer_separator" nolabel="1"
attrs="{'invisible' : ['|', ('allow_subtasks', '=', False), ('subtask_effective_hours', '=', 0.0)]}" />
<span class="o_td_label float-start">
<label class="fw-bold" for="remaining_hours" string="Remaining Hours"
attrs="{'invisible': ['|', '|', ('planned_hours', '=', 0.0), ('encode_uom_in_days', '=', True), ('remaining_hours', '&lt;', 0)]}"/>
<label class="fw-bold" for="remaining_hours" string="Remaining Days"
attrs="{'invisible': ['|', '|', ('planned_hours', '=', 0.0), ('encode_uom_in_days', '=', False), ('remaining_hours', '&lt;', 0)]}"/>
<label class="fw-bold text-danger" for="remaining_hours" string="Remaining Hours"
attrs="{'invisible': ['|', '|', ('planned_hours', '=', 0.0), ('encode_uom_in_days', '=', True), ('remaining_hours', '&gt;=', 0)]}"/>
<label class="fw-bold text-danger" for="remaining_hours" string="Remaining Days"
attrs="{'invisible': ['|', '|', ('planned_hours', '=', 0.0), ('encode_uom_in_days', '=', False), ('remaining_hours', '&gt;=', 0)]}"/>
</span>
<field name="remaining_hours" widget="timesheet_uom" class="oe_subtotal_footer_separator"
attrs="{'invisible' : [('planned_hours', '=', 0.0)]}" nolabel="1"/>
</group>
</group>
</page>
</xpath>
</field>
</record>
<record id="project_sharing_kanban_inherit_project_task_view_kanban" model="ir.ui.view">
<field name="name">project.sharing.project.task.timesheet.kanban.inherited</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.project_sharing_project_task_view_kanban"/>
<field name="arch" type="xml">
<templates position="before">
<field name="progress" />
<field name="remaining_hours" />
<field name="planned_hours" />
<field name="allow_timesheets"/>
<field name="encode_uom_in_days" invisible="1"/>
</templates>
<div class="oe_kanban_bottom_left" position="inside">
<t name="planned_hours" t-if="record.planned_hours.raw_value &gt; 0 and record.allow_timesheets.raw_value">
<t t-set="badge" t-value="'border border-success'"/>
<t t-set="badge" t-value="'border border-warning'" t-if="record.progress.raw_value &gt;= 80 and record.progress.raw_value &lt;= 100"/>
<t t-set="badge" t-value="'border border-danger'" t-if="record.remaining_hours.raw_value &lt; 0"/>
<t t-set="title" t-value="'Remaining days'" t-if="record.encode_uom_in_days.raw_value"/>
<t t-set="title" t-value="'Remaining hours'" t-else=""/>
<div t-attf-class="oe_kanban_align badge {{ badge }}" t-att-title="title">
<field name="remaining_hours" widget="timesheet_uom" />
</div>
</t>
</div>
</field>
</record>
<record id="project_sharing_inherit_project_task_view_tree" model="ir.ui.view">
<field name="name">project.task.tree.inherited</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.project_sharing_project_task_view_tree" />
<field name="arch" type="xml">
<field name="portal_user_names" position="after">
<field name="allow_subtasks" invisible="1"/>
<field name="allow_timesheets" invisible="1"/>
<field name="planned_hours" widget="timesheet_uom_no_toggle" sum="Initially Planned Hours" optional="hide" attrs="{'column_invisible': [('allow_timesheets', '=', False)]}"/>
<field name="effective_hours" widget="timesheet_uom" sum="Effective Hours" optional="hide" attrs="{'column_invisible': [('allow_timesheets', '=', False)]}"/>
<field name="subtask_effective_hours" widget="timesheet_uom" attrs="{'column_invisible' : ['|', ('allow_subtasks', '=', False), ('allow_timesheets', '=', False)]}" optional="hide"/>
<field name="total_hours_spent" widget="timesheet_uom" attrs="{'column_invisible' : ['|', ('allow_subtasks', '=', False), ('allow_timesheets', '=', False)]}" optional="hide"/>
<field name="remaining_hours" widget="timesheet_uom" sum="Remaining Hours" optional="hide" decoration-danger="progress &gt;= 100" decoration-warning="progress &gt;= 80 and progress &lt; 100" attrs="{'column_invisible': [('allow_timesheets', '=', False)]}"/>
<field name="progress" widget="progressbar" attrs="{'column_invisible': [('allow_timesheets', '=', False)]}" optional="hide"/>
</field>
</field>
</record>
<record id="project_sharing_project_task_view_search_inherit_timesheet" model="ir.ui.view">
<field name="name">project.sharing.project.task.view.search.inherit.timesheet</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.project_sharing_project_task_view_search"/>
<field name="arch" type="xml">
<xpath expr="//filter[@name='late']" position='after'>
<filter string="Tasks in Overtime" name="overtime" domain="[('overtime', '&gt;', 0)]"/>
<filter string="Tasks Soon in Overtime" name="remaining_hours_percentage" domain="[('remaining_hours_percentage', '&lt;=', 0.2)]"/>
</xpath>
</field>
</record>
</odoo>

View file

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="portal_my_task" inherit_id="project.portal_my_task" name="Portal: My Task with Timesheets">
<xpath expr="//div[hasclass('o_project_portal_sidebar')]" position="before">
<t t-set="show_portal_timesheets" t-value="timesheets and timesheets[0].env['account.analytic.line']._show_portal_timesheets()"/>
</xpath>
<xpath expr="//div[@id='task-nav']" position="before">
<div t-if="timesheets and allow_timesheets and show_portal_timesheets" class="d-grid flex-grow-1" id='nav-report'>
<a class="btn btn-light o_print_btn o_project_timesheet_print d-block" t-att-href="task.get_portal_url(report_type='pdf')" href="#" title="View Details" role="button" target="_blank"><i class="fa fa-print"/> View Details</a>
</div>
</xpath>
<xpath expr="//li[@id='nav-header']" position="after">
<div t-if="timesheets and allow_timesheets and show_portal_timesheets" class="nav-item">
<a class="nav-link p-0" href="#task_timesheets">
Timesheets
</a>
</div>
</xpath>
<xpath expr="//div[@id='card_body']" position="inside">
<div class="container" t-if="timesheets and allow_timesheets and show_portal_timesheets">
<h5 id="task_timesheets" class="mt-2 mb-2" data-anchor="true">Timesheets</h5>
<t t-call="hr_timesheet.portal_timesheet_table"/>
</div>
</xpath>
<xpath expr="//div[@name='portal_my_task_allocated_hours']" position="after">
<div t-if="task.allocated_hours > 0 and allow_timesheets and show_portal_timesheets"><strong>Progress:</strong> <span t-esc="task.progress * 100" t-options='{"widget": "float", "precision": 0}'/>%</div>
</xpath>
<xpath expr="//div[@name='portal_my_task_allocated_hours']/t" position="replace">
<t t-call="hr_timesheet.portal_my_task_allocated_hours_template"></t>
</xpath>
</template>
<template id="portal_my_task_allocated_hours_template">
<t t-if="allow_timesheets and task.allocated_hours > 0">
<t t-if="is_uom_day">
<span t-out="timesheets._convert_hours_to_days(task.allocated_hours)" t-options='{"widget": "timesheet_uom"}'/>
</t>
<t t-else="" t-call="project.portal_my_task_allocated_hours_template"></t>
</t>
</template>
<template id="portal_tasks_list_inherit" inherit_id="project.portal_tasks_list" name="Portal: My Tasks with Timesheets">
<xpath expr="//thead" position="before">
<t t-set="allow_timesheets" t-value="any(task.allow_timesheets for group in grouped_tasks for task in group)"/>
<t t-set="show_portal_timesheets" t-value="grouped_tasks[0][0].env['account.analytic.line']._show_portal_timesheets()"/>
</xpath>
<xpath expr="//t[@t-foreach='tasks']/tr" position="before">
<t t-set="timesheet_ids" t-value="task.sudo().timesheet_ids"/>
<t t-set="is_uom_day" t-value="timesheet_ids._is_timesheet_encode_uom_day()"/>
</xpath>
<xpath expr="//thead/tr/th[@name='project_portal_milestones']" position="after">
<t t-if="(not project or project.allow_timesheets) and show_portal_timesheets">
<th class="text-end">Time Spent</th>
</t>
</xpath>
<xpath expr="//th[@name='state_col']" position="before">
<th t-if="not project or project.allow_timesheets" class="text-end text-muted fw-normal">
<t t-set="total_hours_dict" t-value="tasks._get_portal_total_hours_dict()"/>
<t t-if="total_hours_dict">
<t t-set="total_allocated_hours" t-value="tasks.project_id.allocated_hours if groupby == 'project_id' else total_hours_dict['allocated_hours']"/>
<t t-set="total_effective_hours" t-value="total_hours_dict['effective_hours']"/>
<span>
Total:
<t t-if="is_uom_day">
<t t-out="tasks._convert_hours_to_days(total_effective_hours)" t-options='{"widget": "timesheet_uom"}'/>
<t t-if="total_allocated_hours"> /
<t t-out="tasks._convert_hours_to_days(total_allocated_hours)" t-options='{"widget": "timesheet_uom"}'/>
</t>
</t>
<t t-else="">
<t t-out="total_effective_hours" t-options='{"widget": "float_time"}'/>
<t t-if="total_allocated_hours"> /
<t t-out="total_allocated_hours" t-options='{"widget": "float_time"}'/>
</t>
</t>
</span>
</t>
</th>
</xpath>
<xpath expr="//tbody/t/tr/td[@name='project_portal_milestones']" position="after">
<td t-if="(not project or project.allow_timesheets) and show_portal_timesheets" class="text-end">
<t t-if="task.allow_timesheets">
<t t-if="is_uom_day">
<t t-out="timesheet_ids._convert_hours_to_days(task.total_hours_spent)"/>
<span t-if="task.allocated_hours > 0"> / <t t-out="timesheet_ids._convert_hours_to_days(task.allocated_hours)"/></span>
</t>
<t t-else="">
<span t-field="task.total_hours_spent" t-options='{"widget": "float_time"}'/>
<t t-if="task.allocated_hours > 0">
/
<span t-field="task.allocated_hours" t-options='{"widget": "float_time"}'/>
</t>
</t>
</t>
</td>
</xpath>
</template>
</odoo>

View file

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="project_sharing_inherit_project_task_view_form" model="ir.ui.view">
<field name="name">project.sharing.project.task.view.form.inherit</field>
<field name="model">project.task</field>
<field name="priority">500</field>
<field name="inherit_id" ref="project.project_sharing_project_task_view_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='child_ids']/list/field[@name='partner_id']" position="after">
<field name="allow_timesheets" column_invisible="1"/>
</xpath>
<xpath expr="//field[@name='depend_on_ids']/list/field[@name='partner_id']" position="after">
<field name="allow_timesheets" column_invisible="1"/>
</xpath>
<xpath expr="//field[@name='child_ids']/list/field[@name='portal_user_names']" position="after">
<field name="allocated_hours" widget="timesheet_uom_no_toggle" sum="Total Allocated Time" optional="hide" column_invisible="not parent.allow_timesheets" invisible="not allow_timesheets"/>
<field name="effective_hours" widget="timesheet_uom" sum="Effective Hours" optional="hide" column_invisible="not parent.allow_timesheets" invisible="not allow_timesheets"/>
<field name="subtask_effective_hours" string="Sub-tasks Time Spent" widget="timesheet_uom" sum="Sub-tasks Time Spent" optional="hide" column_invisible="not parent.allow_timesheets" invisible="not allow_timesheets"/>
<field name="total_hours_spent" widget="timesheet_uom" sum="Total Time Spent" optional="hide" column_invisible="not parent.allow_timesheets" invisible="not allow_timesheets"/>
<field name="remaining_hours" widget="timesheet_uom" sum="Time Remaining" optional="hide" decoration-danger="progress &gt;= 1" decoration-warning="progress &gt;= 0.8 and progress &lt; 1" column_invisible="not parent.allow_timesheets" invisible="not allow_timesheets"/>
<field name="progress" widget="project_task_progressbar" optional="hide" options="{'overflow_class': 'bg-danger'}" column_invisible="not parent.allow_timesheets" invisible="not allow_timesheets"/>
</xpath>
<xpath expr="//field[@name='depend_on_ids']/list/field[@name='portal_user_names']" position="after">
<field name="allocated_hours" widget="timesheet_uom_no_toggle" sum="Total Allocated Time" optional="hide" column_invisible="not parent.allow_timesheets" invisible="not allow_timesheets"/>
<field name="effective_hours" widget="timesheet_uom" sum="Effective Hours" optional="hide" column_invisible="not parent.allow_timesheets" invisible="not allow_timesheets"/>
<field name="subtask_effective_hours" string="Sub-tasks Time Spent" widget="timesheet_uom" sum="Sub-tasks Time Spent" optional="hide" column_invisible="not parent.allow_timesheets" invisible="not allow_timesheets"/>
<field name="total_hours_spent" string="Total Time Spent" widget="timesheet_uom" sum="Total Time Spent" optional="hide" column_invisible="not parent.allow_timesheets" invisible="not allow_timesheets"/>
<field name="remaining_hours" widget="timesheet_uom" sum="Time Remaining" optional="hide" decoration-danger="progress &gt;= 1" decoration-warning="progress &gt;= 0.8 and progress &lt; 1" column_invisible="not parent.allow_timesheets" invisible="not allow_timesheets"/>
<field name="progress" widget="project_task_progressbar" optional="hide" options="{'overflow_class': 'bg-danger'}" column_invisible="not parent.allow_timesheets" invisible="not allow_timesheets"/>
</xpath>
<xpath expr="//div[@name='repeat_intervals']" position="after">
<field name="encode_uom_in_days" invisible="1"/>
<field name="subtask_count" invisible="1"/>
<label for="allocated_hours" invisible="not allow_timesheets"/>
<div id="allocated_hours_container" class="text-nowrap" invisible="not allow_timesheets">
<field name="allocated_hours" class="oe_inline" widget="float_time" readonly="1"/>
<span invisible="subtask_count == 0">
(incl. <field name="subtask_allocated_hours" nolabel="1" widget="timesheet_uom_no_toggle" class="oe_inline"/> on
<span class="fw-bold text-dark"> Sub-tasks</span>)
</span>
(<field name="progress" invisible="not project_id" class="oe_inline" nolabel="1" decoration-danger="progress > 1.005" digits="[1, 0]" widget="percentage"/>)
</div>
</xpath>
<xpath expr="//notebook/page[@name='description_page']" position="after">
<field name="analytic_account_active" invisible="1"/>
<field name="allow_timesheets" invisible="1"/>
<page string="Timesheets" name="page_timesheets" id="timesheets_tab" invisible="not allow_timesheets">
<field name="timesheet_ids" mode="list,kanban"
readonly="1">
<list string="Timesheet Activities" no_open="1" create="false" delete="0">
<field name="date"/>
<field name="employee_id"/>
<field name="name"/>
<field name="unit_amount" string="Time Spent" widget="timesheet_uom" decoration-danger="unit_amount &gt; 24"/>
</list>
<kanban class="o_kanban_mobile" action="action_open_timesheet_view_portal" type="object">
<templates>
<t t-name="card" class="row g-0">
<field name="employee_id" class="col-6 fw-bold"/>
<field name="date" class="col-6 text-end fw-bold" />
<field name="name" class="col-6 text-muted"/>
<field name="unit_amount" widget="float_time" class="col-6 text-end"/>
</t>
</templates>
</kanban>
</field>
<group invisible="not analytic_account_active">
<group class="oe_subtotal_footer" name="project_hours">
<span class="o_td_label float-start">
<label class="fw-bold" for="effective_hours" string="Time Spent"/>
</span>
<field name="effective_hours" widget="timesheet_uom" nolabel="1"/>
<button name="action_view_subtask_timesheet" type="object" class="ps-0 border-0 oe_inline oe_link mb-2 o_td_label float-start" invisible="subtask_effective_hours == 0.0" context="{'is_project_sharing': True}">
<span class="text-nowrap">Time Spent on Sub-tasks:</span>
</button>
<field name="subtask_effective_hours" class="mt-2" widget="timesheet_uom"
invisible="subtask_effective_hours == 0.0" nolabel="1"/>
<span id="total_hours_spent_label" invisible="subtask_effective_hours == 0.0" class="o_td_label float-start">
<label class="fw-bold" for="total_hours_spent" string="Total Time Spent"
invisible="encode_uom_in_days"/>
<label class="fw-bold" for="total_hours_spent" string="Total Days Spent"
invisible="not encode_uom_in_days"/>
</span>
<field name="total_hours_spent" widget="timesheet_uom" class="oe_subtotal_footer_separator" nolabel="1"
invisible="subtask_effective_hours == 0.0" />
<span class="o_td_label float-start">
<label class="fw-bold" for="remaining_hours" string="Time Remaining"
invisible="allocated_hours == 0.0 or encode_uom_in_days or remaining_hours &lt; 0"/>
<label class="fw-bold" for="remaining_hours" string="Days Remaining"
invisible="allocated_hours == 0.0 or not encode_uom_in_days or remaining_hours &lt; 0"/>
<label class="fw-bold text-danger" for="remaining_hours" string="Time Remaining"
invisible="allocated_hours == 0.0 or encode_uom_in_days or remaining_hours &gt;= 0"/>
<label class="fw-bold text-danger" for="remaining_hours" string="Days Remaining"
invisible="allocated_hours == 0.0 or not encode_uom_in_days or remaining_hours &gt;= 0"/>
</span>
<field name="remaining_hours" widget="timesheet_uom" class="oe_subtotal_footer_separator"
invisible="allocated_hours == 0.0" nolabel="1"/>
</group>
</group>
</page>
</xpath>
</field>
</record>
<record id="project_sharing_kanban_inherit_project_task_view_kanban" model="ir.ui.view">
<field name="name">project.sharing.project.task.timesheet.kanban.inherited</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.project_sharing_project_task_view_kanban"/>
<field name="arch" type="xml">
<templates position="before">
<field name="progress" />
<field name="remaining_hours" />
<field name="allocated_hours" />
<field name="allow_timesheets"/>
<field name="encode_uom_in_days" invisible="1"/>
</templates>
<field name="priority" position="before">
<t name="allocated_hours" t-if="record.allocated_hours.raw_value &gt; 0 and record.allow_timesheets.raw_value">
<t t-set="badge" t-value="'border border-success'"/>
<t t-set="badge" t-value="'border border-warning'" t-if="record.progress.raw_value &gt;= 0.8 and record.progress.raw_value &lt;= 1"/>
<t t-set="badge" t-value="'border border-danger'" t-if="record.remaining_hours.raw_value &lt; 0"/>
<t t-set="title" t-if="record.encode_uom_in_days.raw_value">Remaining days</t>
<t t-set="title" t-else="">Time Remaining</t>
<div t-attf-class="badge {{ badge }} bg-transparent flex-shrink-0" t-att-title="title">
<field name="remaining_hours" widget="timesheet_uom" />
</div>
</t>
</field>
</field>
</record>
</odoo>

View file

@ -0,0 +1,251 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record model="ir.ui.view" id="view_task_form2_inherited">
<field name="name">project.task.form.inherited</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_form2" />
<field name="arch" type="xml">
<xpath expr="//field[@name='child_ids']/list/field[@name='company_id']" position="after">
<field name="allocated_hours" widget="timesheet_uom_no_toggle" sum="Total Allocated Time" optional="hide" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="effective_hours" widget="timesheet_uom" sum="Time Spent" optional="hide" groups="hr_timesheet.group_hr_timesheet_user" column_invisible="context.get('template_project')"/>
<field name="subtask_effective_hours" widget="timesheet_uom" sum="Sub-tasks Time Spent" optional="hide" groups="hr_timesheet.group_hr_timesheet_user" column_invisible="context.get('template_project')"/>
<field name="total_hours_spent" widget="timesheet_uom" sum="Total Time Spent" optional="hide" groups="hr_timesheet.group_hr_timesheet_user" column_invisible="context.get('template_project')"/>
<field name="remaining_hours" widget="timesheet_uom" sum="Time Remaining" optional="hide" decoration-danger="progress &gt;= 1" decoration-warning="progress &gt;= 0.8 and progress &lt; 1" groups="hr_timesheet.group_hr_timesheet_user" column_invisible="context.get('template_project')"/>
<field name="progress" widget="project_task_progressbar" optional="hide" options="{'overflow_class': 'bg-danger'}" groups="hr_timesheet.group_hr_timesheet_user"
column_invisible="context.get('template_project')"/>
</xpath>
<xpath expr="//group/field[@name='allocated_hours']" position="replace">
<field name="encode_uom_in_days" invisible="1"/>
<field name="subtask_count" invisible="1"/>
<label for="allocated_hours" invisible="not allow_timesheets" groups="hr_timesheet.group_hr_timesheet_user"/>
<div id="allocated_hours_container" class="text-nowrap" invisible="not allow_timesheets" groups="hr_timesheet.group_hr_timesheet_user">
<field name="allocated_hours" class="oe_inline o_field_float_time o_task_planned_hours" widget="timesheet_uom_no_toggle"/>
<span invisible="subtask_count == 0">
(incl. <field name="subtask_allocated_hours" nolabel="1" widget="timesheet_uom_no_toggle" class="oe_inline"/> on
<span class="fw-bold text-dark"> Sub-tasks</span>)
</span>
<span invisible="is_template or has_project_template">
(<field name="progress" invisible="not project_id" class="oe_inline" nolabel="1" decoration-danger="progress > 1.005" digits="[1, 0]" widget="percentage"/>)
</span>
</div>
</xpath>
<xpath expr="//t[@name='warning_section']" position="inside">
<div class="alert alert-warning text-center mb-2" role="alert" invisible="analytic_account_active or not allow_timesheets or is_template or has_project_template" groups="hr_timesheet.group_hr_timesheet_user">
You cannot log timesheets on this project since it is linked to an inactive analytic account.<br/> Please change this account, or reactivate the current one to timesheet on the project.
</div>
</xpath>
<xpath expr="//notebook/page[@name='description_page']" position="after">
<field name="allow_timesheets" invisible="1"/>
<t groups="hr_timesheet.group_hr_timesheet_user">
<field name="analytic_account_active" invisible="1"/>
</t>
<page string="Timesheets" name="page_timesheets" id="timesheets_tab" invisible="not allow_timesheets or has_template_ancestor or has_project_template or (not id and context.get('hide_timesheet_ids'))" groups="hr_timesheet.group_hr_timesheet_user">
<field name="timesheet_ids" mode="list,kanban" readonly="not analytic_account_active" context="{'default_project_id': project_id, 'default_name': '', 'form_view_ref': 'hr_timesheet.timesheet_view_form_user'}">
<list editable="top" string="Timesheet Activities" decoration-muted="readonly_timesheet == True">
<field name="readonly_timesheet" column_invisible="True"/>
<field name="date" readonly="readonly_timesheet"/>
<field name="user_id" column_invisible="True"/>
<field name="employee_id" widget="many2one_avatar_employee" context="{'active_test': True}"
required="1"
readonly="readonly_timesheet"/>
<field name="name" required="0" readonly="readonly_timesheet"/>
<field name="unit_amount" string="Time Spent" widget="timesheet_uom" decoration-danger="unit_amount &gt; 24 or unit_amount &lt; 0"
readonly="readonly_timesheet"/>
<field name="project_id" column_invisible="True"/>
<field name="task_id" column_invisible="True"/>
<field name="company_id" column_invisible="True"/>
</list>
<kanban class="o_kanban_mobile">
<templates>
<t t-name="card">
<div class="row">
<div class="col-6 d-flex">
<field name="employee_id" class="me-1" widget="many2one_avatar_employee" context="{'active_test': True}" readonly="readonly_timesheet"/>
<field name="employee_id" class="ps-1 fw-bold"/>
</div>
<field name="date" class="col-6 text-end fw-bold"/>
</div>
<div class="row">
<field name="name" class="col-6 text-muted" required="0" readonly="readonly_timesheet"/>
<field name="unit_amount" widget="float_time" class="col-6 text-end"/>
</div>
</t>
</templates>
</kanban>
<form string="Timesheet Activities">
<sheet>
<group>
<field name="readonly_timesheet" invisible="1"/>
<field name="date" readonly="readonly_timesheet"/>
<field name="user_id" invisible="1" readonly="readonly_timesheet"/>
<field name="employee_id" widget="many2one_avatar_employee" context="{'active_test': True}" required="1" readonly="readonly_timesheet"/>
<field name="name" required="0" readonly="readonly_timesheet"/>
<field name="unit_amount" string="Time Spent" widget="float_time" decoration-danger="unit_amount &gt; 24"
readonly="readonly_timesheet"/>
<field name="project_id" invisible="1"/>
<field name="task_id" invisible="1"/>
<field name="company_id" invisible="1"/>
</group>
</sheet>
</form>
</field>
<group invisible="not analytic_account_active">
<group class="oe_subtotal_footer" name="project_hours">
<span class="o_td_label float-start">
<label class="fw-bold" for="effective_hours" string="Time Spent"/>
</span>
<field name="effective_hours" widget="timesheet_uom" nolabel="1"/>
<button name="action_view_subtask_timesheet" type="object" class="ps-0 border-0 oe_inline oe_link mb-2 o_td_label float-start" invisible="subtask_effective_hours == 0.0">
<span class="text-nowrap">Time Spent on Sub-tasks:</span>
</button>
<field name="subtask_effective_hours" class="mt-2" widget="timesheet_uom"
invisible="subtask_effective_hours == 0.0" nolabel="1"/>
<span invisible="subtask_effective_hours == 0.0" class="o_td_label float-start my-1">
<label class="fw-bold" for="total_hours_spent"
invisible="subtask_effective_hours == 0.0 or encode_uom_in_days"/>
<label class="fw-bold" for="total_hours_spent"
invisible="subtask_effective_hours == 0.0 or not encode_uom_in_days"/>
</span>
<field name="total_hours_spent" widget="timesheet_uom" class="oe_subtotal_footer_separator" nolabel="1"
invisible="subtask_effective_hours == 0.0" />
<span class="o_td_label float-start my-1" invisible="allocated_hours == 0.0">
<label class="fw-bold" for="remaining_hours"
invisible="remaining_hours &lt; 0"/>
<label class="fw-bold text-danger" for="remaining_hours"
invisible="remaining_hours &gt;= 0"/>
</span>
<field name="remaining_hours" widget="timesheet_uom" class="oe_subtotal_footer_separator"
invisible="allocated_hours == 0.0" nolabel="1" decoration-danger="remaining_hours &lt; 0"/>
</group>
</group>
</page>
</xpath>
<xpath expr="//field[@name='depend_on_ids']/list//field[@name='company_id']" position="after">
<field name="progress" column_invisible="True" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="allocated_hours" widget="timesheet_uom_no_toggle" sum="Total Allocated Time" optional="hide" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="effective_hours" widget="timesheet_uom" sum="Effective Hours" optional="hide" groups="hr_timesheet.group_hr_timesheet_user" column_invisible="context.get('template_project')"/>
<field name="subtask_effective_hours" widget="timesheet_uom" optional="hide" groups="hr_timesheet.group_hr_timesheet_user" column_invisible="context.get('template_project')"/>
<field name="total_hours_spent" widget="timesheet_uom" optional="hide" groups="hr_timesheet.group_hr_timesheet_user" column_invisible="context.get('template_project')"/>
<field name="remaining_hours" widget="timesheet_uom" sum="Time Remaining" optional="hide" decoration-danger="progress &gt;= 1" decoration-warning="progress &gt;= 0.8 and progress &lt; 1" groups="hr_timesheet.group_hr_timesheet_user" column_invisible="context.get('template_project')"/>
<field name="progress" widget="project_task_progressbar" optional="hide" options="{'overflow_class': 'bg-danger'}" groups="hr_timesheet.group_hr_timesheet_user" column_invisible="context.get('template_project')"/>
</xpath>
</field>
</record>
<record id="view_task_tree2_inherited" model="ir.ui.view">
<field name="name">project.task.list.inherited</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.project_task_view_tree_main_base" />
<field name="arch" type="xml">
<field name="priority" position="before">
<field name="progress" column_invisible="True"/>
<field name="effective_hours" column_invisible="True"/>
<field name="allocated_hours" widget="timesheet_uom_no_toggle" sum="Total Allocated Time" optional="hide" groups="hr_timesheet.group_hr_timesheet_user" column_invisible="not context.get('allow_timesheets', True)"/>
<field name="effective_hours" widget="timesheet_uom" sum="Effective Hours" optional="show" invisible="effective_hours == 0" groups="hr_timesheet.group_hr_timesheet_user" column_invisible="not context.get('allow_timesheets', True) or context.get('template_project')"/>
<field name="subtask_effective_hours" widget="timesheet_uom" sum="Time Spent on Sub-Tasks" optional="hide" groups="hr_timesheet.group_hr_timesheet_user" column_invisible="not context.get('allow_timesheets', True) or context.get('template_project')"/>
<field name="total_hours_spent" widget="timesheet_uom" sum="Total Time Spent" optional="hide" groups="hr_timesheet.group_hr_timesheet_user" column_invisible="not context.get('allow_timesheets', True) or context.get('template_project')"/>
<field name="remaining_hours" widget="timesheet_uom" sum="Time Remaining on SO" optional="hide" decoration-danger="progress &gt;= 1" decoration-warning="progress &gt;= 0.8 and progress &lt; 1" invisible="allocated_hours == 0" groups="hr_timesheet.group_hr_timesheet_user" column_invisible="not context.get('allow_timesheets', True) or context.get('template_project')"/>
<field name="progress" widget="project_task_progressbar" avg="Average of Progress" optional="show" groups="hr_timesheet.group_hr_timesheet_user" invisible="allocated_hours == 0" options="{'overflow_class': 'bg-danger'}" column_invisible="not context.get('allow_timesheets', True) or context.get('template_project')"/>
</field>
</field>
</record>
<record id="view_task_kanban_inherited_progress" model="ir.ui.view">
<field name="name">project.task.timesheet.kanban.inherited.progress</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_kanban"/>
<field name="arch" type="xml">
<templates position="before">
<field name="progress" />
<field name="remaining_hours" />
<field name="allocated_hours" />
<field name="allow_timesheets"/>
<field name="encode_uom_in_days" invisible="1"/>
</templates>
<xpath expr="//footer//field[@name='priority']" position="before">
<t name="allocated_hours" t-if="record.allocated_hours.raw_value &gt; 0 and record.allow_timesheets.raw_value" groups="hr_timesheet.group_hr_timesheet_user">
<t t-set="badge" t-value="'border border-success'"/>
<t t-set="badge" t-value="'border border-warning'" t-if="record.progress.raw_value &gt;= 0.8 and record.progress.raw_value &lt;= 1"/>
<t t-set="badge" t-value="'border border-danger'" t-if="record.remaining_hours.raw_value &lt; 0"/>
<t t-set="title" t-if="record.encode_uom_in_days.raw_value">Remaining days</t>
<t t-set="title" t-else="">Time Remaining</t>
<div t-attf-class="bg-transparent badge {{ badge }} me-0" t-att-title="title">
<field name="remaining_hours" widget="timesheet_uom" />
</div>
</t>
</xpath>
</field>
</record>
<record id="project_task_view_search" model="ir.ui.view">
<field name="name">project.task.view.search.inherit.sale.timesheet.enterprise</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_search_form_project_fsm_base"/>
<field name="priority">10</field>
<field name="arch" type="xml">
<xpath expr="//filter[@name='blocking']/following-sibling::separator[1]" position="after">
<filter string="Timesheets 80%" name="timesheet_80"
domain="[('remaining_hours_percentage', '&gt;', 0.0), ('remaining_hours_percentage', '&lt;=', 0.2)]"
groups="hr_timesheet.group_hr_timesheet_user"
invisible="not context.get('allow_timesheets') or context.get('template_project')"/>
<filter string="Timesheets &gt;100%" name="timesheet_exceeded" domain="[('overtime', '&gt;', 0)]"
groups="hr_timesheet.group_hr_timesheet_user"
invisible="not context.get('allow_timesheets') or context.get('template_project')"/>
<separator/>
</xpath>
</field>
</record>
<record id="project_task_view_graph" model="ir.ui.view">
<field name="name">project.task.view.graph.inherited</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_project_task_graph"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='stage_id']" position='after'>
<field name="allocated_hours" widget="timesheet_uom" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="allocated_hours" widget="timesheet_uom" invisible="1" groups="!hr_timesheet.group_hr_timesheet_user"/>
<field name="remaining_hours" widget="timesheet_uom" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="remaining_hours" widget="timesheet_uom" invisible="1" groups="!hr_timesheet.group_hr_timesheet_user"/>
<field name="effective_hours" widget="timesheet_uom" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="effective_hours" widget="timesheet_uom" invisible="1" groups="!hr_timesheet.group_hr_timesheet_user"/>
<field name="total_hours_spent" widget="timesheet_uom" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="total_hours_spent" widget="timesheet_uom" invisible="1" groups="!hr_timesheet.group_hr_timesheet_user"/>
<field name="overtime" widget="timesheet_uom" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="overtime" widget="timesheet_uom" invisible="1" groups="!hr_timesheet.group_hr_timesheet_user"/>
<field name="subtask_effective_hours" widget="timesheet_uom" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="subtask_effective_hours" widget="timesheet_uom" invisible="1" groups="!hr_timesheet.group_hr_timesheet_user"/>
<field name="progress" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="progress" invisible="1" groups="!hr_timesheet.group_hr_timesheet_user"/>
</xpath>
</field>
</record>
<record id="project_task_view_pivot" model="ir.ui.view">
<field name="name">project.task.view.pivot.inherited</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_project_task_pivot"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='allocated_hours']" position='attributes'>
<attribute name="widget">timesheet_uom</attribute>
<attribute name="groups">hr_timesheet.group_hr_timesheet_user</attribute>
</xpath>
<xpath expr="//field[@name='allocated_hours']" position='after'>
<field name="allocated_hours" widget="timesheet_uom" invisible="1" groups="!hr_timesheet.group_hr_timesheet_user"/>
<field name="remaining_hours" widget="timesheet_uom" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="remaining_hours" widget="timesheet_uom" invisible="1" groups="!hr_timesheet.group_hr_timesheet_user"/>
<field name="effective_hours" widget="timesheet_uom" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="effective_hours" widget="timesheet_uom" invisible="1" groups="!hr_timesheet.group_hr_timesheet_user"/>
<field name="total_hours_spent" widget="timesheet_uom" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="total_hours_spent" widget="timesheet_uom" invisible="1" groups="!hr_timesheet.group_hr_timesheet_user"/>
<field name="overtime" widget="timesheet_uom" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="overtime" widget="timesheet_uom" invisible="1" groups="!hr_timesheet.group_hr_timesheet_user"/>
<field name="subtask_effective_hours" widget="timesheet_uom" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="subtask_effective_hours" widget="timesheet_uom" invisible="1" groups="!hr_timesheet.group_hr_timesheet_user"/>
<field name="progress" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="progress" invisible="1" groups="!hr_timesheet.group_hr_timesheet_user"/>
</xpath>
</field>
</record>
</data>
</odoo>

View file

@ -7,10 +7,23 @@
<field name="inherit_id" ref="project.project_update_view_search"/>
<field name="arch" type="xml">
<xpath expr="//filter[@name='my_updates']" position='after'>
<filter string="My Team's Updates" name="my_team_updates" domain="[('user_id.employee_parent_id.user_id', '=', uid)]"/>
<filter string="My Team's Updates" name="my_team_updates" domain="[('user_id.employee_id.parent_id.user_id', '=', uid)]"/>
<filter string="My Department's Updates" name="my_department_updates" domain="[('user_id.employee_id.member_of_department', '=', True)]"/>
</xpath>
</field>
</record>
<record id="project_update_view_kanban_inherit" model="ir.ui.view">
<field name="name">project.update.view.kanban.inherit</field>
<field name="model">project.update</field>
<field name="inherit_id" ref="project.project_update_view_kanban"/>
<field name="arch" type="xml">
<div id="tasks_stats" position='after'>
<field name="display_timesheet_stats" invisible="1"/>
<div class="o_pupdate_kanban_width flex-grow-1 fw-bolder" invisible="not display_timesheet_stats">
<field name="timesheet_time"/><span invisible="not allocated_time"> / <field name="allocated_time"/></span> <field name="uom_id" no_open="1"/><span invisible="not allocated_time"> (<field name="timesheet_percentage"/>%)</span>
</div>
</div>
</field>
</record>
</data>
</odoo>

View file

@ -1,439 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="act_hr_timesheet_line_by_project" model="ir.actions.act_window">
<field name="name">Timesheets</field>
<field name="res_model">account.analytic.line</field>
<field name="view_mode">tree,kanban,pivot,graph,form</field>
<field name="view_id" ref="timesheet_view_tree_user"/>
<field name="domain">[('project_id', '=', active_id)]</field>
<field name="context">{
"default_project_id": active_id,
"is_timesheet": 1,
}</field>
<field name="search_view_id" ref="hr_timesheet_line_search"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Record a new activity
</p><p>
Track your working hours by projects every day and invoice this time to your customers.
</p>
</field>
</record>
<record id="act_hr_timesheet_line_by_project_view_tree" model="ir.actions.act_window.view">
<field name="view_mode">tree</field>
<field name="sequence" eval="1"/>
<field name="view_id" ref="timesheet_view_tree_user"/>
<field name="act_window_id" ref="act_hr_timesheet_line_by_project"/>
</record>
<record id="act_hr_timesheet_line_by_project_view_kanban" model="ir.actions.act_window.view">
<field name="view_mode">kanban</field>
<field name="sequence" eval="2"/>
<field name="view_id" ref="view_kanban_account_analytic_line"/>
<field name="act_window_id" ref="act_hr_timesheet_line_by_project"/>
</record>
<record id="act_hr_timesheet_line_by_project_view_pivot" model="ir.actions.act_window.view">
<field name="view_mode">pivot</field>
<field name="sequence" eval="3"/>
<field name="view_id" ref="view_hr_timesheet_line_pivot"/>
<field name="act_window_id" ref="act_hr_timesheet_line_by_project"/>
</record>
<record id="act_hr_timesheet_line_by_project_view_graph" model="ir.actions.act_window.view">
<field name="view_mode">graph</field>
<field name="sequence" eval="4"/>
<field name="view_id" ref="view_hr_timesheet_line_graph_all"/>
<field name="act_window_id" ref="act_hr_timesheet_line_by_project"/>
</record>
<record id="act_hr_timesheet_line_by_project_view_form" model="ir.actions.act_window.view">
<field name="view_mode">form</field>
<field name="sequence" eval="10"/>
<field name="view_id" ref="hr_timesheet_line_form"/>
<field name="act_window_id" ref="act_hr_timesheet_line_by_project"/>
</record>
<record id="project_project_view_form_simplified_inherit_timesheet" model="ir.ui.view">
<field name="name">project.project.view.form.simplified.inherit.timesheet</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.project_project_view_form_simplified"/>
<field name="priority">24</field>
<field name="arch" type="xml">
<xpath expr="//div[hasclass('o_settings_container')]" position="inside">
<div class="col-lg-6 o_setting_box">
<div class="o_setting_left_pane">
<field name="allow_timesheets"/>
</div>
<div class="o_setting_right_pane">
<label for="allow_timesheets" string="Timesheets"/>
<div class="text-muted">
Log time on tasks
</div>
</div>
</div>
</xpath>
</field>
</record>
<record id="project_invoice_form" model="ir.ui.view">
<field name="name">Inherit project form : Invoicing Data</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.edit_project"/>
<field name="priority">24</field>
<field name="arch" type="xml">
<xpath expr="//div[@name='dates']" position="after">
<field name="allocated_hours" widget="timesheet_uom_no_toggle" attrs="{'invisible': [('allow_timesheets', '=', False)]}"/>
</xpath>
<xpath expr="//group[@name='group_time_managment']" position="attributes">
<attribute name="invisible">0</attribute>
</xpath>
<xpath expr="//group[@name='group_time_managment']" position="inside">
<div class="o_setting_box" id="timesheet_settings" colspan="2">
<div class="o_setting_left_pane">
<field name="allow_timesheets"/>
</div>
<div class="o_setting_right_pane">
<label for="allow_timesheets" string="Timesheets"/>
<div class="text-muted">
Log time on tasks
</div>
</div>
</div>
</xpath>
</field>
</record>
<record model="ir.ui.view" id="view_task_form2_inherited">
<field name="name">project.task.form.inherited</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_form2" />
<field name="arch" type="xml">
<xpath expr="//field[@name='child_ids']/tree/field[@name='company_id']" position="after">
<field name="planned_hours" widget="timesheet_uom_no_toggle" sum="Initially Planned Hours" optional="hide" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="effective_hours" widget="timesheet_uom" sum="Effective Hours" optional="hide" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="subtask_effective_hours" string="Sub-tasks Hours Spent" widget="timesheet_uom" sum="Sub-tasks Hours Spent" optional="hide" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="total_hours_spent" string="Total Hours" widget="timesheet_uom" sum="Total Hours" optional="hide" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="remaining_hours" widget="timesheet_uom" sum="Remaining Hours" optional="hide" decoration-danger="progress &gt;= 100" decoration-warning="progress &gt;= 80 and progress &lt; 100" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="progress" widget="progressbar" optional="hide" groups="hr_timesheet.group_hr_timesheet_user"/>
</xpath>
<xpath expr="//notebook/page[@name='description_page']" position="after">
<field name="allow_timesheets" invisible="1"/>
<field name="allow_subtasks" invisible="1"/>
<t groups="hr_timesheet.group_hr_timesheet_user">
<field name="analytic_account_active" invisible="1"/>
<field name="encode_uom_in_days" invisible="1"/>
<field name="subtask_count" invisible="1"/>
</t>
<page string="Timesheets" id="timesheets_tab" attrs="{'invisible': [('allow_timesheets', '=', False)]}" groups="hr_timesheet.group_hr_timesheet_user">
<group>
<group>
<label for="planned_hours" string="Allocated Hours" attrs="{'invisible': [('encode_uom_in_days', '=', True)]}"/>
<label for="planned_hours" string="Allocated Days" attrs="{'invisible': [('encode_uom_in_days', '=', False)]}"/>
<div class="o_row">
<field name="planned_hours" class="o_field_float_time oe_inline ms-2" widget="timesheet_uom_no_toggle"/>
<span attrs="{'invisible': ['|', ('allow_subtasks', '=', False), ('subtask_count', '=', 0)]}">
(incl. <field name="subtask_planned_hours" nolabel="1" groups="project.group_subtask_project" widget="timesheet_uom_no_toggle" class="oe_inline"/> on
<span class="fw-bold text-dark"> Sub-tasks</span>)
</span>
</div>
</group>
<group>
<field name="progress" widget="progressbar"/>
</group>
</group>
<group name="timesheet_error" attrs="{'invisible': [('analytic_account_active', '!=', False)]}">
<div class="alert alert-warning" role="alert" colspan="2">
You cannot log timesheets on this project since it is linked to an inactive analytic account. Please change this account, or reactivate the current one to timesheet on the project.
</div>
</group>
<field name="timesheet_ids" mode="tree,kanban" attrs="{'invisible': [('analytic_account_active', '=', False)]}" context="{'default_project_id': project_id, 'default_name':''}">
<tree editable="bottom" string="Timesheet Activities" default_order="date">
<field name="date"/>
<field name="user_id" invisible="1"/>
<field name="employee_id" required="1" widget="many2one_avatar_employee" context="{'active_test': True}" options="{'relation': 'hr.employee.public'}" groups="!hr.group_hr_user"/>
<field name="employee_id" required="1" widget="many2one_avatar_employee" context="{'active_test': True}" options="{'relation': 'hr.employee'}" groups="hr.group_hr_user"/>
<field name="name" required="0"/>
<field name="unit_amount" widget="timesheet_uom" decoration-danger="unit_amount &gt; 24 or unit_amount &lt; 0"/>
<field name="project_id" invisible="1"/>
<field name="task_id" invisible="1"/>
<field name="company_id" invisible="1"/>
</tree>
<kanban class="o_kanban_mobile">
<field name="date"/>
<field name="user_id"/>
<field name="name"/>
<field name="unit_amount" decoration-danger="unit_amount &gt; 24"/>
<field name="project_id"/>
<field name="task_id" invisible="1"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_card oe_kanban_global_click">
<div class="row">
<div class="col-6">
<field name="employee_id" widget="many2one_avatar_employee" context="{'active_test': True}" options="{'relation': 'hr.employee.public'}" groups="!hr.group_hr_user"/>
<field name="employee_id" widget="many2one_avatar_employee" context="{'active_test': True}" options="{'relation': 'hr.employee'}" groups="hr.group_hr_user"/>
<strong><span><t t-esc="record.employee_id.value"/></span></strong>
</div>
<div class="col-6 float-end text-end">
<strong><t t-esc="record.date.value"/></strong>
</div>
</div>
<div class="row">
<div class="col-6 text-muted">
<span><t t-esc="record.name.value"/></span>
</div>
<div class="col-6">
<span class="float-end text-end">
<field name="unit_amount" widget="float_time"/>
</span>
</div>
</div>
</div>
</t>
</templates>
</kanban>
<form string="Timesheet Activities">
<sheet>
<group>
<field name="date"/>
<field name="user_id" invisible="1"/>
<field name="employee_id" required="1" widget="many2one_avatar_employee" context="{'active_test': True}" options="{'relation': 'hr.employee.public'}" groups="!hr.group_hr_user"/>
<field name="employee_id" required="1" widget="many2one_avatar_employee" context="{'active_test': True}" options="{'relation': 'hr.employee'}" groups="hr.group_hr_user"/>
<field name="name" required="0"/>
<field name="unit_amount" string="Duration" widget="float_time" decoration-danger="unit_amount &gt; 24"/>
<field name="project_id" invisible="1"/>
<field name="task_id" invisible="1"/>
<field name="company_id" invisible="1"/>
</group>
</sheet>
</form>
</field>
<group attrs="{'invisible': [('analytic_account_active', '=', False)]}">
<group class="oe_subtotal_footer oe_right" name="project_hours">
<span class="o_td_label float-start">
<label class="fw-bold" for="effective_hours" string="Hours Spent" attrs="{'invisible': [('encode_uom_in_days', '=', True)]}"/>
<label class="fw-bold" for="effective_hours" string="Days Spent" attrs="{'invisible': [('encode_uom_in_days', '=', False)]}"/>
</span>
<field name="effective_hours" widget="timesheet_uom" nolabel="1"/>
<!-- remove o_form_subtask_button class from master-->
<button name="action_view_subtask_timesheet" type="object" class="o_form_subtask_button ps-0 border-0 oe_inline oe_link mb-2 o_td_label float-start" attrs="{'invisible' : ['|', ('allow_subtasks', '=', False), ('subtask_effective_hours', '=', 0.0)]}">
<span class="text-nowrap" attrs="{'invisible' : [('encode_uom_in_days', '=', True)]}">Hours Spent on Sub-tasks:</span>
<span class="text-nowrap" attrs="{'invisible' : [('encode_uom_in_days', '=', False)]}">Days Spent on Sub-tasks:</span>
</button>
<field name="subtask_effective_hours" class="mt-2" widget="timesheet_uom"
attrs="{'invisible' : ['|', ('allow_subtasks', '=', False), ('subtask_effective_hours', '=', 0.0)]}" nolabel="1"/>
<span attrs="{'invisible': ['|', ('allow_subtasks', '=', False), ('subtask_effective_hours', '=', 0.0)]}" class="o_td_label float-start">
<label class="fw-bold" for="total_hours_spent" string="Total Hours"
attrs="{'invisible': ['|', '|', ('allow_subtasks', '=', False), ('subtask_effective_hours', '=', 0.0), ('encode_uom_in_days', '=', True)]}"/>
<label class="fw-bold" for="total_hours_spent" string="Total Days"
attrs="{'invisible': ['|', '|', ('allow_subtasks', '=', False), ('subtask_effective_hours', '=', 0.0), ('encode_uom_in_days', '=', False)]}"/>
</span>
<field name="total_hours_spent" widget="timesheet_uom" class="oe_subtotal_footer_separator" nolabel="1"
attrs="{'invisible' : ['|', ('allow_subtasks', '=', False), ('subtask_effective_hours', '=', 0.0)]}" />
<span class="o_td_label float-start" attrs="{'invisible': [('planned_hours', '=', 0.0)]}">
<label class="fw-bold" for="remaining_hours" string="Remaining Hours"
attrs="{'invisible': ['|', ('encode_uom_in_days', '=', True), ('remaining_hours', '&lt;', 0)]}"/>
<label class="fw-bold" for="remaining_hours" string="Remaining Days"
attrs="{'invisible': ['|', ('encode_uom_in_days', '=', False), ('remaining_hours', '&lt;', 0)]}"/>
<label class="fw-bold text-danger" for="remaining_hours" string="Remaining Hours"
attrs="{'invisible': ['|', ('encode_uom_in_days', '=', True), ('remaining_hours', '&gt;=', 0)]}"/>
<label class="fw-bold text-danger" for="remaining_hours" string="Remaining Days"
attrs="{'invisible': ['|', ('encode_uom_in_days', '=', False), ('remaining_hours', '&gt;=', 0)]}"/>
</span>
<field name="remaining_hours" widget="timesheet_uom" class="oe_subtotal_footer_separator"
attrs="{'invisible' : [('planned_hours', '=', 0.0)]}" nolabel="1"/>
</group>
</group>
</page>
</xpath>
<xpath expr="//field[@name='depend_on_ids']/tree//field[@name='company_id']" position="after">
<field name="allow_subtasks" invisible="1" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="progress" invisible="1" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="planned_hours" widget="timesheet_uom_no_toggle" sum="Initially Planned Hours" optional="hide" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="effective_hours" widget="timesheet_uom" sum="Effective Hours" optional="hide" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="subtask_effective_hours" widget="timesheet_uom" attrs="{'invisible' : [('allow_subtasks', '=', False)]}" optional="hide" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="total_hours_spent" widget="timesheet_uom" attrs="{'invisible' : [('allow_subtasks', '=', False)]}" optional="hide" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="remaining_hours" widget="timesheet_uom" sum="Remaining Hours" optional="hide" decoration-danger="progress &gt;= 100" decoration-warning="progress &gt;= 80 and progress &lt; 100" groups="hr_timesheet.group_hr_timesheet_user"/>
<field name="progress" widget="progressbar" optional="hide" groups="hr_timesheet.group_hr_timesheet_user"/>
</xpath>
</field>
</record>
<record id="project_project_view_tree_inherit_sale_project" model="ir.ui.view">
<field name="name">project.project.tree.inherit.sale.timesheet</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.view_project"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='date']" position="after">
<field name="allocated_hours" widget="timesheet_uom_no_toggle" optional="show" attrs="{'invisible' : [('allocated_hours', '=', 0)]}"/>
</xpath>
</field>
</record>
<record id="view_task_tree2_inherited" model="ir.ui.view">
<field name="name">project.task.tree.inherited</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_tree2" />
<field eval="2" name="priority"/>
<field name="arch" type="xml">
<field name="company_id" position="after">
<field name="allow_subtasks" invisible="1"/>
<field name="progress" invisible="1"/>
<field name="planned_hours" widget="timesheet_uom_no_toggle" sum="Initially Planned Hours" optional="hide"/>
<field name="effective_hours" widget="timesheet_uom" sum="Effective Hours" optional="hide"/>
<field name="subtask_effective_hours" widget="timesheet_uom" attrs="{'invisible' : [('allow_subtasks', '=', False)]}" optional="hide"/>
<field name="total_hours_spent" widget="timesheet_uom" attrs="{'invisible' : [('allow_subtasks', '=', False)]}" optional="hide"/>
<field name="remaining_hours" widget="timesheet_uom" sum="Remaining Hours" optional="hide" decoration-danger="progress &gt;= 100" decoration-warning="progress &gt;= 80 and progress &lt; 100"/>
<field name="progress" widget="progressbar" optional="hide" groups="hr_timesheet.group_hr_timesheet_user" attrs="{'invisible' : [('planned_hours', '=', 0)]}"/>
</field>
</field>
</record>
<record id="view_project_kanban_inherited" model="ir.ui.view">
<field name="name">project.project.timesheet.kanban.inherited</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.view_project_kanban"/>
<field name="priority">24</field>
<field name="arch" type="xml">
<field name="partner_id" position="after">
<field name="allow_timesheets" invisible="1"/>
<field name="timesheet_count" invisible="1"/>
<field name="remaining_hours" invisible="1"/>
<field name="encode_uom_in_days" invisible="1"/>
<field name="allocated_hours" invisible="1"/>
</field>
<xpath expr="//div[hasclass('o_kanban_manage_view')]" position="inside">
<div role="menuitem" t-if="record.allow_timesheets.raw_value and record.timesheet_count and record.timesheet_count.raw_value" groups="hr_timesheet.group_hr_timesheet_user">
<a name="action_project_timesheets" type="object">Timesheets</a>
</div>
</xpath>
<xpath expr="//div[hasclass('o_project_kanban_boxes')]" position="after">
<t t-set="badgeColor" t-value="'border-success'"/>
<t t-set="badgeColor" t-value="'border-danger'" t-if="record.remaining_hours.raw_value &lt; 0"/>
<t t-set="title" t-value="'Remaining days'" t-if="record.encode_uom_in_days.raw_value"/>
<t t-set="title" t-value="'Remaining hours'" t-else=""/>
<div t-if="record.allow_timesheets.raw_value and record.allocated_hours.raw_value &gt; 0"
t-attf-class="oe_kanban_align badge border {{ badgeColor }}" t-att-title="title" groups="hr_timesheet.group_hr_timesheet_user">
<field name="remaining_hours" widget="timesheet_uom"/>
</div>
</xpath>
</field>
</record>
<record id="view_task_kanban_inherited_progress" model="ir.ui.view">
<field name="name">project.task.timesheet.kanban.inherited.progress</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_kanban"/>
<field name="arch" type="xml">
<templates position="before">
<field name="progress" />
<field name="remaining_hours" />
<field name="planned_hours" />
<field name="allow_timesheets"/>
<field name="encode_uom_in_days" invisible="1"/>
</templates>
<div class="oe_kanban_bottom_left" position="inside">
<t name="planned_hours" t-if="record.planned_hours.raw_value &gt; 0 and record.allow_timesheets.raw_value" groups="hr_timesheet.group_hr_timesheet_user">
<t t-set="badge" t-value=""/>
<t t-set="badge" t-value="'border-warning'" t-if="record.progress.raw_value &gt;= 80 and record.progress.raw_value &lt;= 100"/>
<t t-set="badge" t-value="'border-danger'" t-if="record.remaining_hours.raw_value &lt; 0"/>
<t t-set="title" t-value="'Remaining days'" t-if="record.encode_uom_in_days.raw_value"/>
<t t-set="title" t-value="'Remaining hours'" t-else=""/>
<div t-attf-class="oe_kanban_align badge {{ badge }}" t-att-title="title">
<field name="remaining_hours" widget="timesheet_uom" />
</div>
</t>
</div>
</field>
</record>
<record id="project_task_view_search" model="ir.ui.view">
<field name="name">project.task.view.search.inherit.sale.timesheet.enterprise</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_search_form"/>
<field name="arch" type="xml">
<xpath expr="//filter[@name='followed_by_me']" position='after'>
<filter string="My Team's Tasks" name="my_team_tasks" domain="[('user_ids.employee_parent_id.user_id', '=', uid)]"/>
<filter string="My Department's Tasks" name="my_department" domain="[('user_ids.employee_id.member_of_department', '=', True)]"/>
</xpath>
<xpath expr="//filter[@name='tasks_due_today']" position='after'>
<filter string="Tasks in Overtime" name="overtime" domain="[('overtime', '&gt;', 0)]"/>
<filter string="Tasks Soon in Overtime" name="remaining_hours_percentage" domain="[('remaining_hours_percentage', '&lt;=', 0.2)]"/>
</xpath>
</field>
</record>
<record id="view_task_search_form_hr_extended" model="ir.ui.view">
<field name="name">project.task.view.search.inherit.hr.timesheet</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_search_form_extended"/>
<field name="arch" type="xml">
<xpath expr="//filter[@name='my_favorite_projects']" position='after'>
<filter string="My Team's Projects" name="my_teams_projects" domain="[('project_id.user_id.employee_parent_id.user_id', '=', uid)]"/>
<filter string="My Department's Projects" name="my_department" domain="[('manager_id.employee_id.member_of_department', '=', True)]"/>
</xpath>
</field>
</record>
<record id="view_project_project_filter_inherit_timesheet" model="ir.ui.view">
<field name="name">project.project.view.inherit.timesheet</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.view_project_project_filter"/>
<field name="arch" type="xml">
<filter name="followed_by_me" position='before'>
<filter string="My Team" name="my_team_projects" domain="[('user_id.employee_parent_id.user_id', '=', uid)]"/>
<filter string="My Department" name="my_department" domain="[('user_id.employee_id.member_of_department', '=', True)]"/>
</filter>
<filter name="late_milestones" position="before">
<filter string="Projects in Overtime" name="projects_in_overtime" domain="[('is_project_overtime', '=', True)]"/>
</filter>
</field>
</record>
<record id="project_task_view_graph" model="ir.ui.view">
<field name="name">project.task.view.graph.inherited</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_project_task_graph"/>
<field name="arch" type="xml">
<xpath expr="//graph" position="attributes">
<attribute name="js_class">hr_timesheet_graphview</attribute>
</xpath>
<xpath expr="//field[@name='stage_id']" position='after'>
<field name="planned_hours" widget="timesheet_uom"/>
<field name="remaining_hours" widget="timesheet_uom"/>
<field name="effective_hours" widget="timesheet_uom"/>
<field name="total_hours_spent" widget="timesheet_uom"/>
<field name="overtime" widget="timesheet_uom"/>
<field name="subtask_effective_hours" widget="timesheet_uom"/>
</xpath>
</field>
</record>
<record id="project_task_view_pivot" model="ir.ui.view">
<field name="name">project.task.view.pivot.inherited</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_project_task_pivot"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='stage_id']" position='after'>
<field name="planned_hours" widget="timesheet_uom"/>
<field name="remaining_hours" widget="timesheet_uom"/>
<field name="effective_hours" widget="timesheet_uom"/>
<field name="total_hours_spent" widget="timesheet_uom"/>
<field name="overtime" widget="timesheet_uom"/>
<field name="subtask_effective_hours" widget="timesheet_uom"/>
</xpath>
</field>
</record>
<record id="project.open_view_project_all" model="ir.actions.act_window">
<field name="domain">[('is_internal_project', '=', False)]</field>
</record>
<record id="project.open_view_project_all_group_stage" model="ir.actions.act_window">
<field name="domain">[('is_internal_project', '=', False)]</field>
</record>
</data>
</odoo>

View file

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="rating_rating_view_search_project_inherited" model="ir.ui.view">
<field name="name">rating.rating.search.project.inherited</field>
<field name="model">rating.rating</field>
<field name="inherit_id" ref="project.rating_rating_view_search_project"/>
<field name="arch" type="xml">
<xpath expr="//filter[@name='my_ratings']" position="after">
<filter string="My Team's Ratings" name="my_team_rating" domain="[('rated_partner_id.user_ids.employee_parent_id.user_id', '=', uid)]"/>
<filter string="My Department's Ratings" name="my_department_rating" domain="[('rated_partner_id.user_ids.employee_id.member_of_department', '=', True)]"/>
</xpath>
</field>
</record>
</odoo>

View file

@ -6,124 +6,41 @@
<field name="priority" eval="55"/>
<field name="inherit_id" ref="base.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[hasclass('settings')]" position="inside">
<div class="app_settings_block" data-string="Timesheets" string="Timesheets" data-key="hr_timesheet" groups="hr_timesheet.group_timesheet_manager" id="timesheets">
<h2>Time Encoding</h2>
<div class="row mt16 o_settings_container" name="time_encoding_setting_container">
<div class="col-12 col-lg-6 o_setting_box"
id="time_mode_setting"
attrs="{'invisible':[('project_time_mode_id', '!=', False)]}">
<div class="o_setting_right_pane">
<label for="project_time_mode_id"/>
<span class="fa fa-lg fa-building-o" title="Values set here are company-specific." groups="base.group_multi_company"/>
<div class="content-group">
<div class="mt16">
<field name="project_time_mode_id" options="{'no_create': True, 'no_open': True}"/>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box" id="time_unit_timesheets_setting">
<div class="o_setting_right_pane">
<label for="timesheet_encode_uom_id"/>
<span class="fa fa-lg fa-building-o" title="Values set here are company-specific." groups="base.group_multi_company"/>
<div class="row">
<div class="text-muted col-md-12">
Time unit used to record your timesheets
</div>
</div>
<div class="content-group">
<div class="mt16">
<field name="timesheet_encode_uom_id" options="{'no_create': True, 'no_open': True}" required="1" class="col-lg-5 ps-0"/>
<field name="is_encode_uom_days" invisible="1"/>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box" id="synchronize_web_mobile_setting" invisible="1">
<div class="o_setting_left_pane">
<field name="module_project_timesheet_synchro" widget="upgrade_boolean"/>
</div>
<div class="o_setting_right_pane">
<label for="module_project_timesheet_synchro"/>
<div class="text-muted">
Track your time from anywhere, even offline, with our web/mobile apps
</div>
<div class="content-group">
<div class="row mt16 oe_center">
<div class="col-lg-3 pe-0 o_chrome_store_link d-none d-sm-inline-block">
<a href="http://www.odoo.com/app/timesheet?platform=chrome" class="align-middle" target="_blank">
<img alt="Google Chrome Store" class="img img-fluid align-middle mt-1" style="height: 85% !important;" src="project/static/src/img/chrome_store.png"/>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<h2>Timesheets Control</h2>
<div class="row mt16 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane">
<field name="reminder_user_allow" widget="upgrade_boolean"/>
</div>
<div class="o_setting_right_pane" id="reminder_user_allow">
<label for="reminder_user_allow"/>
<span class="fa fa-lg fa-building-o " title="Values set here are company-specific." groups="base.group_multi_company"/>
<div class="text-muted">
Send a periodical email reminder to timesheets users<br/>
that still have timesheets to encode
</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane">
<field name="reminder_manager_allow" widget="upgrade_boolean"/>
</div>
<div class="o_setting_right_pane" id="reminder_manager_allow">
<label for="reminder_manager_allow"/>
<span class="fa fa-lg fa-building-o " title="Values set here are company-specific." groups="base.group_multi_company"/>
<div class="text-muted">
Send a periodical email reminder to timesheets managers<br/>
that still have timesheets to validate
</div>
</div>
</div>
</div>
<xpath expr="//form" position="inside">
<app data-string="Timesheets" string="Timesheets" name="hr_timesheet" groups="hr_timesheet.group_timesheet_manager" id="timesheets">
<block title="Time Encoding" name="time_encoding_setting_container">
<setting id="time_mode_setting" company_dependent="1" invisible="project_time_mode_id">
<field name="project_time_mode_id" options="{'no_create': True, 'no_open': True}"/>
</setting>
<setting company_dependent="1" help="Time unit used to record your timesheets" id="time_unit_timesheets_setting">
<field name="timesheet_encode_method" class="col-lg-5 ps-0" widget="radio"/>
<field name="is_encode_uom_days" invisible="1"/>
</setting>
</block>
<block title="Timesheets Control">
<setting id="reminder_user_allow" company_dependent="1" help="Send a periodical email reminder to timesheets users that still have timesheets to encode">
<field name="reminder_user_allow" widget="upgrade_boolean"/>
</setting>
<setting id="reminder_allow" company_dependent="1" help="Send a periodical email reminder to timesheets approvers that still have timesheets to validate">
<field name="reminder_allow" widget="upgrade_boolean"/>
</setting>
</block>
<div name="section_leaves">
<h2>Time Off</h2>
<div class="row mt16 o_settings_container" name="timesheet_control">
<div class="col-12 col-lg-6 o_setting_box" id="timesheet_off_validation_setting">
<div class="o_setting_left_pane">
<field name="module_project_timesheet_holidays"/>
</div>
<div class="o_setting_right_pane">
<label for="module_project_timesheet_holidays"/>
<span class="fa fa-lg fa-building-o" title="Values set here are company-specific." groups="base.group_multi_company"/>
<div class="text-muted">
Generate timesheets upon time off validation
</div>
<div class="content-group">
<div id="module_project_timesheet_holidays"/>
</div>
</div>
</div>
</div>
<block title="Time Off" name="timesheet_control">
<setting company_dependent="1" documentation="/applications/services/timesheets/time_off.html" help="Generate timesheets for validated time off requests and public holidays" id="timesheet_off_validation_setting">
<field name="module_project_timesheet_holidays"/>
</setting>
</block>
</div>
</div>
</app>
</xpath>
</field>
</record>
<record id="hr_timesheet_config_settings_action" model="ir.actions.act_window">
<field name="name">Settings</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.config.settings</field>
<field name="view_mode">form</field>
<field name="target">inline</field>
<field name="context">{'module' : 'hr_timesheet', 'bin_size': False}</field>
</record>
<menuitem id="hr_timesheet_menu_configuration" name="Configuration" parent="timesheet_menu_root"
action="hr_timesheet_config_settings_action" groups="base.group_system" sequence="100"/>
</odoo>