[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:
@@ -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 > 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>
|
||||
|
||||
@@ -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 > 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 > 24 or unit_amount < 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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user