[IMP] hr_timesheet,industry_fsm: Display CTA buttons with computed fields
Purpose
=======
The various buttons in FSM are currently displayed based on a set
of attributes. As there are many different configurations possible
for projects, it makes a lot of conditions (= the code is a living
nightmare). This task aims at replacing these attributes by computed
fields in order to gain clarity and to avoid the various bugs we
recently faced + add python tests to ensure their robustness.
Specification
=============
START/STOP/PAUSE/RESUME
-----------------------
- should not be visible if the task is marked as done
- should be visible in non-primary if Time > 0
- should be visible in primary if Time = 0
- when the timer is running, do not display the following
buttons: Create Sales Order, Mark as done, Create Invoice,
Sign report, Send report
- only visible if the 'Timesheet Timer' feature is enabled
on the project
SIGN REPORT
-----------
- should not be visible
- if Time = 0 AND Worksheet = 0 AND Products = 0
- OR if the report already is signed
- should be visible in non primary if Time > 0 OR
Worksheet > 0 OR Products > 0
- should be visible in primary if Time > 0 AND Worksheet > 0
AND Products > 0
- once the report is signed, display an 'fa-globe Customer Preview'
stat button redirecting to the webpage with the report
- only visible if the 'worksheets' feature is enabled on the project
SEND REPORT
-----------
- should not be visible if Time = 0 AND Worksheet = 0 AND
Products = 0
- should be visible in non primary if Time > 0 OR Worksheet > 0
OR Products > 0 OR if the report was already sent
- should be visible in primary if
- Time > 0 AND Worksheet > 0 AND Products > 0
- AND the report is signed
- only visible if the 'worksheets' feature is enabled on the project
MARK AS DONE
------------
- should not be visible if the task is marked as done
- should be visible in non primary if
- Time > 0 OR Worksheet > 0 OR Products > 0
- OR if Time = 0 OR Worksheet = 0 OR Products = 0
- should be visible in primary if Time > 0 AND Worksheet > 0 AND
Products > 0
- only visible if is_fsm is true on the project
CREATE INVOICE
--------------
- should not be visible if the task is not marked as done OR if
the SO linked to the task has the 'Fully invoiced' invoice status
- should be visible in non primary if the SO linked to the task has
the 'Nothing to invoice' invoice status
- should be visible in primary if the SO linked to the task has one
of the following invoice status: To Invoice, Upselling
- only visible if the Bill from tasks feature is enabled on
the project
EXTRA QUOTATION + CREATE SALES ORDER
------------------------------------
no change of behavior
closes odoo/odoo#42508
Taskid: 2126857
Related: odoo/enterprise#6918
Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
Co-authored-by: Yannick Tivisse <yti@odoo.com>
This commit is contained in:
committed by
Yannick Tivisse
co-authored by
Yannick Tivisse
parent
abbbeb5714
commit
7e09f931ff
@@ -98,6 +98,38 @@ class Task(models.Model):
|
||||
timesheet_timer_first_start = fields.Datetime("Timesheet Timer First Use", readonly=True)
|
||||
timesheet_timer_last_stop = fields.Datetime("Timesheet Timer Last Use", readonly=True)
|
||||
display_timesheet_timer = fields.Boolean("Display Timesheet Time", compute='_compute_display_timesheet_timer')
|
||||
display_timer_start_primary = fields.Boolean(compute='_compute_display_timer_buttons')
|
||||
display_timer_start_secondary = fields.Boolean(compute='_compute_display_timer_buttons')
|
||||
display_timer_stop = fields.Boolean(compute='_compute_display_timer_buttons')
|
||||
display_timer_pause = fields.Boolean(compute='_compute_display_timer_buttons')
|
||||
display_timer_resume = fields.Boolean(compute='_compute_display_timer_buttons')
|
||||
|
||||
@api.depends('display_timesheet_timer', 'timer_start', 'timer_pause', 'total_hours_spent')
|
||||
def _compute_display_timer_buttons(self):
|
||||
for task in self:
|
||||
start_p, start_s, stop, pause, resume = True, True, True, True, True
|
||||
if not task.display_timesheet_timer:
|
||||
start_p, start_s, stop, pause, resume = False, False, False, False, False
|
||||
else:
|
||||
if task.timer_start:
|
||||
start_p, start_s = False, False
|
||||
if task.timer_pause:
|
||||
pause = False
|
||||
else:
|
||||
resume = False
|
||||
else:
|
||||
stop, pause, resume = False, False, False
|
||||
if not task.total_hours_spent:
|
||||
start_s = False
|
||||
else:
|
||||
start_p = False
|
||||
task.write({
|
||||
'display_timer_start_primary': start_p,
|
||||
'display_timer_start_secondary': start_s,
|
||||
'display_timer_stop': stop,
|
||||
'display_timer_pause': pause,
|
||||
'display_timer_resume': resume,
|
||||
})
|
||||
|
||||
@api.depends('timesheet_ids.unit_amount')
|
||||
def _compute_effective_hours(self):
|
||||
|
||||
@@ -261,16 +261,21 @@
|
||||
<field name="company_id" invisible="1"/>
|
||||
<field name="display_timesheet_timer" invisible="1"/>
|
||||
<field name="timer_pause" invisible="1" />
|
||||
<field name="display_timer_start_primary" invisible="1"/>
|
||||
<field name="display_timer_start_secondary" invisible="1"/>
|
||||
<field name="display_timer_stop" invisible="1"/>
|
||||
<field name="display_timer_pause" invisible="1"/>
|
||||
<field name="display_timer_resume" invisible="1"/>
|
||||
<button class="btn-primary" name="action_timer_start" type="object" string="Start"
|
||||
attrs="{'invisible': ['|', '|', ('total_hours_spent', '!=', 0), ('timer_start', '!=', False), ('display_timesheet_timer', '=', False)]}" groups="hr_timesheet.group_hr_timesheet_user"/>
|
||||
attrs="{'invisible': [('display_timer_start_primary', '=', False)]}" groups="hr_timesheet.group_hr_timesheet_user"/>
|
||||
<button class="btn-secondary" name="action_timer_start" type="object" string="Start"
|
||||
attrs="{'invisible': ['|', '|', ('total_hours_spent', '=', 0), ('timer_start', '!=', False), ('display_timesheet_timer', '=', False)]}" groups="hr_timesheet.group_hr_timesheet_user"/>
|
||||
attrs="{'invisible': [('display_timer_start_secondary', '=', False)]}" groups="hr_timesheet.group_hr_timesheet_user"/>
|
||||
<button class="btn-primary btn-danger o_fsm_stop" name="action_timer_stop" type="object" string="Stop"
|
||||
attrs="{'invisible': ['|', ('timer_start', '=', False), ('display_timesheet_timer', '=', False)]}" groups="hr_timesheet.group_hr_timesheet_user"/>
|
||||
attrs="{'invisible': [('display_timer_stop', '=', False)]}" groups="hr_timesheet.group_hr_timesheet_user"/>
|
||||
<button class="btn-primary" name="action_timer_pause" type="object" string="Pause"
|
||||
attrs="{'invisible': ['|', '|', ('timer_pause', '!=', False), ('timer_start', '=', False), ('display_timesheet_timer', '=', False)]}" groups="hr_timesheet.group_hr_timesheet_user"/>
|
||||
attrs="{'invisible': [('display_timer_pause', '=', False)]}" groups="hr_timesheet.group_hr_timesheet_user"/>
|
||||
<button class="btn-primary btn-info" name="action_timer_resume" type="object" string="Resume"
|
||||
attrs="{'invisible': ['|', '|', ('timer_pause', '=', False), ('timer_start', '=', False), ('display_timesheet_timer', '=', False)]}" groups="hr_timesheet.group_hr_timesheet_user"/>
|
||||
attrs="{'invisible': [('display_timer_resume', '=', False)]}" groups="hr_timesheet.group_hr_timesheet_user"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='stage_id']" position="attributes">
|
||||
<attribute name="class">ml-2</attribute>
|
||||
|
||||
@@ -21,6 +21,15 @@ class Project(models.Model):
|
||||
help="Employee/Sale Order Item Mapping:\n Defines to which sales order item an employee's timesheet entry will be linked."
|
||||
"By extension, it defines the rate at which an employee's time on the project is billed.")
|
||||
allow_billable = fields.Boolean("Bill from Tasks")
|
||||
display_create_order = fields.Boolean(compute='_compute_display_create_order')
|
||||
|
||||
@api.depends('billable_type', 'allow_billable', 'sale_order_id', 'partner_id')
|
||||
def _compute_display_create_order(self):
|
||||
for project in self:
|
||||
show = True
|
||||
if not project.partner_id or project.billable_type != 'no' or project.allow_billable or project.sale_order_id:
|
||||
show = False
|
||||
project.display_create_order = show
|
||||
|
||||
@api.depends('sale_order_id', 'sale_line_id', 'sale_line_employee_ids')
|
||||
def _compute_billable_type(self):
|
||||
@@ -125,6 +134,19 @@ class ProjectTask(models.Model):
|
||||
], string="Billable Type", compute='_compute_billable_type', compute_sudo=True, store=True)
|
||||
is_project_map_empty = fields.Boolean("Is Project map empty", compute='_compute_is_project_map_empty')
|
||||
allow_billable = fields.Boolean(related="project_id.allow_billable")
|
||||
display_create_order = fields.Boolean(compute='_compute_display_create_order')
|
||||
|
||||
@api.depends(
|
||||
'allow_billable', 'allow_timesheets', 'sale_order_id', 'display_timesheet_timer',
|
||||
'timer_start')
|
||||
def _compute_display_create_order(self):
|
||||
for task in self:
|
||||
show = True
|
||||
if not task.allow_billable or not task.allow_timesheets or \
|
||||
task.billable_type == 'employee_rate' or not task.partner_id or \
|
||||
task.sale_order_id or (task.display_timesheet_timer and task.timer_start):
|
||||
show = False
|
||||
task.display_create_order = show
|
||||
|
||||
@api.onchange('sale_line_id')
|
||||
def _onchange_sale_line_id(self):
|
||||
|
||||
@@ -7,11 +7,12 @@
|
||||
<field name="inherit_id" ref="project.edit_project"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//header" position="inside">
|
||||
<button name="action_make_billable" string="Create Sales Order" type="object" attrs="{'invisible': ['|', ('sale_order_id', '!=', False), ('billable_type', '!=', 'no')]}" groups="sales_team.group_sale_salesman"/>
|
||||
<button name="action_make_billable" string="Create Sales Order" type="object" attrs="{'invisible': [('display_create_order', '=', False)]}" groups="sales_team.group_sale_salesman"/>
|
||||
</xpath>
|
||||
<xpath expr="//page[@name='emails']" position="after">
|
||||
<page name="billing_employee_rate" string="Invoicing" attrs="{'invisible': [('billable_type', '=', 'no')]}">
|
||||
<group>
|
||||
<field name="display_create_order" invisible="1"/>
|
||||
<field name="billable_type" invisible="1"/>
|
||||
<field name="sale_order_id" attrs="{'invisible': [('billable_type', '=', 'no')]}"/>
|
||||
<field name="sale_line_id" attrs="{'invisible': [('billable_type', '=', 'no')]}" context="{'create': False, 'edit': False, 'delete': False}"/>
|
||||
@@ -74,7 +75,8 @@
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//header" position='inside'>
|
||||
<field name="allow_billable" invisible="1"/>
|
||||
<button name="action_make_billable" string="Create Sales Order" type="object" attrs="{'invisible': ['|', '|', '|', '|', '|', ('allow_billable', '=', False), ('allow_timesheets', '=', False), ('billable_type', '=', 'employee_rate'), ('partner_id', '=', False), ('sale_order_id', '!=', False), '&', ('display_timesheet_timer', '=', True), ('timer_start', '!=', False)]}" groups="sales_team.group_sale_salesman"/>
|
||||
<field name="display_create_order" invisible="1"/>
|
||||
<button name="action_make_billable" string="Create Sales Order" type="object" attrs="{'invisible': [('display_create_order', '=', False)]}" groups="sales_team.group_sale_salesman"/>
|
||||
</xpath>
|
||||
<xpath expr="//group[@name='sales_order_group']" position="inside">
|
||||
<field name="billable_type" invisible="1"/>
|
||||
|
||||
Reference in New Issue
Block a user