[IMP] (hr, sale)_timesheet, pad(_project): improve project general UX
Purpose fo the task is to improve the UX of timesheet, project and task. Done the chages for below point: - improve the stage demo data to unified the project stage - on the task timesheet 'sub-tasks hours spent' should be clickable and on click, it will display the list of subtask timesheet. - display in warning tasks for which Remaining Hours < 0 if Planned Hours > 0 in task list view - improve the settings of collabrative pad and planning and project form view Task-2129052 closes odoo/odoo#41092 Closes: #41092 Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
This commit is contained in:
committed by
Yannick Tivisse
parent
de4d7e14f8
commit
d16aa4cd39
@@ -135,6 +135,16 @@ class Task(models.Model):
|
||||
for task in self:
|
||||
task.display_timesheet_timer = task.allow_timesheets and task.project_id.allow_timesheet_timer and task.analytic_account_active
|
||||
|
||||
def action_view_subtask_timesheet(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': _('Timesheets'),
|
||||
'res_model': 'account.analytic.line',
|
||||
'view_mode': 'list,form',
|
||||
'domain': [('project_id', '!=', False), ('task_id', 'in', self.child_ids.ids)],
|
||||
}
|
||||
|
||||
def write(self, values):
|
||||
# a timesheet must have an analytic account (and a project)
|
||||
if 'project_id' in values and self and not values.get('project_id'):
|
||||
|
||||
@@ -178,7 +178,8 @@
|
||||
<group attrs="{'invisible': [('analytic_account_active', '=', False)]}">
|
||||
<group class="oe_subtotal_footer oe_right" name="project_hours">
|
||||
<field name="effective_hours" widget="float_time" />
|
||||
<field name="subtask_effective_hours" widget="float_time" attrs="{'invisible' : [('subtask_effective_hours', '=', 0.0)]}" />
|
||||
<button name="action_view_subtask_timesheet" string="Sub-tasks Hours Spent:" type="object" class="oe_inline oe_link pl-0" attrs="{'invisible' : [('subtask_effective_hours', '=', 0.0)]}"/>
|
||||
<field name="subtask_effective_hours" widget="float_time" attrs="{'invisible' : [('subtask_effective_hours', '=', 0.0)]}" nolabel="1"/>
|
||||
<field name="total_hours_spent" widget="float_time" class="oe_subtotal_footer_separator" attrs="{'invisible' : [('subtask_effective_hours', '=', 0.0)]}" />
|
||||
<field name="remaining_hours" widget="float_time" class="oe_subtotal_footer_separator" attrs="{'invisible' : [('planned_hours', '=', 0.0)]}"/>
|
||||
</group>
|
||||
@@ -194,6 +195,9 @@
|
||||
<field name="inherit_id" ref="project.view_task_tree2" />
|
||||
<field eval="2" name="priority"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//tree" position="attributes">
|
||||
<attribute name="decoration-warning">planned_hours and (effective_hours>planned_hours)</attribute>
|
||||
</xpath>
|
||||
<field name="user_id" position="after">
|
||||
<field name="planned_hours" widget="float_time" sum="Initially Planned Hours" optional="show"/>
|
||||
<field name="effective_hours" widget="float_time" sum="Effective Hours" optional="show"/>
|
||||
|
||||
@@ -7,5 +7,5 @@ from odoo import fields, models
|
||||
class ResConfigSettings(models.TransientModel):
|
||||
_inherit = 'res.config.settings'
|
||||
|
||||
pad_server = fields.Char(related='company_id.pad_server', string="Pad Server *", readonly=False)
|
||||
pad_key = fields.Char(related='company_id.pad_key', string="Pad Api Key *", readonly=False)
|
||||
pad_server = fields.Char(related='company_id.pad_server', string="Pad Server", readonly=False)
|
||||
pad_key = fields.Char(related='company_id.pad_key', string="Pad API Key", readonly=False)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<t t-name="FieldPad">
|
||||
<div class="oe_form_field_text oe_pad">
|
||||
<p class="oe_unconfigured d-none">
|
||||
Please enter your Etherpad credentials through the menu 'Settings > General Settings'.
|
||||
Please, enter your Etherpad credentials through the Settings.
|
||||
</p>
|
||||
<t t-if="widget.mode === 'readonly'">
|
||||
<div class="oe_pad_content etherpad_readonly oe_configured" />
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="res_config_settings_view_form" model="ir.ui.view">
|
||||
<field name="name">res.config.settings.view.form.inherit.pad</field>
|
||||
<field name="model">res.config.settings</field>
|
||||
<field name="inherit_id" ref="base_setup.res_config_settings_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<div id="msg_module_pad" position="replace">
|
||||
<div class="content-group" id="pad_configuration_settings" attrs="{'invisible': [('module_pad','=',False)]}">
|
||||
<div class="mt16 row">
|
||||
<label for="pad_server" string="Server" class="col-3 col-lg-3 o_light_label"/>
|
||||
<field name="pad_server" placeholder="e.g. beta.primarypad.com"/>
|
||||
<label for="pad_key" string="API Key" class="col-3 col-lg-3 o_light_label"/>
|
||||
<field name="pad_key"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</field>
|
||||
</record>
|
||||
<record id="res_config_settings_view_form" model="ir.ui.view">
|
||||
<field name="name">res.config.settings.view.form.inherit.pad</field>
|
||||
<field name="model">res.config.settings</field>
|
||||
<field name="inherit_id" ref="base_setup.res_config_settings_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<div id="msg_module_pad" position="replace">
|
||||
<div class="content-group" id="pad_configuration_settings" attrs="{'invisible': [('module_pad', '=', False)]}">
|
||||
<div class="mt16 row">
|
||||
<label for="pad_server" string="Server" class="col-3 col-lg-3 o_light_label"/>
|
||||
<field name="pad_server" placeholder="e.g. beta.primarypad.com" attrs="{'required': [('module_pad', '!=', False)]}"/>
|
||||
<label for="pad_key" string="API Key" class="col-3 col-lg-3 o_light_label"/>
|
||||
<field name="pad_key" attrs="{'required': [('module_pad', '!=', False)]}"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -24,4 +24,4 @@ class ProjectTask(models.Model):
|
||||
class ProjectProject(models.Model):
|
||||
_inherit = "project.project"
|
||||
|
||||
use_pads = fields.Boolean("Use collaborative pads", help="Use collaborative pad for the tasks on this project.")
|
||||
use_pads = fields.Boolean("Use collaborative pads", default=True, help="Use collaborative pad for the tasks on this project.")
|
||||
|
||||
@@ -20,9 +20,19 @@
|
||||
<field name="model">project.project</field>
|
||||
<field name="inherit_id" ref="project.edit_project"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="partner_id" position="after">
|
||||
<field name="use_pads"/>
|
||||
</field>
|
||||
<xpath expr="//div[@id='rating_settings']" position="after">
|
||||
<div class="col-lg-6 o_setting_box" id="pad_settings">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="use_pads"/>
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label for="use_pads" string="Collaborative Pads"/>
|
||||
<div class="text-muted">
|
||||
Use collaborative rich text pads on tasks
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -6,15 +6,14 @@
|
||||
<field name="inherit_id" ref="project.res_config_settings_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<div name="pad_project_right_pane" position="inside">
|
||||
<div class="content-group">
|
||||
<field name='company_id' invisible="1"/>
|
||||
<div class="content-group" attrs="{'invisible': [('module_pad', '=', False)]}">
|
||||
<div class="row mt16">
|
||||
<label for="pad_server" class="col-lg-3 o_light_label"/>
|
||||
<field name="pad_server"/>
|
||||
<field name="pad_server" attrs="{'required': [('module_pad', '!=', False)]}"/>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label for="pad_key" class="col-lg-3 o_light_label"/>
|
||||
<field name="pad_key"/>
|
||||
<field name="pad_key" attrs="{'required': [('module_pad', '!=', False)]}"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -103,19 +103,19 @@
|
||||
|
||||
<record forcecreate="False" id="project_stage_data_0" model="project.task.type">
|
||||
<field name="sequence">1</field>
|
||||
<field name="name">New</field>
|
||||
<field name="name">Basic</field>
|
||||
<field name="project_ids" eval="[(4, ref('project_project_data'))]"/>
|
||||
</record>
|
||||
|
||||
<record forcecreate="False" id="project_stage_data_1" model="project.task.type">
|
||||
<field name="sequence">2</field>
|
||||
<field name="name">Basic</field>
|
||||
<field name="name">Advanced</field>
|
||||
<field name="project_ids" eval="[(4, ref('project_project_data'))]"/>
|
||||
</record>
|
||||
|
||||
<record forcecreate="False" id="project_stage_data_2" model="project.task.type">
|
||||
<field name="sequence">3</field>
|
||||
<field name="name">Advanced</field>
|
||||
<field name="name">Expert</field>
|
||||
<field name="project_ids" eval="[(4, ref('project_project_data'))]"/>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
<!-- Stages -->
|
||||
<record id="project_stage_0" model="project.task.type">
|
||||
<field name="sequence">1</field>
|
||||
<field name="name">To Do</field>
|
||||
<field name="legend_blocked">Not validated</field>
|
||||
<field name="name">New</field>
|
||||
<field name="legend_blocked">Blocked</field>
|
||||
<field name="mail_template_id" ref="project.mail_template_data_project_task"/>
|
||||
</record>
|
||||
<record id="project_stage_1" model="project.task.type">
|
||||
|
||||
@@ -7,7 +7,7 @@ from odoo import api, fields, models
|
||||
class ResConfigSettings(models.TransientModel):
|
||||
_inherit = 'res.config.settings'
|
||||
|
||||
module_project_forecast = fields.Boolean(string="Forecasts")
|
||||
module_project_forecast = fields.Boolean(string="Planning")
|
||||
module_hr_timesheet = fields.Boolean(string="Task Logs")
|
||||
group_subtask_project = fields.Boolean("Sub-tasks", implied_group="project.group_subtask_project")
|
||||
group_project_rating = fields.Boolean("Use Rating on Project", implied_group='project.group_project_rating')
|
||||
|
||||
@@ -11,14 +11,7 @@
|
||||
<field name="product_uom_qty">5.0</field>
|
||||
</record>
|
||||
|
||||
<!-- Projects, Analytic Account and Stages -->
|
||||
<record id="project_stage_fixed" model="project.task.type">
|
||||
<field name="sequence">30</field>
|
||||
<field name="name">Fixed</field>
|
||||
<field name="legend_blocked">Need functional or technical help</field>
|
||||
<field name="legend_done">Done</field>
|
||||
</record>
|
||||
|
||||
<!-- Projects and Analytic Account -->
|
||||
<record id="account_analytic_account_project_support" model="account.analytic.account">
|
||||
<field name="name">After-Sales Services</field>
|
||||
<field name="code">INT</field>
|
||||
@@ -29,7 +22,7 @@
|
||||
<field name="date_start" eval="time.strftime('%Y-%m-01 10:00:00')"/>
|
||||
<field name="name">After-Sales Services</field>
|
||||
<field name="analytic_account_id" ref="account_analytic_account_project_support"/>
|
||||
<field name="type_ids" eval="[(4, ref('project.project_stage_data_0')), (4, ref('project.project_stage_1')), (4, ref('project_stage_fixed'))]"/>
|
||||
<field name="type_ids" eval="[(4, ref('project.project_stage_0')), (4, ref('project.project_stage_1')), (4, ref('project.project_stage_2'))]"/>
|
||||
</record>
|
||||
|
||||
<!-- Project Task -->
|
||||
@@ -418,44 +411,20 @@
|
||||
<field name="unit_amount">1.00</field>
|
||||
</record>
|
||||
|
||||
<!-- task on project generated by sale order 1 -->
|
||||
<record id="project_from_sale_order_1_to_do" model="project.task.type">
|
||||
<field name="sequence">10</field>
|
||||
<field name="name">To Do</field>
|
||||
<field name="legend_blocked">Not ready</field>
|
||||
<field name="legend_done">Ready to be started</field>
|
||||
<field name="project_ids" search="[('sale_order_id', '=', ref('sale_timesheet.sale_order_1'))]" />
|
||||
<record id="project.project_stage_1" model="project.task.type">
|
||||
<field name="project_ids" model="project.project" eval="[(4, obj().search([('sale_order_id', '=', ref('sale_timesheet.sale_order_1'))], limit=1).id)]"/>
|
||||
</record>
|
||||
|
||||
<record id="project_from_sale_order_1_in_progress" model="project.task.type">
|
||||
<field name="sequence">20</field>
|
||||
<field name="name">In Progress</field>
|
||||
<field name="legend_blocked">Need help</field>
|
||||
<field name="legend_done">Work done</field>
|
||||
<field name="project_ids" search="[('sale_order_id', '=', ref('sale_timesheet.sale_order_1'))]" />
|
||||
<record id="project.project_stage_2" model="project.task.type">
|
||||
<field name="project_ids" model="project.project" eval="[(4, obj().search([('sale_order_id', '=', ref('sale_timesheet.sale_order_1'))], limit=1).id)]"/>
|
||||
</record>
|
||||
|
||||
<record id="project_from_sale_order_1_done" model="project.task.type">
|
||||
<field name="sequence">30</field>
|
||||
<field name="name">Done</field>
|
||||
<field name="legend_blocked">Not done yet</field>
|
||||
<field name="legend_done">Done</field>
|
||||
<field name="project_ids" search="[('sale_order_id', '=', ref('sale_timesheet.sale_order_1'))]" />
|
||||
</record>
|
||||
|
||||
<function model="project.task" name="write">
|
||||
<value model="project.task" eval="obj().search([('sale_line_id','=',ref('sale_timesheet.sale_line_13')), ('stage_id', '=', False)]).id"/>
|
||||
<value eval="{
|
||||
'stage_id': ref('sale_timesheet.project_from_sale_order_1_to_do')
|
||||
}"/>
|
||||
</function>
|
||||
|
||||
<record id="project_task_1" model="project.task">
|
||||
<field name="name">Decoration</field>
|
||||
<field name="sale_line_id" ref="sale_timesheet.sale_line_13"/>
|
||||
<field name="sale_order_id" ref="sale_timesheet.sale_order_1"/>
|
||||
<field name="project_id" search="[('sale_order_id', '=', ref('sale_timesheet.sale_order_1'))]" />
|
||||
<field name="stage_id" ref="project_from_sale_order_1_in_progress"/>
|
||||
<field name="stage_id" ref="project.project_stage_2"/>
|
||||
<field name="sale_line_id" ref="sale_timesheet.sale_line_13" />
|
||||
<field name="sale_order_id" ref="sale_timesheet.sale_order_1" />
|
||||
<field name="partner_id" ref="base.res_partner_2" />
|
||||
@@ -466,7 +435,7 @@
|
||||
<field name="sale_line_id" ref="sale_timesheet.sale_line_13"/>
|
||||
<field name="sale_order_id" ref="sale_timesheet.sale_order_1"/>
|
||||
<field name="project_id" search="[('sale_order_id', '=', ref('sale_timesheet.sale_order_1'))]" />
|
||||
<field name="stage_id" ref="project_from_sale_order_1_done"/>
|
||||
<field name="stage_id" ref="project.project_stage_2"/>
|
||||
<field name="sale_line_id" ref="sale_timesheet.sale_line_13" />
|
||||
<field name="sale_order_id" ref="sale_timesheet.sale_order_1" />
|
||||
<field name="partner_id" ref="base.res_partner_2" />
|
||||
@@ -477,7 +446,7 @@
|
||||
<field name="sale_line_id" ref="sale_timesheet.sale_line_13"/>
|
||||
<field name="sale_order_id" ref="sale_timesheet.sale_order_1"/>
|
||||
<field name="project_id" search="[('sale_order_id', '=', ref('sale_timesheet.sale_order_1'))]" />
|
||||
<field name="stage_id" ref="project_from_sale_order_1_in_progress"/>
|
||||
<field name="stage_id" ref="project.project_stage_2"/>
|
||||
<field name="sale_line_id" ref="sale_timesheet.sale_line_13" />
|
||||
<field name="sale_order_id" ref="sale_timesheet.sale_order_1" />
|
||||
<field name="partner_id" ref="base.res_partner_2" />
|
||||
@@ -486,7 +455,7 @@
|
||||
<record id="project_task_4" model="project.task">
|
||||
<field name="name">Furniture Delivery</field>
|
||||
<field name="project_id" search="[('sale_order_id', '=', ref('sale_timesheet.sale_order_1'))]" />
|
||||
<field name="stage_id" ref="project_from_sale_order_1_to_do" />
|
||||
<field name="stage_id" ref="project.project_stage_1" />
|
||||
<field name="sale_line_id" ref="sale_timesheet.sale_line_13" />
|
||||
<field name="sale_order_id" ref="sale_timesheet.sale_order_1" />
|
||||
<field name="partner_id" ref="base.res_partner_2" />
|
||||
|
||||
Reference in New Issue
Block a user