summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
Diffstat (limited to 'addons')
-rw-r--r--addons/sale_timesheet/__manifest__.py1
-rw-r--r--addons/sale_timesheet/data/sale_service_data.xml12
-rw-r--r--addons/sale_timesheet/models/project.py45
-rw-r--r--addons/sale_timesheet/static/img/product_product_time_product.pngbin0 -> 5370 bytes
-rw-r--r--addons/sale_timesheet/views/project_task_views.xml27
-rw-r--r--addons/sale_timesheet/wizard/project_create_sale_order.py3
-rw-r--r--addons/sale_timesheet/wizard/project_task_create_sale_order.py3
7 files changed, 74 insertions, 17 deletions
diff --git a/addons/sale_timesheet/__manifest__.py b/addons/sale_timesheet/__manifest__.py
index 5afefc9b7ec..63c503ec8c7 100644
--- a/addons/sale_timesheet/__manifest__.py
+++ b/addons/sale_timesheet/__manifest__.py
@@ -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',
diff --git a/addons/sale_timesheet/data/sale_service_data.xml b/addons/sale_timesheet/data/sale_service_data.xml
new file mode 100644
index 00000000000..b0042b6acdc
--- /dev/null
+++ b/addons/sale_timesheet/data/sale_service_data.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>
diff --git a/addons/sale_timesheet/models/project.py b/addons/sale_timesheet/models/project.py
index a4a050d9649..48c1bf95259 100644
--- a/addons/sale_timesheet/models/project.py
+++ b/addons/sale_timesheet/models/project.py
@@ -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,
},
}
diff --git a/addons/sale_timesheet/static/img/product_product_time_product.png b/addons/sale_timesheet/static/img/product_product_time_product.png
new file mode 100644
index 00000000000..c9d7a77d4f5
--- /dev/null
+++ b/addons/sale_timesheet/static/img/product_product_time_product.png
Binary files differ
diff --git a/addons/sale_timesheet/views/project_task_views.xml b/addons/sale_timesheet/views/project_task_views.xml
index b5c7aa3caba..064b16676b1 100644
--- a/addons/sale_timesheet/views/project_task_views.xml
+++ b/addons/sale_timesheet/views/project_task_views.xml
@@ -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>
diff --git a/addons/sale_timesheet/wizard/project_create_sale_order.py b/addons/sale_timesheet/wizard/project_create_sale_order.py
index 7b6029e8296..aad2648a0d0 100644
--- a/addons/sale_timesheet/wizard/project_create_sale_order.py
+++ b/addons/sale_timesheet/wizard/project_create_sale_order.py
@@ -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)
diff --git a/addons/sale_timesheet/wizard/project_task_create_sale_order.py b/addons/sale_timesheet/wizard/project_task_create_sale_order.py
index e697f95592c..ffabb0ac9c7 100644
--- a/addons/sale_timesheet/wizard/project_task_create_sale_order.py
+++ b/addons/sale_timesheet/wizard/project_task_create_sale_order.py
@@ -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)