[IMP] sale_timesheet : set the partner_id on the wizard for sale order creation.

The partner_id on the wizard for sale order creation (from project and from tasks) is now set with the one
on the project or on the task if it is set.

Some fields were moved to community (from sale_timesheet_enterprise).

Concerned fields : allow_billable (project and task),
allow_timesheet_timer (project)

This also move timesheet_product_id to community.

This field was being added in industry_fsm_sale and was required
if allow_billable and allow_timesheets were true. But those 2
other fields are already available once sale_timesheet is
installed.

The field timesheet_product_id is thus being moved to
sale_timesheet for more coherence.

Task-2157571

closes odoo/odoo#44509

Related: odoo/enterprise#8118
Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
This commit is contained in:
jdoutreloux
2020-02-12 14:01:03 +00:00
parent 1bbe7c034c
commit fdcab45992
7 changed files with 74 additions and 17 deletions
+1
View File
@@ -15,6 +15,7 @@ have real delivered quantities in sales orders.
""",
'depends': ['sale_project', 'hr_timesheet'],
'data': [
'data/sale_service_data.xml',
'security/ir.model.access.csv',
'security/sale_timesheet_security.xml',
'views/account_invoice_views.xml',
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="time_product" model="product.product">
<field name="name">Service on Timesheet</field>
<field name="type">service</field>
<field name="list_price">40</field>
<field name="service_policy">delivered_timesheet</field>
<field name="image_1920" type="base64" file="sale_timesheet/static/img/product_product_time_product.png"/>
</record>
</data>
</odoo>
+40 -5
View File
@@ -5,9 +5,20 @@ from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
# YTI PLEASE SPLIT ME
class Project(models.Model):
_inherit = 'project.project'
@api.model
def default_get(self, fields):
""" Pre-fill timesheet product as "Time" data product when creating new project allowing billable tasks by default. """
result = super(Project, self).default_get(fields)
if 'timesheet_product_id' in fields and result.get('allow_billable') and result.get('allow_timesheets') and not result.get('timesheet_product_id'):
default_product = self.env.ref('sale_timesheet.time_product', False)
if default_product:
result['timesheet_product_id'] = default_product.id
return result
billable_type = fields.Selection([
('task_rate', 'At Task Rate'),
('employee_rate', 'At Employee Rate'),
@@ -22,6 +33,18 @@ class Project(models.Model):
"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')
timesheet_product_id = fields.Many2one(
'product.product', string='Timesheet Product',
domain="""[
('type', '=', 'service'),
('invoice_policy', '=', 'delivery'),
('service_type', '=', 'timesheet'),
'|', ('company_id', '=', False), ('company_id', '=', company_id)]""",
help='Select a Service product with which you would like to bill your time spent on tasks.')
_sql_constraints = [
('timesheet_product_required_if_billable_and_timesheets', "CHECK((allow_billable = 't' AND allow_timesheets = 't' AND timesheet_product_id IS NOT NULL) OR (allow_billable = 'f') OR (allow_timesheets = 'f'))", 'The timesheet product is required when the task can be billed and timesheets are allowed.'),
]
@api.depends('billable_type', 'allow_billable', 'sale_order_id', 'partner_id')
def _compute_display_create_order(self):
@@ -51,14 +74,24 @@ class Project(models.Model):
if self.billable_type == 'no':
self.sale_line_employee_ids = False
@api.onchange('allow_billable')
def _onchange_allow_billable(self):
@api.depends('allow_timesheets', 'allow_billable')
def _compute_timesheet_product_id(self):
default_product = self.env.ref('sale_timesheet.time_product', False)
for project in self:
if not project.allow_timesheets or not project.allow_billable:
project.timesheet_product_id = False
elif not project.timesheet_product_id:
project.timesheet_product_id = default_product
@api.depends('allow_billable')
def _compute_allow_billable(self):
""" In order to keep task billable type as 'task_rate' using sale_timesheet usual flow.
(see _compute_billable_type method in sale_timesheet)
"""
if self.allow_billable:
self.sale_order_id = False
self.sale_line_employee_ids = False
self.filtered(lambda p: p.allow_billable).update({
'sale_order_id': False,
'sale_line_employee_ids': False,
})
@api.constrains('sale_line_id', 'billable_type')
def _check_sale_line_type(self):
@@ -118,6 +151,7 @@ class Project(models.Model):
"context": {
'active_id': self.id,
'active_model': 'project.project',
'default_product_id': self.timesheet_product_id.id,
},
}
@@ -233,6 +267,7 @@ class ProjectTask(models.Model):
'active_id': self.id,
'active_model': 'project.task',
'form_view_initial_mode': 'edit',
'default_product_id': self.project_id.timesheet_product_id.id,
},
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

@@ -4,7 +4,7 @@
<record id="project_project_view_form" model="ir.ui.view">
<field name="name">project.project.form.inherit</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.edit_project"/>
<field name="inherit_id" ref="hr_timesheet.project_invoice_form"/>
<field name="arch" type="xml">
<xpath expr="//header" position="inside">
<button name="action_make_billable" string="Create Sales Order" type="object" attrs="{'invisible': [('display_create_order', '=', False)]}" groups="sales_team.group_sale_salesman"/>
@@ -26,25 +26,18 @@
</field>
</page>
</xpath>
</field>
</record>
<record id="project_view_form_inherit" model="ir.ui.view">
<field name="name">project.view.form.inherit</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="hr_timesheet.project_invoice_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@id='timesheet_settings']/.." position="after">
<div class="row mt16 o_settings_container">
<div class="col-lg-6 o_setting_box" id="allow_billable_container" attrs="{'invisible': [('billable_type', '=', 'employee_rate')]}">
<div class="o_setting_left_pane">
<field name="allow_billable"/>
<field name="allow_billable" attrs="{'readonly': [('sale_order_id', '!=', False)]}"/>
</div>
<div class="o_setting_right_pane">
<label for="allow_billable"/>
<div class="text-muted" id="allow_billable_setting">
Invoice your time and material from tasks
</div>
<field name="timesheet_product_id" attrs="{'invisible': ['|', ('allow_billable', '=', False), ('allow_timesheets', '=', False)], 'required': ['&amp;', ('allow_billable', '=', True), ('allow_timesheets', '=', True)]}"/>
</div>
</div>
</div>
@@ -52,6 +45,20 @@
</field>
</record>
<record id="project_project_view_form_simplified_inherit" model="ir.ui.view">
<field name="name">project.project.view.form.simplified.inherit</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="hr_timesheet.project_project_view_form_simplified_inherit"/>
<field name="arch" type="xml">
<field name="allow_timesheet_timer" position="after">
<field name="billable_type" invisible="1"/>
<field name="company_id" invisible="1"/>
<field name="allow_billable" attrs="{'invisible': [('billable_type', '=', 'employee_rate')]}"/>
<field name="timesheet_product_id" attrs="{'invisible': ['|', ('allow_billable', '=', False), ('allow_timesheets', '=', False)], 'required': ['&amp;', ('allow_billable', '=', True), ('allow_timesheets', '=', True)]}"/>
</field>
</field>
</record>
<record id="project_project_view_kanban_inherit_sale_timesheet" model="ir.ui.view">
<field name="name">project.project.kanban.inherit.sale.timesheet</field>
<field name="model">project.project</field>
@@ -23,7 +23,8 @@ class ProjectCreateSalesOrder(models.TransientModel):
if project.billable_type != 'no':
raise UserError(_("The project is already billable."))
result['project_id'] = active_id
result['partner_id'] = project.partner_id.id
if not result.get('partner_id', False):
result['partner_id'] = project.partner_id.id
return result
project_id = fields.Many2one('project.project', "Project", domain=[('sale_line_id', '=', False)], help="Project for which we are creating a sales order", required=True)
@@ -23,7 +23,8 @@ class ProjectTaskCreateSalesOrder(models.TransientModel):
if task.billable_type != 'no':
raise UserError(_("The task is already billable."))
result['task_id'] = active_id
result['partner_id'] = task.partner_id.id
if not result.get('partner_id', False):
result['partner_id'] = task.partner_id.id
return result
task_id = fields.Many2one('project.task', "Task", domain=[('sale_line_id', '=', False)], help="Task for which we are creating a sales order", required=True)