[IMP] hr_timesheet, **: improve generic ux for timesheet

** = hr_timesheet_attendance,project_timesheet_holiday,
sale_timesheet

Purpose of this commit to improve generic usage of
timesheet app.

So, in this commit done following change:

- change no content helper for reporting menu actions.
- change no content helper for attendance report menu action.
- make timesheet editable in batch.
- add suspicious duration filter in timesheet search view.
- add analytic tags in timesheet views only visible when analytic
  tag feature enable from accounting settings.
- remove group group_no_one from section_leaves div.
- remov group group_no_one from timesheet group in leave type
  form view.
- improve search view.
- remove form view reference from project_id of timesheet.
- add a condition for decoration danger in o2m tree view for
  timesheet_ids in project form view.

task-2725525

closes odoo/odoo#82305

Related: odoo/upgrade#3355
Related: odoo/enterprise#23284
Signed-off-by: Laurent Stukkens (ltu) <ltu@odoo.com>
This commit is contained in:
Kartik Chavda
2022-04-19 16:39:53 +02:00
parent b622f3b9b1
commit fd3a334637
9 changed files with 47 additions and 18 deletions
@@ -43,12 +43,14 @@ class AccountAnalyticLine(models.Model):
'project.task', 'Task', index='btree_not_null',
compute='_compute_task_id', store=True, readonly=False,
domain="[('company_id', '=', company_id), ('project_id.allow_timesheets', '=', True), ('project_id', '=?', project_id)]")
ancestor_task_id = fields.Many2one('project.task', related='task_id.ancestor_id', store=True, index='btree_not_null')
project_id = fields.Many2one(
'project.project', 'Project', domain=_domain_project_id, index=True,
compute='_compute_project_id', store=True, readonly=False)
user_id = fields.Many2one(compute='_compute_user_id', store=True, readonly=False)
employee_id = fields.Many2one('hr.employee', "Employee", domain=_domain_employee_id, context={'active_test': False})
department_id = fields.Many2one('hr.department', "Department", compute='_compute_department_id', store=True, compute_sudo=True)
manager_id = fields.Many2one('hr.employee', "Manager", related='employee_id.parent_id', store=True)
encoding_uom_id = fields.Many2one('uom.uom', compute='_compute_encoding_uom_id')
partner_id = fields.Many2one(compute='_compute_partner_id', store=True, readonly=False)
@@ -8,10 +8,11 @@
<field name="context">{'search_default_groupby_employee':1, 'grid_range': 'week'}</field>
<field name="search_view_id" ref="hr_timesheet_line_search"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No activities found
<p class="o_view_nocontent_empty_folder">
No data yet!
</p><p>
Track your working hours by projects every day and invoice this time to your customers.
Analyze the projects and tasks on which your employees spend their time.<br/>
Evaluate which part is billable and what costs it represents.
</p>
</field>
</record>
@@ -58,10 +59,11 @@
<field name="context">{'search_default_groupby_project': 1, 'grid_range': 'week'}</field>
<field name="search_view_id" ref="hr_timesheet_line_search"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No activities found
<p class="o_view_nocontent_empty_folder">
No data yet!
</p><p>
Track your working hours by projects every day and invoice this time to your customers.
Analyze the projects and tasks on which your employees spend their time.<br/>
Evaluate which part is billable and what costs it represents.
</p>
</field>
</record>
@@ -108,10 +110,11 @@
<field name="context">{'search_default_groupby_project':1,'search_default_groupby_task':1, 'grid_range': 'week'}</field>
<field name="search_view_id" ref="hr_timesheet_line_search"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No activities found
<p class="o_view_nocontent_empty_folder">
No data yet!
</p><p>
Track your working hours by projects every day and invoice this time to your customers.
Analyze the projects and tasks on which your employees spend their time.<br/>
Evaluate which part is billable and what costs it represents.
</p>
</field>
</record>
@@ -29,8 +29,10 @@ const TaskWithHours = FieldMany2One.extend({
this.additionalContext
);
// We don't want to quick create if no project is set in the timesheet
const canCreate = 'default_project_id' in context && context.default_project_id;
this.nodeOptions.no_quick_create =
this.nodeOptions.no_quick_create || (!('default_project_id' in context) || !context.default_project_id);
this.nodeOptions.no_quick_create || !canCreate;
this.can_create = this.can_create && canCreate;
this._super.apply(this, arguments);
},
/**
@@ -28,6 +28,7 @@
<field name="project_id" required="1" options="{'no_create_edit': 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}" domain="[('project_id', '=', project_id)]"/>
<field name="name" optional="show" required="0"/>
<field name="tag_ids" groups="analytic.group_analytic_tags" widget="many2many_tags" optional="hide"/>
<field name="unit_amount" optional="show" widget="timesheet_uom" sum="Total" decoration-danger="unit_amount &gt; 24"/>
<field name="company_id" invisible="1"/>
<field name="user_id" invisible="1"/>
@@ -126,8 +127,9 @@
<sheet string="Analytic Entry">
<group>
<group>
<field name="project_id" required="1" context="{'form_view_ref': 'project.project_project_view_form_simplified',}"/>
<field name="project_id" required="1"/>
<field name="task_id" widget="task_with_hours" context="{'default_project_id': project_id}" domain="[('project_id', '=', project_id)]"/>
<field name="tag_ids" groups="analytic.group_analytic_tags" widget="many2many_tags"/>
<field name="name"/>
<field name="company_id" groups="base.group_multi_company" invisible="1"/>
</group>
@@ -164,18 +166,23 @@
<search string="Timesheet">
<field name="date"/>
<field name="employee_id"/>
<field name="department_id"/>
<field name="project_id"/>
<field name="ancestor_task_id" groups="project.group_subtask_project"/>
<field name="task_id"/>
<field name="tag_ids" groups="analytic.group_analytic_tags"/>
<field name="name"/>
<field name="department_id"/>
<field name="manager_id"/>
<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>
@@ -190,8 +197,10 @@
<field name="arch" type="xml">
<field name="employee_id" position="replace"/>
<field name="department_id" position="replace"/>
<field name="manager_id" position="replace"/>
<filter name="mine" position="replace"/>
<filter name="groupby_department" position="replace"/>
<filter name="groupby_manager" position="replace"/>
<filter name="groupby_employee" position="replace"/>
</field>
</record>
+2 -1
View File
@@ -154,7 +154,8 @@
<field name="user_id" invisible="1"/>
<field name="employee_id" required="1" widget="many2one_avatar_employee"/>
<field name="name" required="0"/>
<field name="unit_amount" widget="timesheet_uom" decoration-danger="unit_amount &gt; 24"/>
<field name="tag_ids" groups="analytic.group_analytic_tags" widget="many2many_tags" optional="hide"/>
<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"/>
@@ -97,7 +97,7 @@
</div>
</div>
</div>
<div name="section_leaves" groups="base.group_no_one">
<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">
@@ -57,8 +57,10 @@
<field name="view_id" ref="view_hr_timesheet_attendance_report_pivot"/>
<field name="context">{'search_default_group_by_month': True}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
<p class="o_view_nocontent_empty_folder">
No data yet!
</p><p>
Compare the time recorded by your employees with their attendance.
</p>
</field>
</record>
+6
View File
@@ -1034,6 +1034,7 @@ class Task(models.Model):
legend_normal = fields.Char(related='stage_id.legend_normal', string='Kanban Ongoing Explanation', readonly=True, related_sudo=False)
is_closed = fields.Boolean(related="stage_id.fold", string="Closing Stage", store=True, index=True, related_sudo=False, help="Folded in Kanban stages are closing stages.")
parent_id = fields.Many2one('project.task', string='Parent Task', index=True)
ancestor_id = fields.Many2one('project.task', compute='_compute_ancestor_id', index='btree_not_null', recursive=True, store=True)
child_ids = fields.One2many('project.task', 'parent_id', string="Sub-tasks")
child_text = fields.Char(compute="_compute_child_text")
allow_subtasks = fields.Boolean(string="Allow Sub-tasks", related="project_id.allow_subtasks", readonly=True)
@@ -1171,6 +1172,11 @@ class Task(models.Model):
for task in self:
task.is_private = not task.project_id and not task.parent_id
@api.depends('parent_id.ancestor_id')
def _compute_ancestor_id(self):
for task in self:
task.ancestor_id = task.parent_id.ancestor_id or task.parent_id
@api.depends_context('uid')
@api.depends('user_ids')
def _compute_personal_stage_id(self):
@@ -7,6 +7,7 @@
<field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_search"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='task_id']" position="after">
<field name="order_id" string="Sales Order" groups="sales_team.group_sale_salesman"/>
<field name="so_line" groups="sales_team.group_sale_salesman"/>
</xpath>
<xpath expr="//filter[@name='month']" position="before">
@@ -16,6 +17,7 @@
<separator/>
</xpath>
<xpath expr="//filter[@name='groupby_employee']" position="after">
<filter string="Sales Order" name="groupby_sale_order" domain="[]" context="{'group_by': 'order_id'}" groups="sales_team.group_sale_salesman"/>
<filter string="Sales Order Item" name="groupby_sale_order_item" domain="[]" context="{'group_by': 'so_line'}" groups="sales_team.group_sale_salesman"/>
<filter string="Invoice" name="groupby_invoice" domain="[]" context="{'group_by': 'timesheet_invoice_id'}"/>
<filter string="Billable Type" name="groupby_timesheet_invoice_type" domain="[]" context="{'group_by': 'timesheet_invoice_type'}"/>
@@ -29,7 +31,7 @@
<field name="groups_id" eval="[(4, ref('sales_team.group_sale_salesman'))]"/>
<field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_tree"/>
<field name="arch" type="xml">
<xpath expr="//tree/field[@name='unit_amount']" position="before">
<xpath expr="//tree/field[@name='name']" position="after">
<field name="commercial_partner_id" invisible="1"/>
<field name="is_so_line_edited" invisible="1"/>
<field name="so_line" widget="so_line_many2one" optional="hide" options="{'no_create': True}" context="{'create': False, 'edit': False, 'delete': False}"/>
@@ -183,10 +185,12 @@
'pivot_row_groupby': ['date:month'],
}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
<p class="o_view_nocontent_empty_folder">
No data yet!
</p><p>
Analyze the projects and tasks on which your employees spend their time.<br/>
Evaluate which part is billable and what costs it represents.
</p>
<p>Review your timesheets by billing type and make sure your time is billable.</p>
</field>
<field name="search_view_id" ref="hr_timesheet.hr_timesheet_line_search"/>
</record>