From fdcab45992e7215b20af879f1a01135905ab2eaa Mon Sep 17 00:00:00 2001 From: jdoutreloux Date: Tue, 24 Dec 2019 09:03:08 +0000 Subject: [PATCH] [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) --- addons/sale_timesheet/__manifest__.py | 1 + .../sale_timesheet/data/sale_service_data.xml | 12 +++++ addons/sale_timesheet/models/project.py | 45 ++++++++++++++++-- .../img/product_product_time_product.png | Bin 0 -> 5370 bytes .../views/project_task_views.xml | 27 +++++++---- .../wizard/project_create_sale_order.py | 3 +- .../wizard/project_task_create_sale_order.py | 3 +- 7 files changed, 74 insertions(+), 17 deletions(-) create mode 100644 addons/sale_timesheet/data/sale_service_data.xml create mode 100644 addons/sale_timesheet/static/img/product_product_time_product.png 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 @@ + + + + + Service on Timesheet + service + 40 + delivered_timesheet + + + + 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 0000000000000000000000000000000000000000..c9d7a77d4f5c53c60c4ff065786787262828ab46 GIT binary patch literal 5370 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 literal 0 HcmV?d00001 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 @@ project.project.form.inherit project.project - +